Files
swift-mirror/test/Macros/macro_plugin_accessor_syntax_kind.swift
Rintaro Ishizaki fbbbc6b298 [Macros] Don't send Syntax.Kind.accessor to plugins with protocol < 8
`PluginMessage.Syntax.Kind.accessor` was introduced in swift-syntax
protocol version 8. Plugins on an older version don't have this
case in their decoder, so sending it would cause a JSON decode
failure on the plugin side.

Thread `pluginProtocolVersion` (read from the plugin's capability
response) through the two `PluginMessage.Syntax` initialisers in
`PluginHost.swift` and through `pluginLexicalContext(of:)` in
`Macros.swift`. When the plugin's version is less than 8, downgrade
`AccessorDeclSyntax` nodes to `"kind":"declaration"` — safe because
`AccessorDeclSyntax` conforms to `DeclSyntaxProtocol` and the old
plugin will parse it via `DeclSyntax.parse(from:)`.
2026-05-21 10:09:50 -07:00

75 lines
2.4 KiB
Swift

// REQUIRES: swift_swift_parser
// RUN: %empty-directory(%t)
// RUN: split-file %s %t
// RUN: %swift-build-c-plugin -o %t/mock-plugin-v7 %t/plugin-v7.c
// RUN: %swift-build-c-plugin -o %t/mock-plugin-v8 %t/plugin-v8.c
// With protocol version 7 (< 8), AccessorDeclSyntax in the lexical context must
// be sent as "kind":"declaration" (the "accessor" kind is unknown to the plugin).
// RUN: env SWIFT_DUMP_PLUGIN_MESSAGING=1 %target-swift-frontend \
// RUN: -typecheck \
// RUN: -swift-version 5 \
// RUN: -load-plugin-executable %t/mock-plugin-v7#TestPlugin \
// RUN: -module-name MyApp \
// RUN: %t/test.swift \
// RUN: > %t/output-v7.txt 2>&1
// RUN: %FileCheck -check-prefix=CHECK-V7 %s < %t/output-v7.txt
// With protocol version 8, AccessorDeclSyntax in the lexical context must be
// sent as "kind":"accessor".
// RUN: env SWIFT_DUMP_PLUGIN_MESSAGING=1 %target-swift-frontend \
// RUN: -typecheck \
// RUN: -swift-version 5 \
// RUN: -load-plugin-executable %t/mock-plugin-v8#TestPlugin \
// RUN: -module-name MyApp \
// RUN: %t/test.swift \
// RUN: > %t/output-v8.txt 2>&1
// RUN: %FileCheck -check-prefix=CHECK-V8 %s < %t/output-v8.txt
// The accessor is the innermost lexical context, so it's the first element.
// CHECK-V7: "lexicalContext":[{"kind":"declaration",
// CHECK-V7-NOT: "kind":"accessor"
// CHECK-V8: "lexicalContext":[{"kind":"accessor",
//--- test.swift
@freestanding(expression) macro testMacro() -> Int = #externalMacro(module: "TestPlugin", type: "TestMacro")
struct S {
var x: Int {
get { #testMacro() }
}
}
//--- plugin-v7.c
#include "swift-c/MockPlugin/MockPlugin.h"
MOCK_PLUGIN([
{
"expect": {"getCapability": {}},
"response": {"getCapabilityResult": {"capability": {"protocolVersion": 7}}}
},
{
"expect": {"expandFreestandingMacro": {
"macro": {"moduleName": "TestPlugin", "typeName": "TestMacro"}}},
"response": {"expandFreestandingMacroResult": {"expandedSource": "0", "diagnostics": []}}
}
])
//--- plugin-v8.c
#include "swift-c/MockPlugin/MockPlugin.h"
MOCK_PLUGIN([
{
"expect": {"getCapability": {}},
"response": {"getCapabilityResult": {"capability": {"protocolVersion": 8}}}
},
{
"expect": {"expandFreestandingMacro": {
"macro": {"moduleName": "TestPlugin", "typeName": "TestMacro"}}},
"response": {"expandFreestandingMacroResult": {"expandedSource": "0", "diagnostics": []}}
}
])