mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Provide the lexical context to macro expansions
This commit is contained in:
@@ -508,7 +508,8 @@ func expandFreestandingMacroIPC(
|
||||
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
|
||||
macroRole: pluginMacroRole,
|
||||
discriminator: discriminator,
|
||||
syntax: PluginMessage.Syntax(syntax: Syntax(expansionSyntax), in: sourceFilePtr)!
|
||||
syntax: PluginMessage.Syntax(syntax: Syntax(expansionSyntax), in: sourceFilePtr)!,
|
||||
lexicalContext: pluginLexicalContext(of: expansionSyntax)
|
||||
)
|
||||
do {
|
||||
let result = try macro.plugin.sendMessageAndWait(message)
|
||||
@@ -564,6 +565,7 @@ func expandFreestandingMacroInProcess(
|
||||
sourceManager.insert(sourceFilePtr)
|
||||
|
||||
let context = sourceManager.createMacroExpansionContext(
|
||||
lexicalContext: lexicalContext(of: expansionSyntax),
|
||||
discriminator: discriminator
|
||||
)
|
||||
|
||||
@@ -757,6 +759,20 @@ func expandAttachedMacro(
|
||||
)
|
||||
}
|
||||
|
||||
/// Produce the full lexical context of the given node to pass along to
|
||||
/// macro expansion.
|
||||
private func lexicalContext(of node: some SyntaxProtocol) -> [Syntax] {
|
||||
// FIXME: Should we query the source manager to get the macro expansion
|
||||
// information?
|
||||
node.allMacroLexicalContexts()
|
||||
}
|
||||
|
||||
/// Produce the full lexical context of the given node to pass along to
|
||||
/// macro expansion.
|
||||
private func pluginLexicalContext(of node: some SyntaxProtocol) -> [PluginMessage.Syntax] {
|
||||
lexicalContext(of: node).compactMap { .init(syntax: $0) }
|
||||
}
|
||||
|
||||
func expandAttachedMacroIPC(
|
||||
diagEnginePtr: UnsafeMutableRawPointer,
|
||||
macroPtr: UnsafeRawPointer,
|
||||
@@ -829,6 +845,7 @@ func expandAttachedMacroIPC(
|
||||
conformanceListSyntax = .init(syntax: Syntax(placeholderDecl))!
|
||||
}
|
||||
|
||||
|
||||
// Send the message.
|
||||
let message = HostToPluginMessage.expandAttachedMacro(
|
||||
macro: .init(moduleName: macro.moduleName, typeName: macro.typeName, name: macroName),
|
||||
@@ -838,7 +855,8 @@ func expandAttachedMacroIPC(
|
||||
declSyntax: declSyntax,
|
||||
parentDeclSyntax: parentDeclSyntax,
|
||||
extendedTypeSyntax: extendedTypeSyntax,
|
||||
conformanceListSyntax: conformanceListSyntax
|
||||
conformanceListSyntax: conformanceListSyntax,
|
||||
lexicalContext: pluginLexicalContext(of: declarationNode)
|
||||
)
|
||||
do {
|
||||
let expandedSource: String?
|
||||
@@ -926,6 +944,7 @@ func expandAttachedMacroInProcess(
|
||||
|
||||
// Create an expansion context
|
||||
let context = sourceManager.createMacroExpansionContext(
|
||||
lexicalContext: lexicalContext(of: declarationNode),
|
||||
discriminator: discriminator
|
||||
)
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ extension SourceManager {
|
||||
/// The source manager.
|
||||
private let sourceManager: SourceManager
|
||||
|
||||
/// The lexical context for this expansion.
|
||||
let lexicalContext: [Syntax]
|
||||
|
||||
/// The set of diagnostics that were emitted as part of expanding the
|
||||
/// macro.
|
||||
var diagnostics: [Diagnostic] = []
|
||||
@@ -35,18 +38,25 @@ extension SourceManager {
|
||||
/// Used in conjunction with `expansionDiscriminator`.
|
||||
private var uniqueNames: [String: Int] = [:]
|
||||
|
||||
init(sourceManager: SourceManager, discriminator: String) {
|
||||
init(
|
||||
sourceManager: SourceManager,
|
||||
lexicalContext: [Syntax],
|
||||
discriminator: String
|
||||
) {
|
||||
self.sourceManager = sourceManager
|
||||
self.lexicalContext = lexicalContext
|
||||
self.discriminator = discriminator
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new macro expansion context
|
||||
func createMacroExpansionContext(
|
||||
lexicalContext: [Syntax],
|
||||
discriminator: String = ""
|
||||
) -> MacroExpansionContext {
|
||||
return MacroExpansionContext(
|
||||
sourceManager: self,
|
||||
lexicalContext: lexicalContext,
|
||||
discriminator: discriminator
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2316,3 +2316,13 @@ public struct AddSubscript: MemberMacro {
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
public struct AllLexicalContextsMacro: DeclarationMacro {
|
||||
public static func expansion(
|
||||
of node: some FreestandingMacroExpansionSyntax,
|
||||
in context: some MacroExpansionContext
|
||||
) throws -> [DeclSyntax] {
|
||||
context.lexicalContext.compactMap { $0.as(DeclSyntax.self)?.trimmed }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@
|
||||
|
||||
// CHECK: ->(plugin:[[#PID:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}}
|
||||
// CHECK: <-(plugin:[[#PID]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
|
||||
// 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)"}}}
|
||||
// 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)"}}}
|
||||
// CHECK: <-(plugin:[[#PID]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"\"123\"\n + \"foo \""}}
|
||||
// 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)"}}}
|
||||
// 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)"}}}
|
||||
// CHECK: <-(plugin:[[#PID]]) {"expandFreestandingMacroResult":{"diagnostics":[{"fixIts":[],"highlights":[],"message":"message from plugin","notes":[],"position":{"fileName":"{{.*}}test.swift","offset":336},"severity":"error"}],"expandedSource":"\"bar\""}}
|
||||
|
||||
//--- test.swift
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
|
||||
// CHECK: ->(plugin:[[#PID1:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION:]]}}}
|
||||
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
|
||||
// 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)"}}}
|
||||
// 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)"}}}
|
||||
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"invalidResponse":{}}
|
||||
// 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)"}}}
|
||||
// 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)"}}}
|
||||
// ^ This messages causes the mock plugin exit because there's no matching expected message.
|
||||
|
||||
// CHECK: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}}
|
||||
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}}
|
||||
// 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)"}}}
|
||||
// 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)"}}}
|
||||
// CHECK-NEXT: <-(plugin:[[#PID2:]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"3.description"}}
|
||||
|
||||
//--- test.swift
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
|
||||
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros.{{dylib|so|dll}}","moduleName":"EvilMacros"}}
|
||||
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
|
||||
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(a + b)"}}}
|
||||
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(a + b)"}}}
|
||||
// CHECK-NEXT: <-(plugin:[[#PID1]]) {"expandMacroResult":{"diagnostics":[],"expandedSource":"(a + b, \"a + b\")"}}
|
||||
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#evil(42)"}}}
|
||||
// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#evil(42)"}}}
|
||||
// ^ This crashes the plugin server.
|
||||
|
||||
// CHECK: ->(plugin:[[#PID2:]]) {"getCapability":{"capability":{"protocolVersion":[[#PROTOCOL_VERSION]]}}}
|
||||
@@ -61,12 +61,12 @@
|
||||
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
|
||||
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"loadPluginLibrary":{"libraryPath":"{{.*}}EvilMacros.{{dylib|so|dll}}","moduleName":"EvilMacros"}}
|
||||
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}}
|
||||
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(b + a)"}}}
|
||||
// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(b + a)"}}}
|
||||
// CHECK-NEXT: <-(plugin:[[#PID2]]) {"expandMacroResult":{"diagnostics":[],"expandedSource":"(b + a, \"b + a\")"}}
|
||||
|
||||
// CHECK-NEXT ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{*}}},"source":" #missing()"}}}
|
||||
// CHECK-NEXT ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{*}}},"source":" #missing()"}}}
|
||||
// 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"}]}}
|
||||
// CHECK-NEXT ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{*}}},"source":" #notMacro()"}}}
|
||||
// CHECK-NEXT ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","lexicalContext":[{{.*}}],"macro":{"moduleName":"MacroDefinition","name":"missing","typeName":"TypeDoesNotExist"},"macroRole":"expression","syntax":{"kind":"expression","location":{{{*}}},"source":" #notMacro()"}}}
|
||||
// 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"}]}}
|
||||
|
||||
@freestanding(expression) macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")
|
||||
|
||||
Reference in New Issue
Block a user