Skip to content

Commit 452e07d

Browse files
authored
Merge pull request #2154 from ahoppen/ahoppen/peer-on-var-with-multiple-bindings
Disallow attaching peer macro to variable with multiple bindings in `assertMacroExpansion`
2 parents 83c4b48 + 3ffa580 commit 452e07d

File tree

3 files changed

+60
-10
lines changed

3 files changed

+60
-10
lines changed

Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ private func expandPeerMacroMember(
188188
in context: some MacroExpansionContext,
189189
indentationWidth: Trivia
190190
) throws -> MemberBlockItemListSyntax? {
191+
if let variable = attachedTo.as(VariableDeclSyntax.self), variable.bindings.count > 1 {
192+
throw MacroApplicationError.peerMacroOnVariableWithMultipleBindings
193+
}
194+
191195
guard
192196
let expanded = expandAttachedMacro(
193197
definition: definition,
@@ -216,6 +220,10 @@ private func expandPeerMacroCodeItem(
216220
in context: some MacroExpansionContext,
217221
indentationWidth: Trivia
218222
) throws -> CodeBlockItemListSyntax? {
223+
if let variable = attachedTo.as(VariableDeclSyntax.self), variable.bindings.count > 1 {
224+
throw MacroApplicationError.peerMacroOnVariableWithMultipleBindings
225+
}
226+
219227
guard
220228
let expanded = expandAttachedMacro(
221229
definition: definition,
@@ -425,6 +433,7 @@ let diagnosticDomain: String = "SwiftSyntaxMacroExpansion"
425433

426434
private enum MacroApplicationError: DiagnosticMessage, Error {
427435
case accessorMacroOnVariableWithMultipleBindings
436+
case peerMacroOnVariableWithMultipleBindings
428437
case malformedAccessor
429438

430439
var diagnosticID: MessageID {
@@ -436,15 +445,12 @@ private enum MacroApplicationError: DiagnosticMessage, Error {
436445
var message: String {
437446
switch self {
438447
case .accessorMacroOnVariableWithMultipleBindings:
439-
return """
440-
swift-syntax applies macros syntactically and there is no way to represent a variable \
441-
declaration with multiple bindings that have accessors syntactically. \
442-
While the compiler allows this expansion, swift-syntax cannot represent it and thus \
443-
disallows it.
444-
"""
448+
return "accessor macro can only be applied to a single variable"
449+
case .peerMacroOnVariableWithMultipleBindings:
450+
return "peer macro can only be applied to a single variable"
445451
case .malformedAccessor:
446452
return """
447-
Macro returned a malformed accessor. Accessors should start with an introducer like 'get' or 'set'.
453+
macro returned a malformed accessor. Accessors should start with an introducer like 'get' or 'set'.
448454
"""
449455
}
450456
}
@@ -619,11 +625,12 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
619625
}
620626

621627
override func visit(_ node: VariableDeclSyntax) -> DeclSyntax {
628+
var node = super.visit(node).cast(VariableDeclSyntax.self)
629+
622630
guard !macroAttributes(attachedTo: DeclSyntax(node), ofType: AccessorMacro.Type.self).isEmpty else {
623-
return super.visit(node).cast(DeclSyntax.self)
631+
return DeclSyntax(node)
624632
}
625633

626-
var node = super.visit(node).cast(VariableDeclSyntax.self)
627634
guard node.bindings.count == 1, let binding = node.bindings.first else {
628635
context.addDiagnostics(from: MacroApplicationError.accessorMacroOnVariableWithMultipleBindings, node: node)
629636
return DeclSyntax(node)

Tests/SwiftSyntaxMacroExpansionTest/AccessorMacroTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ final class AccessorMacroTests: XCTestCase {
229229
diagnostics: [
230230
DiagnosticSpec(
231231
message:
232-
"swift-syntax applies macros syntactically and there is no way to represent a variable declaration with multiple bindings that have accessors syntactically. While the compiler allows this expansion, swift-syntax cannot represent it and thus disallows it.",
232+
"accessor macro can only be applied to a single variable",
233233
line: 1,
234234
column: 1,
235235
severity: .error

Tests/SwiftSyntaxMacroExpansionTest/PeerMacroTests.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,4 +130,47 @@ final class PeerMacroTests: XCTestCase {
130130
)
131131
}
132132

133+
func testPeerMacroOnVariableWithMultipleBindings() {
134+
struct TestMacro: PeerMacro {
135+
static func expansion(
136+
of node: AttributeSyntax,
137+
providingPeersOf declaration: some DeclSyntaxProtocol,
138+
in context: some MacroExpansionContext
139+
) throws -> [DeclSyntax] {
140+
return ["var baz: Int = 0"]
141+
}
142+
}
143+
144+
assertMacroExpansion(
145+
"""
146+
@Test
147+
let a = 17, b = 12
148+
""",
149+
expandedSource: """
150+
let a = 17, b = 12
151+
""",
152+
diagnostics: [
153+
DiagnosticSpec(message: "peer macro can only be applied to a single variable", line: 1, column: 1)
154+
],
155+
macros: ["Test": TestMacro.self]
156+
)
157+
158+
assertMacroExpansion(
159+
"""
160+
struct Foo {
161+
@Test
162+
let a = 17, b = 12
163+
}
164+
""",
165+
expandedSource: """
166+
struct Foo {
167+
let a = 17, b = 12
168+
}
169+
""",
170+
diagnostics: [
171+
DiagnosticSpec(message: "peer macro can only be applied to a single variable", line: 2, column: 3)
172+
],
173+
macros: ["Test": TestMacro.self]
174+
)
175+
}
133176
}

0 commit comments

Comments
 (0)