Skip to content

Commit e7be8f3

Browse files
committed
Provide the lexical context to macro expansions
1 parent ee10a4e commit e7be8f3

File tree

6 files changed

+52
-13
lines changed

6 files changed

+52
-13
lines changed

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -508,7 +508,8 @@ func expandFreestandingMacroIPC(
508508
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
509509
macroRole: pluginMacroRole,
510510
discriminator: discriminator,
511-
syntax: PluginMessage.Syntax(syntax: Syntax(expansionSyntax), in: sourceFilePtr)!
511+
syntax: PluginMessage.Syntax(syntax: Syntax(expansionSyntax), in: sourceFilePtr)!,
512+
lexicalContext: pluginLexicalContext(of: expansionSyntax)
512513
)
513514
do {
514515
let result = try macro.plugin.sendMessageAndWait(message)
@@ -564,6 +565,7 @@ func expandFreestandingMacroInProcess(
564565
sourceManager.insert(sourceFilePtr)
565566

566567
let context = sourceManager.createMacroExpansionContext(
568+
lexicalContext: lexicalContext(of: expansionSyntax),
567569
discriminator: discriminator
568570
)
569571

@@ -757,6 +759,20 @@ func expandAttachedMacro(
757759
)
758760
}
759761

762+
/// Produce the full lexical context of the given node to pass along to
763+
/// macro expansion.
764+
private func lexicalContext(of node: some SyntaxProtocol) -> [Syntax] {
765+
// FIXME: Should we query the source manager to get the macro expansion
766+
// information?
767+
node.allMacroLexicalContexts()
768+
}
769+
770+
/// Produce the full lexical context of the given node to pass along to
771+
/// macro expansion.
772+
private func pluginLexicalContext(of node: some SyntaxProtocol) -> [PluginMessage.Syntax] {
773+
lexicalContext(of: node).compactMap { .init(syntax: $0) }
774+
}
775+
760776
func expandAttachedMacroIPC(
761777
diagEnginePtr: UnsafeMutableRawPointer,
762778
macroPtr: UnsafeRawPointer,
@@ -829,6 +845,7 @@ func expandAttachedMacroIPC(
829845
conformanceListSyntax = .init(syntax: Syntax(placeholderDecl))!
830846
}
831847

848+
832849
// Send the message.
833850
let message = HostToPluginMessage.expandAttachedMacro(
834851
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
@@ -838,7 +855,8 @@ func expandAttachedMacroIPC(
838855
declSyntax: declSyntax,
839856
parentDeclSyntax: parentDeclSyntax,
840857
extendedTypeSyntax: extendedTypeSyntax,
841-
conformanceListSyntax: conformanceListSyntax
858+
conformanceListSyntax: conformanceListSyntax,
859+
lexicalContext: pluginLexicalContext(of: declarationNode)
842860
)
843861
do {
844862
let expandedSource: String?
@@ -926,6 +944,7 @@ func expandAttachedMacroInProcess(
926944

927945
// Create an expansion context
928946
let context = sourceManager.createMacroExpansionContext(
947+
lexicalContext: lexicalContext(of: declarationNode),
929948
discriminator: discriminator
930949
)
931950

lib/ASTGen/Sources/ASTGen/SourceManager+MacroExpansionContext.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ extension SourceManager {
1919
/// The source manager.
2020
private let sourceManager: SourceManager
2121

22+
/// The lexical context for this expansion.
23+
let lexicalContext: [Syntax]
24+
2225
/// The set of diagnostics that were emitted as part of expanding the
2326
/// macro.
2427
var diagnostics: [Diagnostic] = []
@@ -35,18 +38,25 @@ extension SourceManager {
3538
/// Used in conjunction with `expansionDiscriminator`.
3639
private var uniqueNames: [String: Int] = [:]
3740

38-
init(sourceManager: SourceManager, discriminator: String) {
41+
init(
42+
sourceManager: SourceManager,
43+
lexicalContext: [Syntax],
44+
discriminator: String
45+
) {
3946
self.sourceManager = sourceManager
47+
self.lexicalContext = lexicalContext
4048
self.discriminator = discriminator
4149
}
4250
}
4351

4452
/// Create a new macro expansion context
4553
func createMacroExpansionContext(
54+
lexicalContext: [Syntax],
4655
discriminator: String = ""
4756
) -> MacroExpansionContext {
4857
return MacroExpansionContext(
4958
sourceManager: self,
59+
lexicalContext: lexicalContext,
5060
discriminator: discriminator
5161
)
5262
}

test/Macros/Inputs/syntax_macro_definitions.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2316,3 +2316,13 @@ public struct AddSubscript: MemberMacro {
23162316
]
23172317
}
23182318
}
2319+
2320+
public struct AllLexicalContextsMacro: DeclarationMacro {
2321+
public static func expansion(
2322+
of node: some FreestandingMacroExpansionSyntax,
2323+
in context: some MacroExpansionContext
2324+
) throws -> [DeclSyntax] {
2325+
context.lexicalContext.compactMap { $0.as(DeclSyntax.self)?.trimmed }
2326+
}
2327+
}
2328+

test/Macros/macro_plugin_basic.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030

3131
// CHECK: ->(plugin:[[#PID:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}}
3232
// CHECK: <-(plugin:[[#PID]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
33-
// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"testString","typeName":"TestStringMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":5,"offset":301},"source":"#testString(123)"}}}
33+
// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}func test{{.*}}],"macro":{"moduleName":"TestPlugin","name":"testString","typeName":"TestStringMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":5,"offset":301},"source":"#testString(123)"}}}
3434
// CHECK: <-(plugin:[[#PID]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"\"123\"\n + \"foo \""}}
35-
// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"testStringWithError","typeName":"TestStringWithErrorMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":6,"offset":336},"source":"#testStringWithError(321)"}}}
35+
// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"testStringWithError","typeName":"TestStringWithErrorMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":6,"offset":336},"source":"#testStringWithError(321)"}}}
3636
// CHECK: <-(plugin:[[#PID]]) {"expandFreestandingMacroResult":{"diagnostics":[{"fixIts":[],"highlights":[],"message":"message from plugin","notes":[],"position":{"fileName":"{{.*}}test.swift","offset":336},"severity":"error"}],"expandedSource":"\"bar\""}}
3737

3838
//--- test.swift

test/Macros/macro_plugin_error.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717

1818
// CHECK: ->(plugin:[[#PID1:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}}
1919
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
20-
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":7,"offset":[[#]]},"source":"#fooMacro(1)"}}}
20+
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":7,"offset":[[#]]},"source":"#fooMacro(1)"}}}
2121
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"invalidResponse":{}}
22-
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":9,"offset":[[#]]},"source":"#fooMacro(2)"}}}
22+
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":9,"offset":[[#]]},"source":"#fooMacro(2)"}}}
2323
// ^ This messages causes the mock plugin exit because there's no matching expected message.
2424

2525
// CHECK: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}}
2626
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
27-
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":11,"offset":[[#]]},"source":"#fooMacro(3)"}}}
27+
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"{{.+}}test.swift","line":11,"offset":[[#]]},"source":"#fooMacro(3)"}}}
2828
// CHECK-NEXT: <-(plugin:[[#PID2:]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"3.description"}}
2929

3030
//--- test.swift

test/Macros/macro_plugin_server.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@
5050
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
5151
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros.{{dylib|so|dll}}","moduleName":"EvilMacros"}}
5252
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
53-
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(a + b)"}}}
53+
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(a + b)"}}}
5454
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"expandMacroResult":{"diagnostics":[],"expandedSource":"(a + b, \"a + b\")"}}
55-
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#evil(42)"}}}
55+
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#evil(42)"}}}
5656
// ^ This crashes the plugin server.
5757

5858
// CHECK: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}}
@@ -61,12 +61,12 @@
6161
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
6262
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros.{{dylib|so|dll}}","moduleName":"EvilMacros"}}
6363
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
64-
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(b + a)"}}}
64+
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(b + a)"}}}
6565
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"expandMacroResult":{"diagnostics":[],"expandedSource":"(b + a, \"b + a\")"}}
6666

67-
// CHECK-NEXT ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{*}}},"source":" #missing()"}}}
67+
// CHECK-NEXT ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{*}}},"source":" #missing()"}}}
6868
// CHECK-NEXT <-(plugin:[[#PID2]]) {"expandMacroResult":{"diagnostics":[{"fixIts":[],"highlights":[{{{.*}}}],"message":"macro implementation type 'MacroDefinition.TypeDoesNotExist' could not be found in library plugin '{{.*}}MacroDefinition.{{dylib|so|dll}}'","notes":[],"position":{{{.*}}},"severity":"error"}]}}
69-
// CHECK-NEXT ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{*}}},"source":" #notMacro()"}}}
69+
// CHECK-NEXT ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{*}}},"source":" #notMacro()"}}}
7070
// CHECK-NEXT <-(plugin:[[#PID2]]) {"expandMacroResult":{"diagnostics":[{"fixIts":[],"highlights":[{{{.*}}}],"message":"type 'MacroDefinition.NotMacroStruct' is not a valid macro implementation type in library plugin '{{.*}}MacroDefinition.{{dylib|so|dll}}'","notes":[],"position":{{{.*}}},"severity":"error"}]}}
7171

7272
@freestanding(expression) macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")

0 commit comments

Comments
 (0)