Skip to content

Commit 8de8eb8

Browse files
committed
Fix newline closing brace and opening brace for expanded macros
1 parent 1aea845 commit 8de8eb8

File tree

2 files changed

+146
-6
lines changed

2 files changed

+146
-6
lines changed

Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift

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

764-
override func visit(_ node: MemberBlockItemListSyntax) -> MemberBlockItemListSyntax {
764+
override func visit(_ node: MemberBlockSyntax) -> MemberBlockSyntax {
765765
let parentDeclGroup = node
766-
.parent?
767-
.as(MemberBlockSyntax.self)?
768766
.parent?
769767
.as(DeclSyntax.self)
770768
var newItems: [MemberBlockItemSyntax] = []
@@ -791,7 +789,7 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
791789
extensions += expandExtensions(of: node.decl)
792790
}
793791

794-
for var item in node {
792+
for var item in node.members {
795793
// Expand member attribute members attached to the declaration context.
796794
// Note that MemberAttribute macros are _not_ applied to generated members
797795
if let parentDeclGroup, let decl = item.decl.asProtocol(WithAttributesSyntax.self) {
@@ -824,7 +822,28 @@ private class MacroApplication<Context: MacroExpansionContext>: SyntaxRewriter {
824822
}
825823
}
826824

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

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

Tests/SwiftSyntaxMacroExpansionTest/MemberMacroTests.swift

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

0 commit comments

Comments
 (0)