Skip to content

Commit a7726b9

Browse files
committed
Fix newline closing brace and opening brace for expanded macros
1 parent 72ec001 commit a7726b9

File tree

2 files changed

+150
-5
lines changed

2 files changed

+150
-5
lines changed

Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -762,10 +762,8 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
762762
return CodeBlockItemListSyntax(newItems)
763763
}
764764

765-
override func visit(_ node: MemberBlockItemListSyntax) -> MemberBlockItemListSyntax {
765+
override func visit(_ node: MemberBlockSyntax) -> MemberBlockSyntax {
766766
let parentDeclGroup = node
767-
.parent?
768-
.as(MemberBlockSyntax.self)?
769767
.parent?
770768
.as(DeclSyntax.self)
771769
var newItems: [MemberBlockItemSyntax] = []
@@ -792,7 +790,7 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
792790
extensions += expandExtensions(of: node.decl)
793791
}
794792

795-
for var item in node {
793+
for var item in node.members {
796794
// Expand member attribute members attached to the declaration context.
797795
// Note that MemberAttribute macros are _not_ applied to generated members
798796
if let parentDeclGroup, let decl = item.decl.asProtocol(WithAttributesSyntax.self) {
@@ -825,7 +823,29 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
825823
}
826824
}
827825

828-
return .init(newItems)
826+
/// Returns an leading trivia for the member blocks closing brace.
827+
/// It will add a leading newline, if there is none.
828+
var leadingTriviaForClosingBrace: Trivia {
829+
if (node.members.isEmpty || newItems.isEmpty) && newItems.isEmpty {
830+
return node.rightBrace.leadingTrivia
831+
}
832+
833+
if node.rightBrace.leadingTrivia.contains(where: { $0.isNewline }) {
834+
return node.rightBrace.leadingTrivia
835+
}
836+
837+
if newItems.last?.trailingTrivia.pieces.last?.isNewline ?? false {
838+
return node.rightBrace.leadingTrivia
839+
} else {
840+
return .newline + node.rightBrace.leadingTrivia
841+
}
842+
}
843+
844+
return MemberBlockSyntax(
845+
leftBrace: node.leftBrace,
846+
members: MemberBlockItemListSyntax(newItems),
847+
rightBrace: node.rightBrace.with(\.leadingTrivia, leadingTriviaForClosingBrace)
848+
)
829849
}
830850

831851
override func visit(_ node: VariableDeclSyntax) -> DeclSyntax {

Tests/SwiftSyntaxMacroExpansionTest/MemberMacroTests.swift

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,129 @@ final class MemberMacroTests: XCTestCase {
299299
]
300300
)
301301
}
302+
303+
func testAddMemberToEmptyDeclaration() {
304+
struct TestMacro: MemberMacro {
305+
static func expansion(
306+
of node: AttributeSyntax,
307+
providingMembersOf declaration: some DeclGroupSyntax,
308+
conformingTo protocols: [TypeSyntax],
309+
in context: some MacroExpansionContext
310+
) throws -> [DeclSyntax] {
311+
return [DeclSyntax("var x = 0")]
312+
}
313+
}
314+
315+
assertMacroExpansion(
316+
"""
317+
@Test
318+
struct Foo {}
319+
""",
320+
expandedSource: """
321+
struct Foo {
322+
323+
var x = 0
324+
}
325+
""",
326+
macros: [
327+
"Test": TestMacro.self
328+
],
329+
indentationWidth: indentationWidth
330+
)
331+
}
332+
333+
func testAddTwoMembersToEmptyDeclaration() {
334+
struct TestMacro: MemberMacro {
335+
static func expansion(
336+
of node: AttributeSyntax,
337+
providingMembersOf declaration: some DeclGroupSyntax,
338+
conformingTo protocols: [TypeSyntax],
339+
in context: some MacroExpansionContext
340+
) throws -> [DeclSyntax] {
341+
return [DeclSyntax("var x = 0"), DeclSyntax("var x = 0")]
342+
}
343+
}
344+
345+
assertMacroExpansion(
346+
"""
347+
@Test
348+
struct Foo {}
349+
""",
350+
expandedSource: """
351+
struct Foo {
352+
353+
var x = 0
354+
355+
var x = 0
356+
}
357+
""",
358+
macros: [
359+
"Test": TestMacro.self
360+
],
361+
indentationWidth: indentationWidth
362+
)
363+
}
364+
365+
func testAddMemberToEmptyDeclarationWithEndingNewline() {
366+
struct TestMacro: MemberMacro {
367+
static func expansion(
368+
of node: AttributeSyntax,
369+
providingMembersOf declaration: some DeclGroupSyntax,
370+
conformingTo protocols: [TypeSyntax],
371+
in context: some MacroExpansionContext
372+
) throws -> [DeclSyntax] {
373+
return [DeclSyntax("var x = 0\n")]
374+
}
375+
}
376+
377+
assertMacroExpansion(
378+
"""
379+
@Test
380+
struct Foo {}
381+
""",
382+
expandedSource: """
383+
struct Foo {
384+
385+
var x = 0
386+
}
387+
""",
388+
macros: [
389+
"Test": TestMacro.self
390+
],
391+
indentationWidth: indentationWidth
392+
)
393+
}
394+
395+
func testAddMemberToDeclarationWithASingleVariable() {
396+
struct TestMacro: MemberMacro {
397+
static func expansion(
398+
of node: AttributeSyntax,
399+
providingMembersOf declaration: some DeclGroupSyntax,
400+
conformingTo protocols: [TypeSyntax],
401+
in context: some MacroExpansionContext
402+
) throws -> [DeclSyntax] {
403+
return [DeclSyntax("var x = 0\n")]
404+
}
405+
}
406+
407+
assertMacroExpansion(
408+
"""
409+
@Test
410+
struct Foo {
411+
var y = 0
412+
}
413+
""",
414+
expandedSource: """
415+
struct Foo {
416+
var y = 0
417+
418+
var x = 0
419+
}
420+
""",
421+
macros: [
422+
"Test": TestMacro.self
423+
],
424+
indentationWidth: indentationWidth
425+
)
426+
}
302427
}

0 commit comments

Comments
 (0)