I'm having trouble using #sourceLocation
inside a body macro expansion because the first level of nodes is always formatted.
Consider the following macro:
public struct SourceLocationMacro: BodyMacro {
public static var formatMode: FormatMode { .disabled }
public static func expansion(of node: AttributeSyntax, providingBodyFor declaration: some DeclSyntaxProtocol & WithOptionalCodeBlockSyntax, in context: some MacroExpansionContext) throws -> [CodeBlockItemSyntax] {
if let statements = declaration.body?.statements {
var body: [CodeBlockItemSyntax] = []
statements.forEach { statement in
if let location = context.location(of: statement, at: .afterLeadingTrivia, filePathMode: .filePath) {
let transformed = CodeBlockItemListSyntax {
"\n#sourceLocation(file: \(location.file), line: \(location.line))"
statement
"\n#sourceLocation()"
}
body.append(contentsOf: transformed)
}
}
return body
} else {
return []
}
}
}
If applied to the following code it works fine because let x
is following the default indentation:
@SourceLocationMacro
func f() {
let x: Int = 1
^ Immutable value 'x' was never used; consider replacing with '_' or removing it
}
// Macro Expansion
{
#sourceLocation(file: "/Users/mateusrodrigues/Desktop/TriviaMacro/Sources/TriviaMacroClient/main.swift", line: 8)
let x: Int = 1
#sourceLocation()
}
But if I indent let x
with a different number of spaces the diagnostic is reported in the wrong column because the code is automatically formatted.
@SourceLocationMacro
func f() {
let x: Int = 1
^ Immutable value 'x' was never used; consider replacing with '_' or removing it
}
// Macro Expansion
{
#sourceLocation(file: "/Users/mateusrodrigues/Desktop/TriviaMacro/Sources/TriviaMacroClient/main.swift", line: 8)
let x: Int = 1
#sourceLocation()
}
The problem still affects others level in less degree by shifting the indentation:
let transformed = CodeBlockItemListSyntax {
"\n#sourceLocation(file: \(location.file), line: \(location.line))"
statement
"\n#sourceLocation()"
}
let item: CodeBlockItemSyntax = "let _ = { \(transformed) }()"
body.append(item)
@SourceLocationMacro
func f() {
let x: Int = 1
^ Immutable value 'x' was never used; consider replacing with '_' or removing it
}
{
let _ = {
#sourceLocation(file: "/Users/mateusrodrigues/Desktop/TriviaMacro/Sources/TriviaMacroClient/main.swift", line: 8)
let x: Int = 1
#sourceLocation() }()
}
This can be fixed by calculating the indentation using BasicFormat.inferIndentation(of:)
and subtracting but not a pleasant experience and inferIndentation(of:)
requires at least 3 lines of code so there's that too.
Is there anyway to disable this behavior? I expected that with formatMode
set to disabled
I would have totally control over the indentation.