diff --git a/include/swift/AST/PluginRegistry.h b/include/swift/AST/PluginRegistry.h index b9075947ef27a..13f4d2c8c216b 100644 --- a/include/swift/AST/PluginRegistry.h +++ b/include/swift/AST/PluginRegistry.h @@ -64,6 +64,9 @@ class LoadedExecutablePlugin { /// Callbacks to be called when the connection is restored. llvm::SmallVector *, 0> onReconnect; + /// Flag to dump plugin messagings. + bool dumpMessaging = false; + /// Cleanup function to call ASTGen. std::function cleanup; @@ -121,6 +124,8 @@ class LoadedExecutablePlugin { const void *getCapability() { return capability; }; void setCapability(const void *newValue) { capability = newValue; }; + + void setDumpMessaging(bool flag) { dumpMessaging = flag; } }; class PluginRegistry { @@ -131,7 +136,12 @@ class PluginRegistry { llvm::StringMap> LoadedPluginExecutables; + /// Flag to dump plugin messagings. + bool dumpMessaging = false; + public: + PluginRegistry(); + /// Load a dynamic link library specified by \p path. /// If \p path plugin is already loaded, this returns the cached object. llvm::Expected loadLibraryPlugin(llvm::StringRef path); diff --git a/lib/AST/PluginRegistry.cpp b/lib/AST/PluginRegistry.cpp index 05d9f46d80be3..6f563d6f49e73 100644 --- a/lib/AST/PluginRegistry.cpp +++ b/lib/AST/PluginRegistry.cpp @@ -40,6 +40,10 @@ using namespace swift; +PluginRegistry::PluginRegistry() { + dumpMessaging = ::getenv("SWIFT_DUMP_PLUGIN_MESSAGING") != nullptr; +} + llvm::Expected PluginRegistry::loadLibraryPlugin(StringRef path) { auto found = LoadedPluginLibraries.find(path); if (found != LoadedPluginLibraries.end()) { @@ -94,6 +98,8 @@ PluginRegistry::loadExecutablePlugin(StringRef path) { auto plugin = std::unique_ptr( new LoadedExecutablePlugin(path, stat.getLastModificationTime())); + plugin->setDumpMessaging(dumpMessaging); + // Launch here to see if it's actually executable, and diagnose (by returning // an error) if necessary. if (auto error = plugin->spawnIfNeeded()) { @@ -213,6 +219,10 @@ ssize_t LoadedExecutablePlugin::PluginProcess::write(const void *buf, llvm::Error LoadedExecutablePlugin::sendMessage(llvm::StringRef message) const { ssize_t writtenSize = 0; + if (dumpMessaging) { + llvm::dbgs() << "->(plugin:" << Process->pid << ") " << message << "\n"; + } + const char *data = message.data(); size_t size = message.size(); @@ -269,5 +279,9 @@ llvm::Expected LoadedExecutablePlugin::waitForNextMessage() const { message.append(buffer, readSize); } + if (dumpMessaging) { + llvm::dbgs() << "<-(plugin:" << Process->pid << ") " << message << "\n"; + } + return message; } diff --git a/lib/ASTGen/Sources/ASTGen/PluginHost.swift b/lib/ASTGen/Sources/ASTGen/PluginHost.swift index b703b573a0e9b..bc0747f87813f 100644 --- a/lib/ASTGen/Sources/ASTGen/PluginHost.swift +++ b/lib/ASTGen/Sources/ASTGen/PluginHost.swift @@ -103,10 +103,6 @@ struct CompilerPlugin { private func sendMessage(_ message: HostToPluginMessage) throws { let hadError = try LLVMJSON.encoding(message) { (data) -> Bool in -// // FIXME: Add -dump-plugin-message option? -// data.withMemoryRebound(to: UInt8.self) { buffer in -// print(">> " + String(decoding: buffer, as: UTF8.self)) -// } return Plugin_sendMessage(opaqueHandle, BridgedData(baseAddress: data.baseAddress, size: data.count)) } if hadError { @@ -122,10 +118,6 @@ struct CompilerPlugin { throw PluginError.failedToReceiveMessage } let data = UnsafeBufferPointer(start: result.baseAddress, count: result.size) -// // FIXME: Add -dump-plugin-message option? -// data.withMemoryRebound(to: UInt8.self) { buffer in -// print("<< " + String(decoding: buffer, as: UTF8.self)) -// } return try LLVMJSON.decode(PluginToHostMessage.self, from: data) } diff --git a/test/Macros/macro_plugin_basic.swift b/test/Macros/macro_plugin_basic.swift index 81078aee2d74c..b8516e9661cc8 100644 --- a/test/Macros/macro_plugin_basic.swift +++ b/test/Macros/macro_plugin_basic.swift @@ -11,16 +11,23 @@ // RUN: -o %t/mock-plugin \ // RUN: %t/plugin.c -// RUN: %swift-target-frontend \ +// RUN: SWIFT_DUMP_PLUGIN_MESSAGING=1 %swift-target-frontend \ // RUN: -typecheck -verify \ // RUN: -swift-version 5 \ // RUN: -load-plugin-executable %t/mock-plugin#TestPlugin \ -// RUN: -dump-macro-expansions \ +// RUN: -module-name MyApp \ // RUN: %t/test.swift \ // RUN: 2>&1 | tee %t/macro-expansions.txt // RUN: %FileCheck -strict-whitespace %s < %t/macro-expansions.txt +// CHECK: ->(plugin:[[#PID:]]) {"getCapability":{}} +// CHECK: <-(plugin:[[#PID]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}} +// CHECK: ->(plugin:[[#PID]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"testString","typeName":"TestStringMacro"},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"BUILD_DIR{{.+}}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"},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"BUILD_DIR{{.+}}test.swift","line":6,"offset":336},"source":"#testStringWithError(321)"}}} +// CHECK: <-(plugin:[[#PID]]) {"expandFreestandingMacroResult":{"diagnostics":[{"fixIts":[],"highlights":[],"message":"message from plugin","notes":[],"position":{"fileName":"BUILD_DIR{{.*}}test.swift","offset":336},"severity":"error"}],"expandedSource":"\"bar\""}} + //--- test.swift @freestanding(expression) macro testString(_: Any) -> String = #externalMacro(module: "TestPlugin", type: "TestStringMacro") @freestanding(expression) macro testStringWithError(_: Any) -> String = #externalMacro(module: "TestPlugin", type: "TestStringWithErrorMacro") @@ -31,15 +38,6 @@ func test() { // expected-error @-1 {{message from plugin}} } -// CHECK: ------------------------------ -// CHECK-NEXT: {{^}}"123" -// CHECK-NEXT: {{^}} + "foo " -// CHECK-NEXT: ------------------------------ - -// CHECK: ------------------------------ -// CHECK-NEXT: {{^}}"bar" -// CHECK-NEXT: ------------------------------ - //--- plugin.c #include "swift-c/MockPlugin/MockPlugin.h" diff --git a/test/Macros/macro_plugin_error.swift b/test/Macros/macro_plugin_error.swift index 4ccbebd2da2d2..902c5ef7ae6f4 100644 --- a/test/Macros/macro_plugin_error.swift +++ b/test/Macros/macro_plugin_error.swift @@ -11,12 +11,25 @@ // RUN: -o %t/mock-plugin \ // RUN: %t/plugin.c -// RUN: %swift-target-frontend \ +// RUN: SWIFT_DUMP_PLUGIN_MESSAGING=1 %swift-target-frontend \ // RUN: -typecheck -verify \ // RUN: -swift-version 5 -enable-experimental-feature Macros \ // RUN: -load-plugin-executable %t/mock-plugin#TestPlugin \ -// RUN: -dump-macro-expansions \ -// RUN: %t/test.swift +// RUN: -module-name MyApp \ +// RUN: %t/test.swift \ +// RUN: 2>&1 | tee %t/macro-expansions.txt + +// RUN: %FileCheck -strict-whitespace %s < %t/macro-expansions.txt + +// CHECK: ->(plugin:[[#PID1:]]) {"getCapability":{}} +// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"protocolVersion":1}}} +// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"BUILD_DIR{{.+}}test.swift","line":6,"offset":200},"source":"#fooMacro(1)"}}} +// CHECK-NEXT: <-(plugin:[[#PID1]]) {"invalidResponse":{}} +// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"BUILD_DIR{{.+}}test.swift","line":8,"offset":304},"source":"#fooMacro(2)"}}} +// ^ This messages causes the mock plugin exit because there's no matching expected message. + +// CHECK: ->(plugin:[[#PID2:]]) {"expandFreestandingMacro":{"discriminator":"$s{{.+}}","macro":{"moduleName":"TestPlugin","name":"fooMacro","typeName":"FooMacro"},"syntax":{"kind":"expression","location":{"column":19,"fileID":"MyApp/test.swift","fileName":"BUILD_DIR{{.+}}test.swift","line":10,"offset":386},"source":"#fooMacro(3)"}}} +// CHECK-NEXT: <-(plugin:[[#PID2:]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"3.description"}} //--- test.swift @freestanding(expression) macro fooMacro(_: Any) -> String = #externalMacro(module: "TestPlugin", type: "FooMacro") diff --git a/test/Macros/macro_plugin_server.swift b/test/Macros/macro_plugin_server.swift index aa49e1bdfcac9..301550e154579 100644 --- a/test/Macros/macro_plugin_server.swift +++ b/test/Macros/macro_plugin_server.swift @@ -25,16 +25,33 @@ // RUN: %S/Inputs/evil_macro_definitions.swift \ // RUN: -g -no-toolchain-stdlib-rpath -// RUN: %swift-target-frontend \ +// RUN: SWIFT_DUMP_PLUGIN_MESSAGING=1 %swift-target-frontend \ // RUN: -typecheck -verify \ -// RUN: -swift-version 5 \ +// RUN: -swift-version 5 -enable-experimental-feature Macros \ // RUN: -external-plugin-path %t/plugins#%swift-plugin-server \ -// RUN: -dump-macro-expansions \ +// RUN: -module-name MyApp \ // RUN: %s \ // RUN: 2>&1 | tee %t/macro-expansions.txt // RUN: %FileCheck -strict-whitespace %s < %t/macro-expansions.txt +// CHECK: ->(plugin:[[#PID1:]]) {"getCapability":{}} +// CHECK-NEXT: <-(plugin:[[#PID1]]) {"getCapabilityResult":{"capability":{"features":["load-plugin-library"],"protocolVersion":4}}} +// CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"BUILD_DIR{{.*}}plugins/libMacroDefinition.dylib","moduleName":"MacroDefinition"}} +// CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}} +// CHECK-NEXT: ->(plugin:[[#PID1]]) {"loadPluginLibrary":{"libraryPath":"BUILD_DIR{{.*}}plugins/libEvilMacros.dylib","moduleName":"EvilMacros"}} +// CHECK-NEXT: <-(plugin:[[#PID1]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}} +// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(a + b)"}}} +// CHECK-NEXT: <-(plugin:[[#PID1]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"(a + b, \"a + b\")"}} +// CHECK-NEXT: ->(plugin:[[#PID1]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"EvilMacros","name":"evil","typeName":"CrashingMacro"},"syntax":{"kind":"expression","location":{{{.+}}},"source":"#evil(42)"}}} +// ^ This crashes the plugin server. + +// CHECK-NEXT: ->(plugin:[[#PID2:]]) {"loadPluginLibrary":{"libraryPath":"BUILD_DIR{{.*}}plugins/libMacroDefinition.dylib","moduleName":"MacroDefinition"}} +// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}} +// CHECK-NEXT: ->(plugin:[[#PID2]]) {"loadPluginLibrary":{"libraryPath":"BUILD_DIR{{.*}}plugins/libEvilMacros.dylib","moduleName":"EvilMacros"}} +// CHECK-NEXT: <-(plugin:[[#PID2]]) {"loadPluginLibraryResult":{"diagnostics":[],"loaded":true}} +// CHECK-NEXT: ->(plugin:[[#PID2]]) {"expandFreestandingMacro":{"discriminator":"${{.*}}","macro":{"moduleName":"MacroDefinition","name":"stringify","typeName":"StringifyMacro"},"syntax":{"kind":"expression","location":{{{.+}}},"source":"#stringify(b + a)"}}} +// CHECK-NEXT: <-(plugin:[[#PID2]]) {"expandFreestandingMacroResult":{"diagnostics":[],"expandedSource":"(b + a, \"b + a\")"}} @freestanding(expression) macro stringify(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro") @freestanding(expression) macro evil(_ value: Int) -> String = #externalMacro(module: "EvilMacros", type: "CrashingMacro") @@ -43,17 +60,10 @@ func testStringify(a: Int, b: Int) { let s1: String = #stringify(a + b).1 print(s1) - let s2: String = #evil(42) // expected-error {{failedToReceiveMessage (from macro 'evil')}} + // expected-error @+1 {{failedToReceiveMessage (from macro 'evil')}} + let s2: String = #evil(42) print(s2) let s3: String = #stringify(b + a).1 print(s3) } - -// CHECK: {{^}}------------------------------ -// CHECK-NEXT: {{^}}(a + b, "a + b") -// CHECK-NEXT: {{^}}------------------------------ - -// CHECK: {{^}}------------------------------ -// CHECK-NEXT: {{^}}(b + a, "b + a") -// CHECK-NEXT: {{^}}------------------------------