@@ -28,117 +28,51 @@ import XCTest
28
28
final class PeerMacroTests : XCTestCase {
29
29
private let indentationWidth : Trivia = . spaces( 2 )
30
30
31
- fileprivate struct AddCompletionHandler : PeerMacro {
32
- static func expansion(
33
- of node: AttributeSyntax ,
34
- providingPeersOf declaration: some DeclSyntaxProtocol ,
35
- in context: some MacroExpansionContext
36
- ) throws -> [ DeclSyntax ] {
37
- // Only on functions at the moment. We could handle initializers as well
38
- // with a bit of work.
39
- guard let funcDecl = declaration. as ( FunctionDeclSyntax . self) else {
40
- throw MacroExpansionErrorMessage ( " @addCompletionHandler only works on functions " )
41
- }
42
-
43
- // This only makes sense for async functions.
44
- if funcDecl. signature. effectSpecifiers? . asyncSpecifier == nil {
45
- let newEffects : FunctionEffectSpecifiersSyntax
46
- if let existingEffects = funcDecl. signature. effectSpecifiers {
47
- newEffects = existingEffects. with ( \. asyncSpecifier, . keyword( . async) )
48
- } else {
49
- newEffects = FunctionEffectSpecifiersSyntax ( asyncSpecifier: . keyword( . async) )
31
+ func testAddCompletionHandler( ) {
32
+ struct TestMacro : PeerMacro {
33
+ static func expansion(
34
+ of node: AttributeSyntax ,
35
+ providingPeersOf declaration: some DeclSyntaxProtocol ,
36
+ in context: some MacroExpansionContext
37
+ ) throws -> [ DeclSyntax ] {
38
+ // Only on functions at the moment. We could handle initializers as well
39
+ // with a bit of work.
40
+ guard let funcDecl = declaration. as ( FunctionDeclSyntax . self) else {
41
+ throw MacroExpansionErrorMessage ( " @addCompletionHandler only works on functions " )
50
42
}
51
43
52
- let newSignature = funcDecl. signature. with ( \. effectSpecifiers, newEffects)
53
-
54
- let diag = Diagnostic (
55
- node: Syntax ( funcDecl. funcKeyword) ,
56
- message: MacroExpansionErrorMessage (
57
- " can only add a completion-handler variant to an 'async' function "
58
- ) ,
59
- fixIts: [
60
- FixIt (
61
- message: MacroExpansionFixItMessage (
62
- " add 'async' "
63
- ) ,
64
- changes: [
65
- FixIt . Change. replace (
66
- oldNode: Syntax ( funcDecl. signature) ,
67
- newNode: Syntax ( newSignature)
68
- )
69
- ]
70
- )
71
- ]
72
- )
73
-
74
- context. diagnose ( diag)
75
- return [ ]
76
- }
77
-
78
- // Form the completion handler parameter.
79
- let resultType : TypeSyntax ? = funcDecl. signature. returnClause? . type. trimmed
80
-
81
- let completionHandlerParam =
82
- FunctionParameterSyntax (
83
- firstName: . identifier( " completionHandler " ) ,
84
- colon: . colonToken( trailingTrivia: . space) ,
85
- type: TypeSyntax ( " ( \( resultType ?? " " ) ) -> Void " )
86
- )
87
-
88
- // Add the completion handler parameter to the parameter list.
89
- let parameterList = funcDecl. signature. parameterClause. parameters
90
- var newParameterList = parameterList
91
- if !parameterList. isEmpty {
92
- // We need to add a trailing comma to the preceding list.
93
- newParameterList [ newParameterList. index ( before: newParameterList. endIndex) ] . trailingComma = . commaToken( trailingTrivia: . space)
94
- }
95
- newParameterList. append ( completionHandlerParam)
96
-
97
- let callArguments : [ String ] = parameterList. map { param in
98
- let argName = param. secondName ?? param. firstName
99
-
100
- if param. firstName. text != " _ " {
101
- return " \( param. firstName. text) : \( argName. text) "
44
+ // This only makes sense for async functions.
45
+ if funcDecl. signature. effectSpecifiers? . asyncSpecifier == nil {
46
+ let newEffects = FunctionEffectSpecifiersSyntax ( asyncSpecifier: . keyword( . async) )
47
+ let newSignature = funcDecl. signature. with ( \. effectSpecifiers, newEffects)
48
+
49
+ let diag = Diagnostic (
50
+ node: Syntax ( funcDecl. funcKeyword) ,
51
+ message: MacroExpansionErrorMessage (
52
+ " can only add a completion-handler variant to an 'async' function "
53
+ ) ,
54
+ fixIts: [
55
+ FixIt (
56
+ message: MacroExpansionFixItMessage (
57
+ " add 'async' "
58
+ ) ,
59
+ changes: [
60
+ FixIt . Change. replace (
61
+ oldNode: Syntax ( funcDecl. signature) ,
62
+ newNode: Syntax ( newSignature)
63
+ )
64
+ ]
65
+ )
66
+ ]
67
+ )
68
+
69
+ context. diagnose ( diag)
70
+ return [ ]
102
71
}
103
72
104
- return " \( argName. text) "
105
- }
106
-
107
- let call : ExprSyntax =
108
- " \( funcDecl. name) ( \( raw: callArguments. joined ( separator: " , " ) ) ) "
109
-
110
- // FIXME: We should make CodeBlockSyntax ExpressibleByStringInterpolation,
111
- // so that the full body could go here.
112
- let newBody : ExprSyntax =
113
- """
114
-
115
- Task {
116
- completionHandler(await \( call) )
117
- }
118
-
119
- """
120
-
121
- // Drop the @addCompletionHandler attribute from the new declaration.
122
- let newAttributeList = funcDecl. attributes. filter {
123
- guard case let . attribute( attribute) = $0 else {
124
- return true
125
- }
126
- return attribute. attributeName. as ( IdentifierTypeSyntax . self) ? . name == " addCompletionHandler "
73
+ return [ ]
127
74
}
128
-
129
- var newFunc = funcDecl
130
- newFunc. signature. effectSpecifiers? . asyncSpecifier = nil // drop async
131
- newFunc. signature. returnClause = nil // drop result type
132
- newFunc. signature. parameterClause. parameters = newParameterList
133
- newFunc. signature. parameterClause. trailingTrivia = [ ]
134
- newFunc. body = CodeBlockSyntax { newBody }
135
- newFunc. attributes = newAttributeList
136
-
137
- return [ DeclSyntax ( newFunc) ]
138
75
}
139
- }
140
-
141
- func testAddCompletionHandler( ) {
142
76
assertMacroExpansion (
143
77
"""
144
78
@addCompletionHandler
@@ -153,7 +87,7 @@ final class PeerMacroTests: XCTestCase {
153
87
}
154
88
}
155
89
""" ,
156
- macros: [ " addCompletionHandler " : AddCompletionHandler . self] ,
90
+ macros: [ " addCompletionHandler " : TestMacro . self] ,
157
91
indentationWidth: indentationWidth
158
92
)
159
93
}
@@ -221,30 +155,4 @@ final class PeerMacroTests: XCTestCase {
221
155
]
222
156
)
223
157
}
224
-
225
- func testAddCompletionHandlerWhereThereIsNotAsync( ) {
226
- assertMacroExpansion (
227
- """
228
- @addCompletionHandler
229
- func f(a: Int, for b: String, _ value: Double) -> String { }
230
- """ ,
231
- expandedSource: """
232
- func f(a: Int, for b: String, _ value: Double) -> String { }
233
- """ ,
234
- diagnostics: [
235
- DiagnosticSpec (
236
- message: " can only add a completion-handler variant to an 'async' function " ,
237
- line: 2 ,
238
- column: 1 ,
239
- fixIts: [ FixItSpec ( message: " add 'async' " ) ]
240
- )
241
- ] ,
242
- macros: [ " addCompletionHandler " : AddCompletionHandler . self] ,
243
- fixedSource: """
244
- @addCompletionHandler
245
- func f(a: Int, for b: String, _ value: Double) async-> String { }
246
- """ ,
247
- indentationWidth: indentationWidth
248
- )
249
- }
250
158
}
0 commit comments