Skip to content

Commit 32c6662

Browse files
committed
adjust Indentation Of Freestanding Macro
1 parent f38bac3 commit 32c6662

File tree

2 files changed

+142
-17
lines changed

2 files changed

+142
-17
lines changed

Sources/SwiftSyntaxMacroExpansion/MacroSystem.swift

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,8 @@ private func expandFreestandingMemberDeclList(
7878
return nil
7979
}
8080

81-
let indentedSource =
82-
expanded
83-
.indented(by: node.indentationOfFirstLine)
84-
.wrappingInTrivia(from: node)
81+
let indentedSource = adjustIndentationOfFreestandingMacro(expandedCode: expanded, node: node)
82+
8583
return "\(raw: indentedSource)"
8684
}
8785

@@ -103,13 +101,8 @@ private func expandFreestandingCodeItemList(
103101
return nil
104102
}
105103

106-
// The macro expansion just provides an expansion for the content.
107-
// We need to make sure that we aren’t dropping the trivia before and after
108-
// the expansion.
109-
let indentedSource =
110-
expanded
111-
.indented(by: node.indentationOfFirstLine)
112-
.wrappingInTrivia(from: node)
104+
let indentedSource = adjustIndentationOfFreestandingMacro(expandedCode: expanded, node: node)
105+
113106
return "\(raw: indentedSource)"
114107
}
115108

@@ -131,13 +124,29 @@ private func expandFreestandingExpr(
131124
return nil
132125
}
133126

134-
let indentedSource =
135-
expanded
136-
.indented(by: node.indentationOfFirstLine)
137-
.wrappingInTrivia(from: node)
127+
let indentedSource = adjustIndentationOfFreestandingMacro(expandedCode: expanded, node: node)
128+
138129
return "\(raw: indentedSource)"
139130
}
140131

132+
/// Adds the appropriate indentation on expanded code even if it's multi line.
133+
/// Makes sure original macro expression's trivia is maintained by adding it to expanded code.
134+
private func adjustIndentationOfFreestandingMacro(expandedCode: String, node: some FreestandingMacroExpansionSyntax) -> String {
135+
let indentationOfFirstLine = node.indentationOfFirstLine
136+
137+
var indentedSource =
138+
expandedCode
139+
.indented(by: indentationOfFirstLine)
140+
.wrappingInTrivia(from: node)
141+
142+
// if the experssion started in middle of the line, then remove indentation of the first line
143+
if !node.leadingTrivia.contains(where: \.isNewline) {
144+
indentedSource.removeFirst(indentationOfFirstLine.sourceLength.utf8Length)
145+
}
146+
147+
return indentedSource
148+
}
149+
141150
private func expandMemberMacro(
142151
definition: MemberMacro.Type,
143152
attributeNode: AttributeSyntax,

Tests/SwiftSyntaxMacroExpansionTest/LexicalContextTests.swift

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,24 @@ public struct FunctionMacro: ExpressionMacro {
173173
}
174174
}
175175

176+
public struct MultilineFunctionMacro: ExpressionMacro {
177+
public static func expansion<
178+
Node: FreestandingMacroExpansionSyntax,
179+
Context: MacroExpansionContext
180+
>(
181+
of node: Node,
182+
in context: Context
183+
) -> ExprSyntax {
184+
guard let lexicalContext = context.lexicalContext.first,
185+
let name = lexicalContext.functionName(in: context)
186+
else {
187+
return #""<unknown>""#
188+
}
189+
190+
return ExprSyntax("{\n\(literal: name)\n}")
191+
}
192+
}
193+
176194
public struct AllLexicalContextsMacro: DeclarationMacro {
177195
public static func expansion(
178196
of node: some FreestandingMacroExpansionSyntax,
@@ -194,7 +212,7 @@ final class LexicalContextTests: XCTestCase {
194212
""",
195213
expandedSource: """
196214
func f(a: Int, _: Double, c: Int) {
197-
print( "f(a:_:c:)")
215+
print("f(a:_:c:)")
198216
}
199217
""",
200218
macros: ["function": FunctionMacro.self],
@@ -263,14 +281,112 @@ final class LexicalContextTests: XCTestCase {
263281
""",
264282
expandedSource: """
265283
extension A {
266-
static var staticProp: String = "staticProp"
284+
static var staticProp: String = "staticProp"
267285
}
268286
""",
269287
macros: ["function": FunctionMacro.self],
270288
indentationWidth: indentationWidth
271289
)
272290
}
273291

292+
func testPoundMultilineFunction() {
293+
assertMacroExpansion(
294+
"""
295+
func f(a: Int, _: Double, c: Int) {
296+
print(#function)
297+
}
298+
""",
299+
expandedSource: """
300+
func f(a: Int, _: Double, c: Int) {
301+
print({
302+
"f(a:_:c:)"
303+
})
304+
}
305+
""",
306+
macros: ["function": MultilineFunctionMacro.self],
307+
indentationWidth: indentationWidth
308+
)
309+
310+
assertMacroExpansion(
311+
"""
312+
struct X {
313+
init(from: String) {
314+
#function
315+
}
316+
317+
subscript(a: Int) -> String {
318+
#function
319+
}
320+
321+
subscript(a a: Int) -> String {
322+
#function
323+
}
324+
}
325+
""",
326+
expandedSource: """
327+
struct X {
328+
init(from: String) {
329+
{
330+
"init(from:)"
331+
}
332+
}
333+
334+
subscript(a: Int) -> String {
335+
{
336+
"subscript(_:)"
337+
}
338+
}
339+
340+
subscript(a a: Int) -> String {
341+
{
342+
"subscript(a:)"
343+
}
344+
}
345+
}
346+
""",
347+
macros: ["function": MultilineFunctionMacro.self],
348+
indentationWidth: indentationWidth
349+
)
350+
351+
assertMacroExpansion(
352+
"""
353+
var computed: String {
354+
get {
355+
#function
356+
}
357+
}
358+
""",
359+
expandedSource: """
360+
var computed: String {
361+
get {
362+
{
363+
"computed"
364+
}
365+
}
366+
}
367+
""",
368+
macros: ["function": MultilineFunctionMacro.self],
369+
indentationWidth: indentationWidth
370+
)
371+
372+
assertMacroExpansion(
373+
"""
374+
extension A {
375+
static var staticProp: String = #function
376+
}
377+
""",
378+
expandedSource: """
379+
extension A {
380+
static var staticProp: String = {
381+
"staticProp"
382+
}
383+
}
384+
""",
385+
macros: ["function": MultilineFunctionMacro.self],
386+
indentationWidth: indentationWidth
387+
)
388+
}
389+
274390
func testAllLexicalContexts() {
275391
assertMacroExpansion(
276392
"""

0 commit comments

Comments
 (0)