Skip to content

Commit 26475ab

Browse files
committed
Merge branch 'feature/generated-accessors-1' into develop
2 parents 7015ca1 + 7dca3bd commit 26475ab

18 files changed

+843
-202
lines changed

Sources/ManagedModelMacros/CompilerPlugin.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import SwiftSyntaxMacros
99
@main
1010
struct ModelsPlugin: CompilerPlugin {
1111
let providingMacros: [ Macro.Type ] = [
12-
TransientMacro.self,
13-
AttributeMacro.self,
14-
RelationshipMacro.self,
15-
ModelMacro.self
12+
TransientMacro .self,
13+
AttributeMacro .self,
14+
RelationshipMacro .self,
15+
PersistedPropertyMacro.self,
16+
ModelMacro .self
1617
]
1718
}

Sources/ManagedModelMacros/ModelMacro/MetadataSlot.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ extension ModelMacro {
7878
func metadata(for property: ModelProperty) -> ExprSyntax {
7979
let metaExpr : ExprSyntax? = switch property.type {
8080
case .plain: generateInfo(for: property)
81-
case .attribute (let attribute):
81+
case .attribute (let attribute, isTransformable: _):
8282
attributeInfo (for: property, attribute: attribute)
8383
case .relationship(let attribute):
8484
relationshipInfo(for: property, attribute: attribute)

Sources/ManagedModelMacros/ModelMacro/ModelMemberAttributes.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import SwiftSyntaxBuilder
99
import SwiftSyntaxMacros
1010

1111
/**
12-
* Attaches attributes (`@NSManaged` etc) to members.
12+
* Attaches attributes, `@_PersistedProperty`, to members.
1313
*
1414
* This is attached to tracked properties:
15-
* - `@NSManaged`
15+
* - `@_PersistedProperty`
1616
*/
1717
extension ModelMacro: MemberAttributeMacro { // @attached(memberAttribute)
1818

@@ -30,7 +30,8 @@ extension ModelMacro: MemberAttributeMacro { // @attached(memberAttribute)
3030
}
3131

3232
var properties = [ ModelProperty ]()
33-
addModelProperties(in: member, to: &properties, context: context)
33+
addModelProperties(in: member, to: &properties,
34+
context: context)
3435

3536
guard let property = properties.first else { return [] } // other member
3637

@@ -41,6 +42,6 @@ extension ModelMacro: MemberAttributeMacro { // @attached(memberAttribute)
4142

4243
guard !property.isTransient else { return [] }
4344

44-
return [ "@NSManaged" ]
45+
return [ "@_PersistedProperty" ]
4546
}
4647
}

Sources/ManagedModelMacros/Models/ModelProperty.swift

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct ModelProperty {
3131
case relationship(AttributeSyntax)
3232

3333
/// The property was explicitly tagged as an `Attribute`.
34-
case attribute (AttributeSyntax)
34+
case attribute (AttributeSyntax, isTransformable: Bool)
3535
}
3636

3737
let binding : PatternBindingSyntax
@@ -46,6 +46,17 @@ struct ModelProperty {
4646
let initExpression : ExprSyntax?
4747
}
4848

49+
extension ModelProperty {
50+
51+
var isTransformable : Bool {
52+
switch type {
53+
case .plain : return false
54+
case .relationship(_) : return false
55+
case .attribute(_, isTransformable: let value): return value
56+
}
57+
}
58+
}
59+
4960
extension ModelProperty {
5061

5162
/**
@@ -67,14 +78,14 @@ extension ModelProperty {
6778

6879
var isKnownAttributePropertyType: Bool {
6980
switch type {
70-
case .attribute(_) : return true
81+
case .attribute(_, _) : return true
7182
case .relationship(_) : return false
7283
case .plain: return valueType?.isKnownAttributePropertyType ?? false
7384
}
7485
}
7586
var isKnownRelationshipPropertyType: Bool {
7687
switch type {
77-
case .attribute(_) : return false
88+
case .attribute(_, _) : return false
7889
case .relationship(_) : return true
7990
case .plain: return valueType?.isKnownRelationshipPropertyType ?? false
8091
}
@@ -100,8 +111,9 @@ extension ModelProperty.PropertyType: CustomStringConvertible {
100111
var description: String {
101112
switch self {
102113
case .plain : return "plain"
103-
case .attribute (_) : return "Attribute"
104114
case .relationship(_) : return "Relationship"
115+
case .attribute(_, isTransformable: let isTransformable) :
116+
return isTransformable ? "TransformableAttribute" : "Attribute"
105117
}
106118
}
107119
}
@@ -222,8 +234,11 @@ extension ModelMacro {
222234
case "Attribute":
223235
switch propertyType {
224236
case .plain:
225-
propertyType = .attribute(attribute)
226-
case .attribute(_):
237+
propertyType = .attribute(
238+
attribute,
239+
isTransformable: isTransformableAttribute(attribute)
240+
)
241+
case .attribute(_, _):
227242
context.diagnose(.multipleAttributeMacrosAppliedOnProperty,
228243
on: attributes)
229244
case .relationship(_):
@@ -242,7 +257,7 @@ extension ModelMacro {
242257
.multipleRelationshipMacrosAppliedOnProperty,
243258
on: attributes
244259
)
245-
case .attribute(_):
260+
case .attribute(_, _):
246261
context.diagnose(
247262
.attributeAndRelationshipMacrosAppliedOnProperty,
248263
on: attributes
@@ -258,4 +273,39 @@ extension ModelMacro {
258273

259274
return ( propertyType, isTransient )
260275
}
276+
277+
// Check whether the attribute specified a `.transformable` option.
278+
// Check for: `@Attribute(.transformable(by: xx))`,
279+
// Signature: (_ options: Option..., originalName...)
280+
private static func isTransformableAttribute(_ syntax: AttributeSyntax)
281+
-> Bool
282+
{
283+
guard let arguments = syntax.arguments,
284+
case .argumentList(let labeledExpressions) = arguments else
285+
{
286+
return false
287+
}
288+
289+
for labeledExpression in labeledExpressions {
290+
guard labeledExpression.label == nil else { break }
291+
292+
guard let funCall = labeledExpression.expression
293+
.as(FunctionCallExprSyntax.self),
294+
let member = funCall.calledExpression
295+
.as(MemberAccessExprSyntax.self)
296+
else {
297+
continue
298+
}
299+
guard case .identifier(let name) =
300+
member.declName.baseName.tokenKind else
301+
{
302+
continue
303+
}
304+
305+
// Could be more advanced :-)
306+
if name == "transformable" { return true }
307+
}
308+
309+
return false
310+
}
261311
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import SwiftCompilerPlugin
2+
import SwiftSyntax
3+
import SwiftSyntaxBuilder
4+
import SwiftSyntaxMacros
5+
6+
// @attached(accessor) macro
7+
public struct PersistedPropertyMacro: AccessorMacro {
8+
9+
public static func expansion(
10+
of macroNode : AttributeSyntax,
11+
providingAccessorsOf declaration : some DeclSyntaxProtocol,
12+
in context : some MacroExpansionContext
13+
) throws -> [ AccessorDeclSyntax ]
14+
{
15+
assert(declaration.parent == nil, "We do have access to the parent?!")
16+
17+
var properties = [ ModelProperty ]()
18+
ModelMacro
19+
.addModelProperties(in: declaration, to: &properties, context: context)
20+
guard let property = properties.first else { return [] }
21+
if properties.count > 1 {
22+
context.diagnose(.multipleMembersInAttributesMacroCall, on: macroNode)
23+
return []
24+
}
25+
26+
return property.isTransformable
27+
? [ "set { setTransformableValue(forKey: \(literal: property.name), to: newValue) }",
28+
"get { getTransformableValue(forKey: \(literal: property.name)) }" ]
29+
: [ "set { setValue(forKey: \(literal: property.name), to: newValue) }",
30+
"get { getValue(forKey: \(literal: property.name)) }" ]
31+
}
32+
}

Sources/ManagedModels/ModelMacroDefinition.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ public macro Relationship(
5555
public macro Transient() =
5656
#externalMacro(module: "ManagedModelMacros", type: "TransientMacro")
5757

58+
/**
59+
* An internal helper macro. Don't use this.
60+
*/
61+
@available(swift 5.9)
62+
@attached(accessor, names: named(init))
63+
public macro _PersistedProperty() =
64+
#externalMacro(module: "ManagedModelMacros", type: "PersistedPropertyMacro")
65+
5866

5967
// MARK: - Model Macro
6068

0 commit comments

Comments
 (0)