Skip to content

Commit 5873c3e

Browse files
authored
fix: fixed optional types not detected with valueCoder strategy (#141)
1 parent e2b09b4 commit 5873c3e

File tree

3 files changed

+104
-26
lines changed

3 files changed

+104
-26
lines changed

Sources/PluginCore/Attributes/Codable/Strategies/StrategyFinder.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,18 +80,19 @@ extension Registration where Var: DefaultPropertyVariable {
8080
from decl: some AttributableDeclSyntax
8181
) -> Registration<Decl, Key, StrategyVariable<Var.Initialization>> {
8282
let finder = StrategyFinder(decl: decl)
83-
let inStrategy =
84-
finder.valueCodingStrategies.first { strategy in
85-
strategy.trimmedDescription
86-
== self.variable.type.trimmedDescription
87-
} != nil
83+
let type = finder.valueCodingStrategies.first { strategy in
84+
return strategy.trimmedDescription
85+
== self.variable.type.trimmedDescription
86+
|| strategy.trimmedDescription
87+
== self.variable.type.wrappedType.trimmedDescription
88+
}
8889

8990
let newVariable: AnyPropertyVariable<Var.Initialization>
90-
if inStrategy {
91+
if let type = type {
9192
newVariable =
9293
HelperCodedVariable(
9394
base: self.variable,
94-
options: .helper("ValueCoder<\(variable.type)>()")
95+
options: .helper("ValueCoder<\(type)>()")
9596
).any
9697
} else {
9798
newVariable = self.variable.any

Sources/PluginCore/Variables/Property/PropertyVariable.swift

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -195,35 +195,40 @@ extension CodeBlockItemListSyntax: ConditionalVariableSyntax {
195195
}
196196

197197
extension TypeSyntax {
198-
/// Check whether current type syntax represents an optional type.
198+
/// Extract actual type of an optional type.
199199
///
200-
/// Checks whether the type syntax uses
200+
/// Extracts type based on whether the type syntax uses
201201
/// `?` optional type syntax (i.e. `Type?`) or
202202
/// `!` implicitly unwrapped optional type syntax (i.e. `Type!`) or
203203
/// generic optional syntax (i.e. `Optional<Type>`).
204-
var isOptionalTypeSyntax: Bool {
205-
if self.is(OptionalTypeSyntax.self) {
206-
return true
207-
} else if self.is(ImplicitlyUnwrappedOptionalTypeSyntax.self) {
208-
return true
209-
} else if let type = self.as(IdentifierTypeSyntax.self),
210-
type.name.trimmed.text == "Optional",
211-
let gArgs = type.genericArgumentClause?.arguments,
212-
gArgs.count == 1
204+
/// Otherwise, returns the type syntax as is.
205+
var wrappedType: TypeSyntax {
206+
if let type = self.as(OptionalTypeSyntax.self) {
207+
return type.wrappedType
208+
} else if let type = self.as(ImplicitlyUnwrappedOptionalTypeSyntax.self)
213209
{
214-
return true
215-
} else if let type = self.as(MemberTypeSyntax.self),
216-
let baseType = type.baseType.as(IdentifierTypeSyntax.self),
217-
baseType.trimmed.name.text == "Swift",
218-
type.trimmed.name.text == "Optional",
210+
return type.wrappedType
211+
} else if let type = self.as(IdentifierTypeSyntax.self),
212+
type.name.text == "Optional",
219213
let gArgs = type.genericArgumentClause?.arguments,
220-
gArgs.count == 1
214+
gArgs.count == 1,
215+
let wrappedType = gArgs.first?.argument.as(TypeSyntax.self)
221216
{
222-
return true
217+
return wrappedType
223218
} else {
224-
return false
219+
return self
225220
}
226221
}
222+
223+
/// Check whether current type syntax represents an optional type.
224+
///
225+
/// Checks whether the type syntax uses
226+
/// `?` optional type syntax (i.e. `Type?`) or
227+
/// `!` implicitly unwrapped optional type syntax (i.e. `Type!`) or
228+
/// generic optional syntax (i.e. `Optional<Type>`).
229+
var isOptionalTypeSyntax: Bool {
230+
wrappedType != self
231+
}
227232
}
228233

229234
#if swift(<6.0)

Tests/MetaCodableTests/Codable/CommonStrategiesValueCoderTests.swift

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,18 @@ struct CommonStrategiesValueCoderTests {
1111
let int: Int
1212
let double: Double
1313
let string: String
14+
let optBool: Bool?
15+
let optInt: Int?
16+
let optDouble: Double?
17+
let optString: String?
18+
let impBool: Bool!
19+
let impInt: Int!
20+
let impDouble: Double!
21+
let impString: String!
22+
let optGenBool: Optional<Bool>
23+
let optGenInt: Optional<Int>
24+
let optGenDouble: Optional<Double>
25+
let optGenString: Optional<String>
1426
}
1527

1628
@Test
@@ -54,6 +66,18 @@ struct CommonStrategiesValueCoderTests {
5466
let int: Int
5567
let double: Double
5668
let string: String
69+
let optBool: Bool?
70+
let optInt: Int?
71+
let optDouble: Double?
72+
let optString: String?
73+
let impBool: Bool!
74+
let impInt: Int!
75+
let impDouble: Double!
76+
let impString: String!
77+
let optGenBool: Optional<Bool>
78+
let optGenInt: Optional<Int>
79+
let optGenDouble: Optional<Double>
80+
let optGenString: Optional<String>
5781
}
5882
""",
5983
expandedSource:
@@ -63,6 +87,18 @@ struct CommonStrategiesValueCoderTests {
6387
let int: Int
6488
let double: Double
6589
let string: String
90+
let optBool: Bool?
91+
let optInt: Int?
92+
let optDouble: Double?
93+
let optString: String?
94+
let impBool: Bool!
95+
let impInt: Int!
96+
let impDouble: Double!
97+
let impString: String!
98+
let optGenBool: Optional<Bool>
99+
let optGenInt: Optional<Int>
100+
let optGenDouble: Optional<Double>
101+
let optGenString: Optional<String>
66102
}
67103
68104
extension Model: Decodable {
@@ -72,6 +108,18 @@ struct CommonStrategiesValueCoderTests {
72108
self.int = try ValueCoder<Int>().decode(from: container, forKey: CodingKeys.int)
73109
self.double = try ValueCoder<Double>().decode(from: container, forKey: CodingKeys.double)
74110
self.string = try ValueCoder<String>().decode(from: container, forKey: CodingKeys.string)
111+
self.optBool = try ValueCoder<Bool>().decodeIfPresent(from: container, forKey: CodingKeys.optBool)
112+
self.optInt = try ValueCoder<Int>().decodeIfPresent(from: container, forKey: CodingKeys.optInt)
113+
self.optDouble = try ValueCoder<Double>().decodeIfPresent(from: container, forKey: CodingKeys.optDouble)
114+
self.optString = try ValueCoder<String>().decodeIfPresent(from: container, forKey: CodingKeys.optString)
115+
self.impBool = try ValueCoder<Bool>().decodeIfPresent(from: container, forKey: CodingKeys.impBool)
116+
self.impInt = try ValueCoder<Int>().decodeIfPresent(from: container, forKey: CodingKeys.impInt)
117+
self.impDouble = try ValueCoder<Double>().decodeIfPresent(from: container, forKey: CodingKeys.impDouble)
118+
self.impString = try ValueCoder<String>().decodeIfPresent(from: container, forKey: CodingKeys.impString)
119+
self.optGenBool = try ValueCoder<Bool>().decodeIfPresent(from: container, forKey: CodingKeys.optGenBool)
120+
self.optGenInt = try ValueCoder<Int>().decodeIfPresent(from: container, forKey: CodingKeys.optGenInt)
121+
self.optGenDouble = try ValueCoder<Double>().decodeIfPresent(from: container, forKey: CodingKeys.optGenDouble)
122+
self.optGenString = try ValueCoder<String>().decodeIfPresent(from: container, forKey: CodingKeys.optGenString)
75123
}
76124
}
77125
@@ -82,6 +130,18 @@ struct CommonStrategiesValueCoderTests {
82130
try ValueCoder<Int>().encode(self.int, to: &container, atKey: CodingKeys.int)
83131
try ValueCoder<Double>().encode(self.double, to: &container, atKey: CodingKeys.double)
84132
try ValueCoder<String>().encode(self.string, to: &container, atKey: CodingKeys.string)
133+
try ValueCoder<Bool>().encodeIfPresent(self.optBool, to: &container, atKey: CodingKeys.optBool)
134+
try ValueCoder<Int>().encodeIfPresent(self.optInt, to: &container, atKey: CodingKeys.optInt)
135+
try ValueCoder<Double>().encodeIfPresent(self.optDouble, to: &container, atKey: CodingKeys.optDouble)
136+
try ValueCoder<String>().encodeIfPresent(self.optString, to: &container, atKey: CodingKeys.optString)
137+
try ValueCoder<Bool>().encodeIfPresent(self.impBool, to: &container, atKey: CodingKeys.impBool)
138+
try ValueCoder<Int>().encodeIfPresent(self.impInt, to: &container, atKey: CodingKeys.impInt)
139+
try ValueCoder<Double>().encodeIfPresent(self.impDouble, to: &container, atKey: CodingKeys.impDouble)
140+
try ValueCoder<String>().encodeIfPresent(self.impString, to: &container, atKey: CodingKeys.impString)
141+
try ValueCoder<Bool>().encodeIfPresent(self.optGenBool, to: &container, atKey: CodingKeys.optGenBool)
142+
try ValueCoder<Int>().encodeIfPresent(self.optGenInt, to: &container, atKey: CodingKeys.optGenInt)
143+
try ValueCoder<Double>().encodeIfPresent(self.optGenDouble, to: &container, atKey: CodingKeys.optGenDouble)
144+
try ValueCoder<String>().encodeIfPresent(self.optGenString, to: &container, atKey: CodingKeys.optGenString)
85145
}
86146
}
87147
@@ -91,6 +151,18 @@ struct CommonStrategiesValueCoderTests {
91151
case int = "int"
92152
case double = "double"
93153
case string = "string"
154+
case optBool = "optBool"
155+
case optInt = "optInt"
156+
case optDouble = "optDouble"
157+
case optString = "optString"
158+
case impBool = "impBool"
159+
case impInt = "impInt"
160+
case impDouble = "impDouble"
161+
case impString = "impString"
162+
case optGenBool = "optGenBool"
163+
case optGenInt = "optGenInt"
164+
case optGenDouble = "optGenDouble"
165+
case optGenString = "optGenString"
94166
}
95167
}
96168
"""

0 commit comments

Comments
 (0)