Skip to content

Commit 3a5367e

Browse files
committed
Address code review and update release notes
1 parent 5c47c90 commit 3a5367e

File tree

6 files changed

+63
-30
lines changed

6 files changed

+63
-30
lines changed

Release Notes/511.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
- Description: `SwiftParser` adds an extension on `String` to check if it can be used as an identifier in a given context.
3737
- Pull Request: https://github.com/apple/swift-syntax/pull/2434
3838

39+
- `SyntaxProtocol.asMacroLexicalContext()` and `allMacroLexicalContexts(enclosingSyntax:)`
40+
- Description: Produce the lexical context for a given syntax node (if it has one), or the entire stack of lexical contexts enclosing a syntax node, for use in macro expansion.
41+
- Pull request: https://github.com/apple/swift-syntax/pull/1554
42+
3943
## API Behavior Changes
4044

4145
## Deprecations
@@ -93,6 +97,11 @@
9397
- The new cases cover the newly introduced `ThrowsClauseSyntax`
9498
- Pull request: https://github.com/apple/swift-syntax/pull/2379
9599
- Migration steps: In exhaustive switches over `SyntaxEnum` and `SyntaxKind`, cover the new case.
100+
101+
- `MacroExpansionContext` now requires a property `lexicalContext`:
102+
- Description: The new property provides the lexical context in which the macro is expanded, and has several paired API changes. Types that conform to `MacroExpansionContext` will need to implement this property. Additionally, the `HostToPluginMessage` cases `expandFreestandingMacro` and `expandAttachedMacro` now include an optional `lexicalContext`. Finally, the `SyntaxProtocol.expand(macros:in:indentationWidth:)` syntactic expansion operation has been deprecated in favor of a new version `expand(macros:contextGenerator:indentationWidth:)` that takes a function produces a new macro expansion context for each expansion.
103+
- Pull request: https://github.com/apple/swift-syntax/pull/1554
104+
- Migration steps: Add the new property `lexicalContext` to any `MacroExpansionContext`-conforming types. If implementing the host-to-plugin message protocol, add support for `lexicalContext`. For macro expansion operations going through `SyntaxProtocol.expand`, provide a context generator that creates a fresh context including the lexical context.
96105

97106

98107
## Template

Sources/SwiftCompilerPluginMessageHandling/PluginMessages.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public enum HostToPluginMessage: Codable {
2424
macroRole: PluginMessage.MacroRole? = nil,
2525
discriminator: String,
2626
syntax: PluginMessage.Syntax,
27-
lexicalContext: [PluginMessage.Syntax]?
27+
lexicalContext: [PluginMessage.Syntax]? = nil
2828
)
2929

3030
/// Expand an '@attached' macro.
@@ -37,7 +37,7 @@ public enum HostToPluginMessage: Codable {
3737
parentDeclSyntax: PluginMessage.Syntax?,
3838
extendedTypeSyntax: PluginMessage.Syntax?,
3939
conformanceListSyntax: PluginMessage.Syntax?,
40-
lexicalContext: [PluginMessage.Syntax]?
40+
lexicalContext: [PluginMessage.Syntax]? = nil
4141
)
4242

4343
/// Optionally implemented message to load a dynamic link library.

Sources/SwiftSyntaxMacroExpansion/BasicMacroExpansionContext.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public class BasicMacroExpansionContext {
7373

7474
/// Create a new macro evaluation context.
7575
public init(
76-
lexicalContext: [Syntax],
76+
lexicalContext: [Syntax] = [],
7777
expansionDiscriminator: String = "__macro_local_",
7878
sourceFiles: [SourceFileSyntax: KnownSourceFile] = [:]
7979
) {

Sources/SwiftSyntaxMacros/MacroExpansionContext.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ public protocol MacroExpansionContext: AnyObject {
5959
/// member lists emptied, and properties and subscripts have their accessor
6060
/// blocks removed.
6161
///
62-
/// The first entry in the array is the innermost context, which could be
63-
/// the syntax node to which
62+
/// The first entry in the array is the innermost context. For attached
63+
/// macros, this is often the declaration to which the macro is attached.
64+
/// This array can be empty if there is no context, for example when a
65+
/// freestanding macro is used at file scope.
6466
var lexicalContext: [Syntax] { get }
6567
}
6668

Sources/SwiftSyntaxMacrosTestSupport/Assertions.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,6 @@ public func assertMacroExpansion(
322322

323323
// Expand all macros in the source.
324324
let context = BasicMacroExpansionContext(
325-
lexicalContext: /*FIXME:*/ [],
326325
sourceFiles: [origSourceFile: .init(moduleName: testModuleName, fullFilePath: testFileName)]
327326
)
328327

Tests/SwiftSyntaxMacroExpansionTest/LexicalContextTests.swift

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@ extension SyntaxProtocol {
6565
/// Form a function name.
6666
private func formFunctionName(
6767
_ baseName: String,
68-
_ parameters: FunctionParameterClauseSyntax?,
69-
isSubscript: Bool = false
68+
_ parameters: FunctionParameterClauseSyntax?
7069
) -> String {
7170
let argumentNames: [String] =
7271
parameters?.parameters.map { param in
@@ -97,8 +96,7 @@ extension SyntaxProtocol {
9796
if let subscriptDecl = self.as(SubscriptDeclSyntax.self) {
9897
return formFunctionName(
9998
"subscript",
100-
subscriptDecl.parameterClause,
101-
isSubscript: true
99+
subscriptDecl.parameterClause
102100
)
103101
}
104102

@@ -193,14 +191,19 @@ final class LexicalContextTests: XCTestCase {
193191
func f(a: Int, _: Double, c: Int) {
194192
print(#function)
195193
}
196-
197-
struct X {
198-
var computed: String {
199-
get {
200-
#function
201-
}
194+
""",
195+
expandedSource: """
196+
func f(a: Int, _: Double, c: Int) {
197+
print( "f(a:_:c:)")
202198
}
199+
""",
200+
macros: ["function": FunctionMacro.self],
201+
indentationWidth: indentationWidth
202+
)
203203

204+
assertMacroExpansion(
205+
"""
206+
struct X {
204207
init(from: String) {
205208
#function
206209
}
@@ -213,23 +216,9 @@ final class LexicalContextTests: XCTestCase {
213216
#function
214217
}
215218
}
216-
217-
extension A {
218-
static var staticProp: String = #function
219-
}
220219
""",
221220
expandedSource: """
222-
func f(a: Int, _: Double, c: Int) {
223-
print( "f(a:_:c:)")
224-
}
225-
226221
struct X {
227-
var computed: String {
228-
get {
229-
"computed"
230-
}
231-
}
232-
233222
init(from: String) {
234223
"init(from:)"
235224
}
@@ -242,7 +231,37 @@ final class LexicalContextTests: XCTestCase {
242231
"subscript(a:)"
243232
}
244233
}
234+
""",
235+
macros: ["function": FunctionMacro.self],
236+
indentationWidth: indentationWidth
237+
)
245238

239+
assertMacroExpansion(
240+
"""
241+
var computed: String {
242+
get {
243+
#function
244+
}
245+
}
246+
""",
247+
expandedSource: """
248+
var computed: String {
249+
get {
250+
"computed"
251+
}
252+
}
253+
""",
254+
macros: ["function": FunctionMacro.self],
255+
indentationWidth: indentationWidth
256+
)
257+
258+
assertMacroExpansion(
259+
"""
260+
extension A {
261+
static var staticProp: String = #function
262+
}
263+
""",
264+
expandedSource: """
246265
extension A {
247266
static var staticProp: String = "staticProp"
248267
}
@@ -294,5 +313,9 @@ final class LexicalContextTests: XCTestCase {
294313
""",
295314
macros: ["allLexicalContexts": AllLexicalContextsMacro.self]
296315
)
316+
317+
// Test closures separately, because they don't fit as declaration macros.
318+
let closure: ExprSyntax = "{ (a, b) in print(a + b) }"
319+
XCTAssertEqual(closure.asMacroLexicalContext()!.description, "{ (a, b) in }")
297320
}
298321
}

0 commit comments

Comments
 (0)