Skip to content

Commit 973060c

Browse files
committed
[Macros] Remove the source location converter from MacroEvaluationContext.
Having the source location converter in the context exposes the entire contents of the source file containing the macro expansion to the implementation of the macro. While convenient for the macro author, this breaks Swift's incremental build model, because Swift assumes that (e.g.) changing the body of a function cannot affect the result of type-checking the body of an unrelated function. Drop the implementations of some "built-in" macros that are no longer expressible, such as `#filePath`, `#line`, and `#column`.
1 parent f4ede75 commit 973060c

File tree

4 files changed

+37
-76
lines changed

4 files changed

+37
-76
lines changed

Sources/_SwiftSyntaxMacros/MacroEvaluationContext.swift

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,29 @@ public struct MacroEvaluationContext {
1818
/// The name of the module in which the macro is being evaluated.
1919
public let moduleName: String
2020

21-
/// Used to map the provided syntax nodes into source locations.
22-
public let sourceLocationConverter: SourceLocationConverter
21+
/// The name of the source file in which the macro is being evaluated,
22+
/// without any path information.
23+
///
24+
/// Swift prevents two files within the same module from having the same
25+
/// name, so the combination of file and module name is unique.
26+
public let fileName: String
2327

28+
/// Create a new macro evaluation context.
29+
public init(moduleName: String, fileName: String) {
30+
self.moduleName = moduleName
31+
self.fileName = fileName
32+
}
33+
34+
/// Create a new macro evaluation context.
35+
@available(*, deprecated, message: "Use init(moduleName:fileName:)")
2436
public init(
2537
moduleName: String,
2638
sourceLocationConverter: SourceLocationConverter
2739
) {
28-
self.moduleName = moduleName
29-
self.sourceLocationConverter = sourceLocationConverter
40+
let fileName = sourceLocationConverter.location(
41+
for: AbsolutePosition(utf8Offset: -1)
42+
).file ?? "unknown.swift"
43+
44+
self.init(moduleName: moduleName, fileName: fileName)
3045
}
3146
}

Sources/_SwiftSyntaxMacros/MacroSystem+Builtin.swift

Lines changed: 1 addition & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,6 @@
1313
import SwiftSyntax
1414
import SwiftSyntaxBuilder
1515

16-
public struct ColumnMacro: ExpressionMacro {
17-
public static func apply(
18-
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
19-
) -> MacroResult<ExprSyntax> {
20-
let line = macro.startLocation(
21-
converter: context.sourceLocationConverter
22-
).column ?? 0
23-
return .init("\(literal: line)")
24-
}
25-
}
26-
27-
public struct LineMacro: ExpressionMacro {
28-
public static func apply(
29-
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
30-
) -> MacroResult<ExprSyntax> {
31-
let line = macro.startLocation(
32-
converter: context.sourceLocationConverter
33-
).line ?? 0
34-
return .init("\(literal: line)")
35-
}
36-
}
37-
3816
extension PatternBindingSyntax {
3917
/// When the variable is declaring a single binding, produce the name of
4018
/// that binding.
@@ -208,37 +186,12 @@ public struct ImageLiteralMacro: ExpressionMacro {
208186
}
209187
}
210188

211-
public struct FilePathMacro: ExpressionMacro {
212-
public static func apply(
213-
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
214-
) -> MacroResult<ExprSyntax> {
215-
let fileName = context.sourceLocationConverter.location(
216-
for: .init(utf8Offset: 0)
217-
).file ?? "<unknown file>"
218-
let fileLiteral: ExprSyntax = "\(literal: fileName)"
219-
if let leadingTrivia = macro.leadingTrivia {
220-
return MacroResult(fileLiteral.withLeadingTrivia(leadingTrivia))
221-
}
222-
return MacroResult(fileLiteral)
223-
}
224-
}
225-
226189
public struct FileIDMacro: ExpressionMacro {
227190
public static func apply(
228191
_ macro: MacroExpansionExprSyntax, in context: MacroEvaluationContext
229192
) -> MacroResult<ExprSyntax> {
230-
var fileName = context.sourceLocationConverter.location(
231-
for: .init(utf8Offset: 0)
232-
).file ?? "<unknown file>"
233-
234-
// Only keep everything after the last slash.
235-
if let lastSlash = fileName.lastIndex(of: "/") {
236-
fileName = String(fileName[fileName.index(after: lastSlash)...])
237-
}
238-
239193
// FIXME: Compiler has more sophisticated file ID computation
240-
let fileID = "\(context.moduleName)/\(fileName)"
241-
194+
let fileID = "\(context.moduleName)/\(context.fileName)"
242195
let fileLiteral: ExprSyntax = "\(literal: fileID)"
243196
if let leadingTrivia = macro.leadingTrivia {
244197
return MacroResult(fileLiteral.withLeadingTrivia(leadingTrivia))
@@ -251,13 +204,9 @@ extension MacroSystem {
251204
public static var builtinMacroSystem: MacroSystem = {
252205
var macroSystem = MacroSystem()
253206
try! macroSystem.add(ColorLiteralMacro.self, name: "colorLiteral")
254-
try! macroSystem.add(ColumnMacro.self, name: "column")
255207
try! macroSystem.add(FileIDMacro.self, name: "fileID")
256-
try! macroSystem.add(FileLiteralMacro.self, name: "file")
257-
try! macroSystem.add(FilePathMacro.self, name: "filePath")
258208
try! macroSystem.add(FunctionMacro.self, name: "function")
259209
try! macroSystem.add(ImageLiteralMacro.self, name: "imageLiteral")
260-
try! macroSystem.add(LineMacro.self, name: "line")
261210
return macroSystem
262211
}()
263212
}

Sources/swift-parser-cli/swift-parser-cli.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@ private func getContentsOfSourceFile(at path: String?) throws -> [UInt8] {
4848
return [UInt8](source)
4949
}
5050

51+
extension String {
52+
/// Drop everything up to and including the last '/' from the string.
53+
fileprivate func withoutPath() -> String {
54+
// Only keep everything after the last slash.
55+
if let lastSlash = lastIndex(of: "/") {
56+
return String(self[index(after: lastSlash)...])
57+
}
58+
59+
return self
60+
}
61+
}
62+
5163
/// Fold all of the sequences in the given source file.
5264
func foldAllSequences(_ tree: SourceFileSyntax) -> (Syntax, [Diagnostic]) {
5365
var diags: [Diagnostic] = []
@@ -230,9 +242,8 @@ class ExpandMacros: ParsableCommand {
230242
resultTree = Syntax(tree)
231243
}
232244

233-
let converter = SourceLocationConverter(file: self.sourceFile, tree: resultTree)
234245
let context = MacroEvaluationContext(
235-
moduleName: "MyModule", sourceLocationConverter: converter
246+
moduleName: "MyModule", fileName: self.sourceFile.withoutPath()
236247
)
237248
var diags = ParseDiagnosticsGenerator.diagnostics(for: tree)
238249
let transformedTree = MacroSystem.exampleSystem.evaluateMacros(

Tests/SwiftSyntaxMacrosTest/MacroSystemTests.swift

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,20 @@ final class MacroSystemTests: XCTestCase {
2020
func testExpressionExpansion() {
2121
let sf: SourceFileSyntax =
2222
"""
23-
#line
24-
let a = (#line)
2523
let b = #stringify(x + y)
2624
#colorLiteral(red: 0.5, green: 0.5, blue: 0.25, alpha: 1.0)
27-
let c = #column
2825
"""
29-
let converter = SourceLocationConverter(file: "test.swift", tree: sf)
3026
let context = MacroEvaluationContext(
31-
moduleName: "MyModule", sourceLocationConverter: converter
27+
moduleName: "MyModule", fileName: "test.swift"
3228
)
3329
let transformedSF = MacroSystem.exampleSystem.evaluateMacros(
3430
node: sf, in: context, errorHandler: { error in }
3531
)
3632
AssertStringsEqualWithDiff(
3733
transformedSF.description,
3834
"""
39-
1
40-
let a = (2)
4135
let b = (x + y, "x + y")
4236
.init(_colorLiteralRed: 0.5, green: 0.5, blue: 0.25, alpha: 1.0)
43-
let c = 9
4437
"""
4538
)
4639
}
@@ -53,9 +46,8 @@ final class MacroSystemTests: XCTestCase {
5346
return true
5447
})
5548
"""
56-
let converter = SourceLocationConverter(file: "test.swift", tree: sf)
5749
let context = MacroEvaluationContext(
58-
moduleName: "MyModule", sourceLocationConverter: converter
50+
moduleName: "MyModule", fileName: "test.swift"
5951
)
6052
let transformedSF = MacroSystem.exampleSystem.evaluateMacros(
6153
node: sf, in: context, errorHandler: { error in }
@@ -102,9 +94,8 @@ final class MacroSystemTests: XCTestCase {
10294
static var staticProp: String = #function
10395
}
10496
"""
105-
let converter = SourceLocationConverter(file: "test.swift", tree: sf)
10697
let context = MacroEvaluationContext(
107-
moduleName: "MyModule", sourceLocationConverter: converter
98+
moduleName: "MyModule", fileName: "test.swift"
10899
)
109100
let transformedSF = MacroSystem.exampleSystem.evaluateMacros(
110101
node: sf, in: context, errorHandler: { error in }
@@ -146,22 +137,17 @@ final class MacroSystemTests: XCTestCase {
146137
func testFileExpansions() {
147138
let sf: SourceFileSyntax =
148139
"""
149-
let a = #filePath
150140
let b = #fileID
151141
"""
152-
let converter = SourceLocationConverter(
153-
file: "/tmp/src/taylor.swift", tree: sf
154-
)
155142
let context = MacroEvaluationContext(
156-
moduleName: "MyModule", sourceLocationConverter: converter
143+
moduleName: "MyModule", fileName: "taylor.swift"
157144
)
158145
let transformedSF = MacroSystem.exampleSystem.evaluateMacros(
159146
node: sf, in: context, errorHandler: { error in }
160147
)
161148
AssertStringsEqualWithDiff(
162149
transformedSF.description,
163150
"""
164-
let a = "/tmp/src/taylor.swift"
165151
let b = "MyModule/taylor.swift"
166152
"""
167153
)

0 commit comments

Comments
 (0)