I want to write a macro GetSetMacro
which is taking in the value of the stored property of the type and generate the accessors for another property based on it.
// Definition
@attached(accessor)
public macro GetSetMacro<Value>(_ : Value) = #externalMacro(module: "MyMacroModule", type: "GetSetMacro")
// Implementation
public struct GetSetMacro: AccessorMacro {
public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingAccessorsOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.AccessorDeclSyntax] {
guard
case let .argumentList(arguments) = node.arguments,
let argument = arguments.first
else { return [] }
return [
"""
get {
// How to access the member value of the type in here?
???
}
""",
"""
set {
??? = newValue
}
"""
]
}
}
Example usage
var value = 1
@GetSetMacro(\.value)
var newIntValue: Int
// expansion
var newIntValue {
get {
value
} set {
value = newValue
}
}
In the macro declaration, take a WritableKeyPath
:
@attached(accessor, names: named(get), named(set))
public macro GetSet<Root, Value>(_ keyPath: WritableKeyPath<Root, Value>) = #externalMacro(...)
The implementation just uses the [keyPath: ...]
subscript to get and set the desired key path.
enum GetSetMacro: AccessorMacro {
static func expansion(of node: AttributeSyntax, providingAccessorsOf declaration: some DeclSyntaxProtocol, in context: some MacroExpansionContext) throws -> [AccessorDeclSyntax] {
guard let keyPath = node.arguments?.as(LabeledExprListSyntax.self)?.first?.expression else {
return []
}
return [
"""
get { self[keyPath: \(keyPath)] }
""",
"""
set { self[keyPath: \(keyPath)] = newValue }
"""
]
}
}
Example usage:
class Foo {
var value = 1
@GetSet(\Foo.value)
var newIntValue: Int
}
Notes:
\Foo.value
. The compiler cannot infer the root type.