Skip to content

Commit 5824002

Browse files
committed
Fix trivia transfer bugs for freestanding expression macros
There were two bugs in the way we transferred trivia from the original macro expansion expression to the expanded expression. 1. We were attaching the stripped leading trivia to the end of the node 2. We weren’t resetting the `lineContainedComment` and `lineContainedNonWhitespaceNonComment` variables when seeing a newline in a comment-only line (1) is easy to fix. For (2), I just remove the entire comment-handling logic because it didn’t match what “Inline Macro” was doing anyway. rdar://113639097
1 parent e030d7a commit 5824002

File tree

3 files changed

+44
-49
lines changed

3 files changed

+44
-49
lines changed

Sources/SwiftSyntaxMacroExpansion/IndentationUtils.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@ extension Trivia {
8585
}
8686
return Trivia(pieces: resultPieces)
8787
}
88+
89+
/// Remove all indentation from the last line of this trivia
90+
var removingIndentationOnLastLine: Trivia {
91+
let lastNewlineIndex = pieces.lastIndex(where: \.isNewline) ?? pieces.startIndex
92+
93+
return Trivia(pieces: pieces[..<lastNewlineIndex]) + Trivia(pieces: pieces[lastNewlineIndex...]).removingIndentation
94+
}
8895
}
8996

9097
extension SyntaxProtocol {

Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift

Lines changed: 13 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private func expandFreestandingMemberDeclList(
6666
let indentedSource =
6767
expanded
6868
.indented(by: node.indentationOfFirstLine)
69-
.wrappingInNonCommentTrivia(from: node)
69+
.wrappingInTrivia(from: node)
7070
return "\(raw: indentedSource)"
7171
}
7272

@@ -94,7 +94,7 @@ private func expandFreestandingCodeItemList(
9494
let indentedSource =
9595
expanded
9696
.indented(by: node.indentationOfFirstLine)
97-
.wrappingInNonCommentTrivia(from: node)
97+
.wrappingInTrivia(from: node)
9898
return "\(raw: indentedSource)"
9999
}
100100

@@ -119,7 +119,7 @@ private func expandFreestandingExpr(
119119
let indentedSource =
120120
expanded
121121
.indented(by: node.indentationOfFirstLine)
122-
.wrappingInNonCommentTrivia(from: node)
122+
.wrappingInTrivia(from: node)
123123
return "\(raw: indentedSource)"
124124
}
125125

@@ -947,17 +947,18 @@ private extension AccessorBlockSyntax {
947947
}
948948

949949
private extension String {
950-
/// Add any non-comment trivia from `node` before/after this string.
950+
/// Add any trivia from `node` before/after this string.
951951
///
952-
/// We need to do this because the macro is responsible for copying trivia
953-
/// from the freestanding macro to the generated declaration.
954-
///
955-
/// Essentially, what we want to keep any empty newlines in front of the
956-
/// freestanding macro that separate it from the previous declarations.
957-
func wrappingInNonCommentTrivia(from node: some SyntaxProtocol) -> String {
958-
return node.leadingTrivia.removingComments.removingIndentation.description
952+
/// We need to do this because we are replacing the entire macro expansion
953+
/// declaration / expression with the expanded source but semantically, the
954+
/// user should think about it as just replacing the `#...` expression without
955+
/// any trivia.
956+
func wrappingInTrivia(from node: some SyntaxProtocol) -> String {
957+
// We need to remove the indentation from the last line because the macro
958+
// expansion buffer already contains the indentation.
959+
return node.leadingTrivia.removingIndentationOnLastLine.description
959960
+ self
960-
+ node.leadingTrivia.removingComments.removingIndentation.description
961+
+ node.trailingTrivia.description
961962
}
962963
}
963964

@@ -972,37 +973,3 @@ private extension SyntaxProtocol {
972973
return self.detached
973974
}
974975
}
975-
976-
private extension Trivia {
977-
/// Drop all comments from the trivia.
978-
///
979-
/// If a comment is the only entry on a line, drop the entire line instead of
980-
/// leaving an empty line.
981-
var removingComments: Trivia {
982-
var result: [TriviaPiece] = []
983-
984-
var lineContainedComment = false
985-
var lineContainedNonWhitespaceNonComment = false
986-
for piece in self.pieces {
987-
switch piece {
988-
case .spaces, .tabs:
989-
result.append(piece)
990-
case .backslashes, .formfeeds, .pounds, .unexpectedText, .verticalTabs:
991-
lineContainedNonWhitespaceNonComment = true
992-
result.append(piece)
993-
case .blockComment, .docBlockComment, .docLineComment, .lineComment:
994-
lineContainedComment = true
995-
case .carriageReturns, .carriageReturnLineFeeds, .newlines:
996-
if lineContainedComment && !lineContainedNonWhitespaceNonComment {
997-
continue
998-
} else {
999-
result.append(piece)
1000-
}
1001-
lineContainedComment = false
1002-
lineContainedNonWhitespaceNonComment = false
1003-
}
1004-
}
1005-
1006-
return Trivia(pieces: result)
1007-
}
1008-
}

Tests/SwiftSyntaxMacroExpansionTest/MacroSystemTests.swift

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,25 @@ final class MacroSystemTests: XCTestCase {
701701
)
702702
}
703703

704+
func testTriviaTransferOnExpressionMacro() {
705+
assertMacroExpansion(
706+
"""
707+
// Ignore me
708+
\t
709+
// Capture me
710+
#stringify(x)
711+
""",
712+
expandedSource: """
713+
// Ignore me
714+
\t
715+
// Capture me
716+
(x, "x")
717+
""",
718+
macros: testMacros,
719+
indentationWidth: indentationWidth
720+
)
721+
}
722+
704723
func testCommentsOnExpressionMacro() {
705724
assertMacroExpansion(
706725
"""
@@ -709,7 +728,7 @@ final class MacroSystemTests: XCTestCase {
709728
""",
710729
expandedSource: """
711730
let b =
712-
(x + y, "x + y")
731+
/*leading */ (x + y, "x + y") /*trailing*/
713732
""",
714733
macros: testMacros,
715734
indentationWidth: indentationWidth
@@ -1441,10 +1460,11 @@ final class MacroSystemTests: XCTestCase {
14411460
) /* trailing comment */
14421461
""",
14431462
expandedSource: """
1463+
// some comment
14441464
func foo() {
14451465
}
14461466
func bar() {
1447-
}
1467+
} /* trailing comment */
14481468
""",
14491469
macros: ["decls": DeclsFromStringsMacro.self],
14501470
indentationWidth: indentationWidth
@@ -1464,10 +1484,11 @@ final class MacroSystemTests: XCTestCase {
14641484
""",
14651485
expandedSource: """
14661486
struct Foo {
1487+
// some comment
14671488
func foo() {
14681489
}
14691490
func bar() {
1470-
}
1491+
} /* trailing comment */
14711492
}
14721493
""",
14731494
macros: ["decls": DeclsFromStringsMacro.self],

0 commit comments

Comments
 (0)