From 9dbe6b03c078ca111c7766eb9b15a9571635e72b Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Mon, 27 Mar 2023 16:56:25 -0700 Subject: [PATCH 1/4] [Macros] PluginRegistry vends 'LoadedLibraryPlugin' instead of 'void *' `LoadedLibraryPlugin` is currently just a wrapper of `void` pointer from `dlopen`. This will be convenient for abstracting platform specific dynamic linrary handling. (cherry picked from commit f99d70d18152b77472b4967047a355fa507e3b76) --- include/swift/AST/ASTContext.h | 3 ++- include/swift/AST/PluginRegistry.h | 19 ++++++++++++-- include/swift/AST/TypeCheckRequests.h | 9 ++++--- lib/AST/ASTContext.cpp | 2 +- lib/AST/PluginRegistry.cpp | 25 +++++++++++++----- lib/Sema/TypeCheckMacros.cpp | 37 ++++++++------------------- 6 files changed, 55 insertions(+), 40 deletions(-) diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 237be274497bb..1f790833aae83 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -80,6 +80,7 @@ namespace swift { class ExtensionDecl; struct ExternalSourceLocs; class LoadedExecutablePlugin; + class LoadedLibraryPlugin; class ForeignRepresentationInfo; class FuncDecl; class GenericContext; @@ -1487,7 +1488,7 @@ class ASTContext final { /// returns a nullptr. /// NOTE: This method is idempotent. If the plugin is already loaded, the same /// instance is simply returned. - void *loadLibraryPlugin(StringRef path); + LoadedLibraryPlugin *loadLibraryPlugin(StringRef path); /// Lookup an executable plugin that is declared to handle \p moduleName /// module by '-load-plugin-executable'. diff --git a/include/swift/AST/PluginRegistry.h b/include/swift/AST/PluginRegistry.h index ee38e6294fd16..a32cfe9cb0250 100644 --- a/include/swift/AST/PluginRegistry.h +++ b/include/swift/AST/PluginRegistry.h @@ -22,6 +22,21 @@ namespace swift { +/// Represent a 'dlopen'ed plugin library. +class LoadedLibraryPlugin { + // Opaque handle used to interface with OS-specific dynamic library. + void *handle; + + /// Cache of loaded symbols. + llvm::StringMap resolvedSymbols; + +public: + LoadedLibraryPlugin(void *handle) : handle(handle) {} + + /// Finds the address of the given symbol within the library. + void *getAddressOfSymbol(const char *symbolName); +}; + /// Represent a "resolved" exectuable plugin. /// /// Plugin clients usually deal with this object to communicate with the actual @@ -130,7 +145,7 @@ class LoadedExecutablePlugin { class PluginRegistry { /// Record of loaded plugin library modules. - llvm::StringMap LoadedPluginLibraries; + llvm::StringMap> LoadedPluginLibraries; /// Record of loaded plugin executables. llvm::StringMap> @@ -146,7 +161,7 @@ class 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); + llvm::Expected loadLibraryPlugin(llvm::StringRef path); /// Load an executable plugin specified by \p path . /// If \p path plugin is already loaded, this returns the cached object. diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index ade29a2bb6d6a..e800fafface7f 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -50,6 +50,7 @@ class ClosureExpr; class GenericParamList; class LabeledStmt; class LoadedExecutablePlugin; +class LoadedLibraryPlugin; class MacroDefinition; class PrecedenceGroupDecl; class PropertyWrapperInitializerInfo; @@ -4036,15 +4037,17 @@ class LoadedCompilerPlugin { public: LoadedCompilerPlugin(std::nullptr_t) : kind(PluginKind::None), ptr(nullptr) {} - static LoadedCompilerPlugin inProcess(void *ptr) { + static LoadedCompilerPlugin inProcess(LoadedLibraryPlugin *ptr) { return {PluginKind::InProcess, ptr}; } static LoadedCompilerPlugin executable(LoadedExecutablePlugin *ptr) { return {PluginKind::Executable, ptr}; } - void *getAsInProcessPlugin() const { - return kind == PluginKind::InProcess ? ptr : nullptr; + LoadedLibraryPlugin *getAsInProcessPlugin() const { + return kind == PluginKind::InProcess + ? static_cast(ptr) + : nullptr; } LoadedExecutablePlugin *getAsExecutablePlugin() const { return kind == PluginKind::Executable diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f9b5b4bb72e16..c668b496fb9de 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -6403,7 +6403,7 @@ LoadedExecutablePlugin *ASTContext::loadExecutablePlugin(StringRef path) { return plugin.get(); } -void *ASTContext::loadLibraryPlugin(StringRef path) { +LoadedLibraryPlugin *ASTContext::loadLibraryPlugin(StringRef path) { // Remember the path (even if it fails to load.) getImpl().LoadedPluginLibraryPaths.insert(path); diff --git a/lib/AST/PluginRegistry.cpp b/lib/AST/PluginRegistry.cpp index a9584fb79a8ec..8aad0779230de 100644 --- a/lib/AST/PluginRegistry.cpp +++ b/lib/AST/PluginRegistry.cpp @@ -44,13 +44,15 @@ PluginRegistry::PluginRegistry() { dumpMessaging = ::getenv("SWIFT_DUMP_PLUGIN_MESSAGING") != nullptr; } -llvm::Expected PluginRegistry::loadLibraryPlugin(StringRef path) { +llvm::Expected +PluginRegistry::loadLibraryPlugin(StringRef path) { std::lock_guard lock(mtx); - auto found = LoadedPluginLibraries.find(path); - if (found != LoadedPluginLibraries.end()) { + auto &storage = LoadedPluginLibraries[path]; + if (storage) { // Already loaded. - return found->second; + return storage.get(); } + void *lib = nullptr; #if defined(_WIN32) lib = LoadLibraryA(path.str().c_str()); @@ -64,8 +66,19 @@ llvm::Expected PluginRegistry::loadLibraryPlugin(StringRef path) { return llvm::createStringError(llvm::inconvertibleErrorCode(), dlerror()); } #endif - LoadedPluginLibraries.insert({path, lib}); - return lib; + + storage = std::unique_ptr(new LoadedLibraryPlugin(lib)); + return storage.get(); +} + +void *LoadedLibraryPlugin::getAddressOfSymbol(const char *symbolName) { + auto &cached = resolvedSymbols[symbolName]; + if (cached) + return cached; +#if !defined(_WIN32) + cached = dlsym(handle, symbolName); +#endif + return cached; } llvm::Expected diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 046979c0def62..93cb807c6e0f2 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -38,14 +38,6 @@ #include "swift/Subsystems.h" #include "llvm/Config/config.h" -#if defined(_WIN32) -#define WIN32_LEAN_AND_MEAN -#define NOMINMAX -#include -#else -#include -#endif - using namespace swift; extern "C" void *swift_ASTGen_resolveMacroType(const void *macroType); @@ -90,10 +82,10 @@ extern "C" bool swift_ASTGen_pluginServerLoadLibraryPlugin( #if SWIFT_SWIFT_PARSER /// Look for macro's type metadata given its external module and type name. -static void const *lookupMacroTypeMetadataByExternalName( - ASTContext &ctx, StringRef moduleName, StringRef typeName, - void *libraryHint = nullptr -) { +static void const * +lookupMacroTypeMetadataByExternalName(ASTContext &ctx, StringRef moduleName, + StringRef typeName, + LoadedLibraryPlugin *plugin) { // Look up the type metadata accessor as a struct, enum, or class. const Demangle::Node::Kind typeKinds[] = { Demangle::Node::Kind::Structure, @@ -105,11 +97,7 @@ static void const *lookupMacroTypeMetadataByExternalName( for (auto typeKind : typeKinds) { auto symbolName = Demangle::mangledNameForTypeMetadataAccessor( moduleName, typeName, typeKind); -#if !defined(_WIN32) - /// FIXME: 'PluginRegistry' should vend a wrapper object of the library - /// handle (like llvm::sys::DynamicLibrary) and dlsym should be abstracted. - accessorAddr = dlsym(libraryHint, symbolName.c_str()); -#endif + accessorAddr = plugin->getAddressOfSymbol(symbolName.c_str()); if (accessorAddr) break; } @@ -276,7 +264,8 @@ MacroDefinition MacroDefinitionRequest::evaluate( } /// Load a plugin library based on a module name. -static void *loadLibraryPluginByName(ASTContext &ctx, Identifier moduleName) { +static LoadedLibraryPlugin *loadLibraryPluginByName(ASTContext &ctx, + Identifier moduleName) { std::string libraryPath; if (auto found = ctx.lookupLibraryPluginByModuleName(moduleName)) { libraryPath = *found; @@ -367,10 +356,6 @@ loadExecutablePluginByName(ASTContext &ctx, Identifier moduleName) { LoadedCompilerPlugin CompilerPluginLoadRequest::evaluate(Evaluator &evaluator, ASTContext *ctx, Identifier moduleName) const { - auto fs = ctx->SourceMgr.getFileSystem(); - auto &searchPathOpts = ctx->SearchPathOpts; - auto *registry = ctx->getPluginRegistry(); - // Check dynamic link library plugins. // i.e. '-plugin-path', and '-load-plugin-library'. if (auto found = loadLibraryPluginByName(*ctx, moduleName)) @@ -386,14 +371,12 @@ CompilerPluginLoadRequest::evaluate(Evaluator &evaluator, ASTContext *ctx, } static Optional -resolveInProcessMacro( - ASTContext &ctx, Identifier moduleName, Identifier typeName, - void *libraryHint = nullptr -) { +resolveInProcessMacro(ASTContext &ctx, Identifier moduleName, + Identifier typeName, LoadedLibraryPlugin *plugin) { #if SWIFT_SWIFT_PARSER /// Look for the type metadata given the external module and type names. auto macroMetatype = lookupMacroTypeMetadataByExternalName( - ctx, moduleName.str(), typeName.str(), libraryHint); + ctx, moduleName.str(), typeName.str(), plugin); if (macroMetatype) { // Check whether the macro metatype is in-process. if (auto inProcess = swift_ASTGen_resolveMacroType(macroMetatype)) { From 99e15317a73946cbfe46e94e81b656a0e8cb076c Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Sat, 1 Apr 2023 22:10:59 -0700 Subject: [PATCH 2/4] [Macros] Make 'LoadedCompilerPlugin' a wrapper of PointerUnion (cherry picked from commit ace080c9f34b682de85a9e4532417e3625a043da) --- include/swift/AST/PluginRegistry.h | 4 +++ include/swift/AST/TypeCheckRequests.h | 40 ++++++--------------------- lib/Sema/TypeCheckMacros.cpp | 9 +++--- 3 files changed, 18 insertions(+), 35 deletions(-) diff --git a/include/swift/AST/PluginRegistry.h b/include/swift/AST/PluginRegistry.h index a32cfe9cb0250..812dadbb30eb0 100644 --- a/include/swift/AST/PluginRegistry.h +++ b/include/swift/AST/PluginRegistry.h @@ -9,6 +9,8 @@ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// +#ifndef SWIFT_PLUGIN_REGISTRY_H +#define SWIFT_PLUGIN_REGISTRY_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" @@ -170,3 +172,5 @@ class PluginRegistry { }; } // namespace swift + +#endif // SWIFT_PLUGIN_REGISTRY_H diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index e800fafface7f..9af3087c160c0 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -26,6 +26,7 @@ #include "swift/AST/Type.h" #include "swift/AST/Evaluator.h" #include "swift/AST/Pattern.h" +#include "swift/AST/PluginRegistry.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/SimpleRequest.h" #include "swift/AST/SourceFile.h" @@ -49,8 +50,6 @@ struct ExternalMacroDefinition; class ClosureExpr; class GenericParamList; class LabeledStmt; -class LoadedExecutablePlugin; -class LoadedLibraryPlugin; class MacroDefinition; class PrecedenceGroupDecl; class PropertyWrapperInitializerInfo; @@ -4018,41 +4017,20 @@ class ExpandSynthesizedMemberMacroRequest void noteCycleStep(DiagnosticEngine &diags) const; }; -/// Load a plugin module with the given name. -/// -/// +/// Represent a loaded plugin either an in-process library or an executable. class LoadedCompilerPlugin { - enum class PluginKind : uint8_t { - None, - InProcess, - Executable, - }; - PluginKind kind; - void *ptr; - - LoadedCompilerPlugin(PluginKind kind, void *ptr) : kind(kind), ptr(ptr) { - assert(ptr != nullptr || kind == PluginKind::None); - } + llvm::PointerUnion ptr; public: - LoadedCompilerPlugin(std::nullptr_t) : kind(PluginKind::None), ptr(nullptr) {} - - static LoadedCompilerPlugin inProcess(LoadedLibraryPlugin *ptr) { - return {PluginKind::InProcess, ptr}; - } - static LoadedCompilerPlugin executable(LoadedExecutablePlugin *ptr) { - return {PluginKind::Executable, ptr}; - } + LoadedCompilerPlugin(std::nullptr_t) : ptr(nullptr) {} + LoadedCompilerPlugin(LoadedLibraryPlugin *ptr) : ptr(ptr){}; + LoadedCompilerPlugin(LoadedExecutablePlugin *ptr) : ptr(ptr){}; - LoadedLibraryPlugin *getAsInProcessPlugin() const { - return kind == PluginKind::InProcess - ? static_cast(ptr) - : nullptr; + LoadedLibraryPlugin *getAsLibraryPlugin() const { + return ptr.dyn_cast(); } LoadedExecutablePlugin *getAsExecutablePlugin() const { - return kind == PluginKind::Executable - ? static_cast(ptr) - : nullptr; + return ptr.dyn_cast(); } }; diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 93cb807c6e0f2..dc2451aed9057 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -358,13 +358,14 @@ CompilerPluginLoadRequest::evaluate(Evaluator &evaluator, ASTContext *ctx, Identifier moduleName) const { // Check dynamic link library plugins. // i.e. '-plugin-path', and '-load-plugin-library'. - if (auto found = loadLibraryPluginByName(*ctx, moduleName)) - return LoadedCompilerPlugin::inProcess(found); + if (auto found = loadLibraryPluginByName(*ctx, moduleName)) { + return found; + } // Fall back to executable plugins. // i.e. '-external-plugin-path', and '-load-plugin-executable'. if (auto *found = loadExecutablePluginByName(*ctx, moduleName)) { - return LoadedCompilerPlugin::executable(found); + return found; } return nullptr; @@ -421,7 +422,7 @@ ExternalMacroDefinitionRequest::evaluate(Evaluator &evaluator, ASTContext *ctx, LoadedCompilerPlugin loaded = evaluateOrDefault(evaluator, loadRequest, nullptr); - if (auto loadedLibrary = loaded.getAsInProcessPlugin()) { + if (auto loadedLibrary = loaded.getAsLibraryPlugin()) { if (auto inProcess = resolveInProcessMacro( *ctx, moduleName, typeName, loadedLibrary)) return *inProcess; From f256b28d65ce01a22888d42b85682ddce69974a3 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 11 Apr 2023 15:01:53 -0700 Subject: [PATCH 3/4] Use make_unique (cherry picked from commit 90e15583415cc39420427c14258d3c9539af2b9b) --- lib/AST/PluginRegistry.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/AST/PluginRegistry.cpp b/lib/AST/PluginRegistry.cpp index 8aad0779230de..49702980577b3 100644 --- a/lib/AST/PluginRegistry.cpp +++ b/lib/AST/PluginRegistry.cpp @@ -67,7 +67,7 @@ PluginRegistry::loadLibraryPlugin(StringRef path) { } #endif - storage = std::unique_ptr(new LoadedLibraryPlugin(lib)); + storage = std::make_unique(lib); return storage.get(); } @@ -111,8 +111,8 @@ PluginRegistry::loadExecutablePlugin(StringRef path) { "not executable"); } - auto plugin = std::unique_ptr( - new LoadedExecutablePlugin(path, stat.getLastModificationTime())); + auto plugin = std::make_unique( + path, stat.getLastModificationTime()); plugin->setDumpMessaging(dumpMessaging); @@ -153,9 +153,9 @@ llvm::Error LoadedExecutablePlugin::spawnIfNeeded() { return llvm::errorCodeToError(childInfo.getError()); } - Process = std::unique_ptr( - new PluginProcess(childInfo->Pid, childInfo->ReadFileDescriptor, - childInfo->WriteFileDescriptor)); + Process = std::make_unique(childInfo->Pid, + childInfo->ReadFileDescriptor, + childInfo->WriteFileDescriptor); // Call "on reconnect" callbacks. for (auto *callback : onReconnect) { From 0a1d14a0c688d63d7a2831bf6fe168d7804983d5 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 18 Apr 2023 11:43:36 -0700 Subject: [PATCH 4/4] [Macros] Track plugin dependencies * Factor out ASTContext plugin loading to newly introduced 'PluginLoader' * Insert 'DependencyTracker' to 'PluginLoader' * Add dependencies right before loading the plugins rdar://104938481 (cherry picked from commit a551c01d6abc68e57549a557b89eb531074d6d28) --- include/swift/AST/ASTContext.h | 19 +-- include/swift/AST/PluginLoader.h | 91 ++++++++++ include/swift/Frontend/Frontend.h | 1 + lib/AST/ASTContext.cpp | 160 +++--------------- lib/AST/CMakeLists.txt | 1 + lib/AST/PluginLoader.cpp | 150 ++++++++++++++++ lib/Frontend/Frontend.cpp | 16 +- lib/FrontendTool/LoadedModuleTrace.cpp | 4 - lib/IDETool/CompileInstance.cpp | 3 +- lib/IDETool/IDEInspectionInstance.cpp | 3 +- test/Driver/loaded_module_trace.swift | 3 + test/Macros/macro_swiftdeps.swift | 125 ++++++++++++++ .../lib/SwiftLang/SwiftASTManager.cpp | 4 +- 13 files changed, 420 insertions(+), 160 deletions(-) create mode 100644 include/swift/AST/PluginLoader.h create mode 100644 lib/AST/PluginLoader.cpp create mode 100644 test/Macros/macro_swiftdeps.swift diff --git a/include/swift/AST/ASTContext.h b/include/swift/AST/ASTContext.h index 1f790833aae83..fc1f3eeacbedc 100644 --- a/include/swift/AST/ASTContext.h +++ b/include/swift/AST/ASTContext.h @@ -93,7 +93,7 @@ namespace swift { class ModuleDependencyInfo; class PatternBindingDecl; class PatternBindingInitializer; - class PluginRegistry; + class PluginLoader; class SourceFile; class SourceLoc; class Type; @@ -1477,6 +1477,12 @@ class ASTContext final { Type getNamedSwiftType(ModuleDecl *module, StringRef name); + /// Set the plugin loader. + void setPluginLoader(std::unique_ptr loader); + + /// Get the plugin loader. + PluginLoader &getPluginLoader(); + /// Lookup a library plugin that can handle \p moduleName and return the path /// to it. /// The path is valid within the VFS, use `FS.getRealPath()` for the @@ -1510,15 +1516,6 @@ class ASTContext final { /// instance is simply returned. LoadedExecutablePlugin *loadExecutablePlugin(StringRef path); - /// Get the plugin registry this ASTContext is using. - PluginRegistry *getPluginRegistry() const; - - /// Set the plugin registory this ASTContext should use. - /// This should be called before any plugin is loaded. - void setPluginRegistry(PluginRegistry *newValue); - - const llvm::StringSet<> &getLoadedPluginLibraryPaths() const; - private: friend Decl; @@ -1531,8 +1528,6 @@ class ASTContext final { Optional getBriefComment(const Decl *D); void setBriefComment(const Decl *D, StringRef Comment); - void createModuleToExecutablePluginMap(); - friend TypeBase; friend ArchetypeType; friend OpaqueTypeDecl; diff --git a/include/swift/AST/PluginLoader.h b/include/swift/AST/PluginLoader.h new file mode 100644 index 0000000000000..0ded337c72af6 --- /dev/null +++ b/include/swift/AST/PluginLoader.h @@ -0,0 +1,91 @@ +//===--- PluginLoader.h -----------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +#ifndef SWIFT_AST_PLUGIN_LOADER_H +#define SWIFT_AST_PLUGIN_LOADER_H + +#include "swift/AST/ModuleLoader.h" +#include "swift/AST/PluginRegistry.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +namespace swift { + +class ASTContext; + +/// Compiler plugin loader tied to an ASTContext. This is responsible for: +/// * Find plugins based on the module name +/// * Load plugins resolving VFS paths +/// * Track plugin dependencies +class PluginLoader { + /// Plugin registry. Lazily populated by get/setRegistry(). + /// NOTE: Do not reference this directly. Use getRegistry(). + PluginRegistry *Registry = nullptr; + + /// `Registry` storage if this owns it. + std::unique_ptr OwnedRegistry = nullptr; + + ASTContext &Ctx; + DependencyTracker *DepTracker; + + /// Map a module name to an executable plugin path that provides the module. + llvm::DenseMap ExecutablePluginPaths; + + void createModuleToExecutablePluginMap(); + +public: + PluginLoader(ASTContext &Ctx, DependencyTracker *DepTracker) + : Ctx(Ctx), DepTracker(DepTracker) { + createModuleToExecutablePluginMap(); + } + + void setRegistry(PluginRegistry *newValue); + PluginRegistry *getRegistry(); + + /// Lookup a library plugin that can handle \p moduleName and return the path + /// to it from `-plugin-path` or `-load-plugin-library`. + /// The path returned can be loaded by 'loadLibraryPlugin' method. + llvm::Optional + lookupLibraryPluginByModuleName(Identifier moduleName); + + /// Lookup an executable plugin that is declared to handle \p moduleName + /// module by '-load-plugin-executable'. + /// The path returned can be loaded by 'loadExecutablePlugin' method. + llvm::Optional + lookupExecutablePluginByModuleName(Identifier moduleName); + + /// Look for dynamic libraries in paths from `-external-plugin-path` and + /// return a pair of `(library path, plugin server executable)` if found. + /// These paths are valid within the VFS, use `FS.getRealPath()` for their + /// underlying path. + llvm::Optional> + lookupExternalLibraryPluginByModuleName(Identifier moduleName); + + /// Load the specified dylib plugin path resolving the path with the + /// current VFS. If it fails to load the plugin, a diagnostic is emitted, and + /// returns a nullptr. + /// NOTE: This method is idempotent. If the plugin is already loaded, the same + /// instance is simply returned. + LoadedLibraryPlugin *loadLibraryPlugin(llvm::StringRef path); + + /// Launch the specified executable plugin path resolving the path with the + /// current VFS. If it fails to load the plugin, a diagnostic is emitted, and + /// returns a nullptr. + /// NOTE: This method is idempotent. If the plugin is already loaded, the same + /// instance is simply returned. + LoadedExecutablePlugin *loadExecutablePlugin(llvm::StringRef path); +}; + +} // namespace swift + +#endif // SWIFT_AST_PLUGIN_LOADER_H diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 30785440fa5fe..796317eeb804f 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -625,6 +625,7 @@ class CompilerInstance { void setUpLLVMArguments(); void setUpDiagnosticOptions(); bool setUpModuleLoaders(); + bool setUpPluginLoader(); bool setUpInputs(); bool setUpASTContextIfNeeded(); void setupStatsReporter(); diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c668b496fb9de..1c020839bcea3 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -41,7 +41,7 @@ #include "swift/AST/NameLookup.h" #include "swift/AST/PackConformance.h" #include "swift/AST/ParameterList.h" -#include "swift/AST/PluginRegistry.h" +#include "swift/AST/PluginLoader.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" @@ -67,7 +67,6 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Config/config.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" @@ -524,17 +523,8 @@ struct ASTContext::Implementation { llvm::StringMap> SearchPathsSet; - /// Plugin registry. Lazily populated by get/setPluginRegistry(). - /// NOTE: Do not reference this directly. Use ASTContext::getPluginRegistry(). - PluginRegistry *Plugins = nullptr; - - /// `Plugins` storage if this ASTContext owns it. - std::unique_ptr OwnedPluginRegistry = nullptr; - - /// Map a module name to an executable plugin path that provides the module. - llvm::DenseMap ExecutablePluginPaths; - - llvm::StringSet<> LoadedPluginLibraryPaths; + /// Plugin loader. + std::unique_ptr Plugins; /// The permanent arena. Arena Permanent; @@ -705,8 +695,6 @@ ASTContext::ASTContext( // Register any request-evaluator functions available at the AST layer. registerAccessRequestFunctions(evaluator); registerNameLookupRequestFunctions(evaluator); - - createModuleToExecutablePluginMap(); } ASTContext::~ASTContext() { @@ -6266,34 +6254,33 @@ BuiltinTupleType *ASTContext::getBuiltinTupleType() { return result; } -void ASTContext::setPluginRegistry(PluginRegistry *newValue) { - assert(getImpl().Plugins == nullptr && - "Too late to set a new plugin registry"); - getImpl().Plugins = newValue; +void ASTContext::setPluginLoader(std::unique_ptr loader) { + getImpl().Plugins = std::move(loader); } -PluginRegistry *ASTContext::getPluginRegistry() const { - PluginRegistry *®istry = getImpl().Plugins; +PluginLoader &ASTContext::getPluginLoader() { return *getImpl().Plugins; } - // Create a new one if it hasn't been set. - if (!registry) { - registry = new PluginRegistry(); - getImpl().OwnedPluginRegistry.reset(registry); - } +Optional +ASTContext::lookupLibraryPluginByModuleName(Identifier moduleName) { + return getImpl().Plugins->lookupLibraryPluginByModuleName(moduleName); +} - assert(registry != nullptr); - return registry; +Optional +ASTContext::lookupExecutablePluginByModuleName(Identifier moduleName) { + return getImpl().Plugins->lookupExecutablePluginByModuleName(moduleName); } -void ASTContext::createModuleToExecutablePluginMap() { - for (auto &arg : SearchPathOpts.getCompilerPluginExecutablePaths()) { - // Create a moduleName -> pluginPath mapping. - assert(!arg.ExecutablePath.empty() && "empty plugin path"); - auto pathStr = AllocateCopy(arg.ExecutablePath); - for (auto moduleName : arg.ModuleNames) { - getImpl().ExecutablePluginPaths[getIdentifier(moduleName)] = pathStr; - } - } +Optional> +ASTContext::lookupExternalLibraryPluginByModuleName(Identifier moduleName) { + return getImpl().Plugins->lookupExternalLibraryPluginByModuleName(moduleName); +} + +LoadedLibraryPlugin *ASTContext::loadLibraryPlugin(StringRef path) { + return getImpl().Plugins->loadLibraryPlugin(path); +} + +LoadedExecutablePlugin *ASTContext::loadExecutablePlugin(StringRef path) { + return getImpl().Plugins->loadExecutablePlugin(path); } Type ASTContext::getNamedSwiftType(ModuleDecl *module, StringRef name) { @@ -6331,105 +6318,6 @@ Type ASTContext::getNamedSwiftType(ModuleDecl *module, StringRef name) { return decl->getDeclaredInterfaceType(); } -Optional -ASTContext::lookupLibraryPluginByModuleName(Identifier moduleName) { - auto fs = SourceMgr.getFileSystem(); - - // Look for 'lib${module name}(.dylib|.so)'. - SmallString<64> expectedBasename; - expectedBasename.append("lib"); - expectedBasename.append(moduleName.str()); - expectedBasename.append(LTDL_SHLIB_EXT); - - // Try '-plugin-path'. - for (const auto &searchPath : SearchPathOpts.PluginSearchPaths) { - SmallString<128> fullPath(searchPath); - llvm::sys::path::append(fullPath, expectedBasename); - if (fs->exists(fullPath)) { - return std::string(fullPath); - } - } - - // Try '-load-plugin-library'. - for (const auto &libPath : SearchPathOpts.getCompilerPluginLibraryPaths()) { - if (llvm::sys::path::filename(libPath) == expectedBasename) { - return libPath; - } - } - - return None; -} - -Optional -ASTContext::lookupExecutablePluginByModuleName(Identifier moduleName) { - auto &execPluginPaths = getImpl().ExecutablePluginPaths; - auto found = execPluginPaths.find(moduleName); - if (found == execPluginPaths.end()) - return None; - return found->second; -} - -Optional> -ASTContext::lookupExternalLibraryPluginByModuleName(Identifier moduleName) { - auto fs = this->SourceMgr.getFileSystem(); - for (auto &pair : SearchPathOpts.ExternalPluginSearchPaths) { - SmallString<128> fullPath(pair.SearchPath); - llvm::sys::path::append(fullPath, "lib" + moduleName.str() + LTDL_SHLIB_EXT); - - if (fs->exists(fullPath)) { - return {{std::string(fullPath), pair.ServerPath}}; - } - } - return None; -} - -LoadedExecutablePlugin *ASTContext::loadExecutablePlugin(StringRef path) { - SmallString<128> resolvedPath; - auto fs = this->SourceMgr.getFileSystem(); - if (auto err = fs->getRealPath(path, resolvedPath)) { - Diags.diagnose(SourceLoc(), diag::compiler_plugin_not_loaded, path, - err.message()); - return nullptr; - } - - // Load the plugin. - auto plugin = getPluginRegistry()->loadExecutablePlugin(resolvedPath); - if (!plugin) { - Diags.diagnose(SourceLoc(), diag::compiler_plugin_not_loaded, path, - llvm::toString(plugin.takeError())); - return nullptr; - } - - return plugin.get(); -} - -LoadedLibraryPlugin *ASTContext::loadLibraryPlugin(StringRef path) { - // Remember the path (even if it fails to load.) - getImpl().LoadedPluginLibraryPaths.insert(path); - - SmallString<128> resolvedPath; - auto fs = this->SourceMgr.getFileSystem(); - if (auto err = fs->getRealPath(path, resolvedPath)) { - Diags.diagnose(SourceLoc(), diag::compiler_plugin_not_loaded, path, - err.message()); - return nullptr; - } - - // Load the plugin. - auto plugin = getPluginRegistry()->loadLibraryPlugin(resolvedPath); - if (!plugin) { - Diags.diagnose(SourceLoc(), diag::compiler_plugin_not_loaded, path, - llvm::toString(plugin.takeError())); - return nullptr; - } - - return plugin.get(); -} - -const llvm::StringSet<> &ASTContext::getLoadedPluginLibraryPaths() const { - return getImpl().LoadedPluginLibraryPaths; -} - bool ASTContext::supportsMoveOnlyTypes() const { // currently the only thing holding back whether the types can appear is this. return SILOpts.LexicalLifetimes != LexicalLifetimesOption::Off; diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 6816149d07993..9320fec8b9b76 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -72,6 +72,7 @@ add_swift_host_library(swiftAST STATIC Parameter.cpp Pattern.cpp PlatformKind.cpp + PluginLoader.cpp PluginRegistry.cpp PrettyStackTrace.cpp ProtocolConformance.cpp diff --git a/lib/AST/PluginLoader.cpp b/lib/AST/PluginLoader.cpp new file mode 100644 index 0000000000000..3eddd2b08c3c3 --- /dev/null +++ b/lib/AST/PluginLoader.cpp @@ -0,0 +1,150 @@ +//===--- PluginLoader.cpp -------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/PluginLoader.h" +#include "swift/AST/ASTContext.h" +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsFrontend.h" +#include "swift/Basic/SourceManager.h" +#include "llvm/Config/config.h" + +using namespace swift; + +void PluginLoader::createModuleToExecutablePluginMap() { + for (auto &arg : Ctx.SearchPathOpts.getCompilerPluginExecutablePaths()) { + // Create a moduleName -> pluginPath mapping. + assert(!arg.ExecutablePath.empty() && "empty plugin path"); + StringRef pathStr = Ctx.AllocateCopy(arg.ExecutablePath); + for (auto moduleName : arg.ModuleNames) { + ExecutablePluginPaths[Ctx.getIdentifier(moduleName)] = pathStr; + } + } +} + +void PluginLoader::setRegistry(PluginRegistry *newValue) { + assert(Registry == nullptr && "Too late to set a new plugin registry"); + Registry = newValue; +} + +PluginRegistry *PluginLoader::getRegistry() { + // Create a new one if it hasn't been set. + if (!Registry) { + Registry = new PluginRegistry(); + OwnedRegistry.reset(Registry); + } + + assert(Registry != nullptr); + return Registry; +} + +llvm::Optional +PluginLoader::lookupLibraryPluginByModuleName(Identifier moduleName) { + auto fs = Ctx.SourceMgr.getFileSystem(); + + // Look for 'lib${module name}(.dylib|.so)'. + SmallString<64> expectedBasename; + expectedBasename.append("lib"); + expectedBasename.append(moduleName.str()); + expectedBasename.append(LTDL_SHLIB_EXT); + + // Try '-load-plugin-library'. + for (const auto &libPath : + Ctx.SearchPathOpts.getCompilerPluginLibraryPaths()) { + if (llvm::sys::path::filename(libPath) == expectedBasename) { + return libPath; + } + } + + // Try '-plugin-path'. + for (const auto &searchPath : Ctx.SearchPathOpts.PluginSearchPaths) { + SmallString<128> fullPath(searchPath); + llvm::sys::path::append(fullPath, expectedBasename); + if (fs->exists(fullPath)) { + return std::string(fullPath); + } + } + + return None; +} + +Optional> +PluginLoader::lookupExternalLibraryPluginByModuleName(Identifier moduleName) { + auto fs = Ctx.SourceMgr.getFileSystem(); + + for (auto &pair : Ctx.SearchPathOpts.ExternalPluginSearchPaths) { + SmallString<128> fullPath(pair.SearchPath); + llvm::sys::path::append(fullPath, + "lib" + moduleName.str() + LTDL_SHLIB_EXT); + + if (fs->exists(fullPath)) { + return {{std::string(fullPath), pair.ServerPath}}; + } + } + return None; +} + +Optional +PluginLoader::lookupExecutablePluginByModuleName(Identifier moduleName) { + auto &execPluginPaths = ExecutablePluginPaths; + auto found = execPluginPaths.find(moduleName); + if (found == execPluginPaths.end()) + return None; + return found->second; +} + +LoadedLibraryPlugin *PluginLoader::loadLibraryPlugin(StringRef path) { + auto fs = Ctx.SourceMgr.getFileSystem(); + SmallString<128> resolvedPath; + if (auto err = fs->getRealPath(path, resolvedPath)) { + Ctx.Diags.diagnose(SourceLoc(), diag::compiler_plugin_not_loaded, path, + err.message()); + return nullptr; + } + + // Track the dependency. + if (DepTracker) + DepTracker->addDependency(resolvedPath, /*IsSystem=*/false); + + // Load the plugin. + auto plugin = getRegistry()->loadLibraryPlugin(resolvedPath); + if (!plugin) { + Ctx.Diags.diagnose(SourceLoc(), diag::compiler_plugin_not_loaded, path, + llvm::toString(plugin.takeError())); + return nullptr; + } + + return plugin.get(); +} + +LoadedExecutablePlugin *PluginLoader::loadExecutablePlugin(StringRef path) { + auto fs = Ctx.SourceMgr.getFileSystem(); + SmallString<128> resolvedPath; + if (auto err = fs->getRealPath(path, resolvedPath)) { + Ctx.Diags.diagnose(SourceLoc(), diag::compiler_plugin_not_loaded, path, + err.message()); + return nullptr; + } + + // Track the dependency. + if (DepTracker) + DepTracker->addDependency(resolvedPath, /*IsSystem=*/false); + + // Load the plugin. + auto plugin = getRegistry()->loadExecutablePlugin(resolvedPath); + if (!plugin) { + Ctx.Diags.diagnose(SourceLoc(), diag::compiler_plugin_not_loaded, path, + llvm::toString(plugin.takeError())); + return nullptr; + } + + return plugin.get(); +} diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 5a8ddacecae36..30bd582efb0e3 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -22,6 +22,7 @@ #include "swift/AST/FileSystem.h" #include "swift/AST/Module.h" #include "swift/AST/ModuleDependencies.h" +#include "swift/AST/PluginLoader.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/FileTypes.h" #include "swift/Basic/SourceManager.h" @@ -281,6 +282,8 @@ bool CompilerInstance::setUpASTContextIfNeeded() { if (setUpModuleLoaders()) return true; + if (setUpPluginLoader()) + return true; return false; } @@ -386,11 +389,6 @@ void CompilerInstance::setupDependencyTrackerIfNeeded() { return; DepTracker = std::make_unique(*collectionMode); - - // Collect compiler plugin dependencies. - auto &searchPathOpts = Invocation.getSearchPathOptions(); - for (auto &path : searchPathOpts.getCompilerPluginLibraryPaths()) - DepTracker->addDependency(path, /*isSystem=*/false); } bool CompilerInstance::setup(const CompilerInvocation &Invoke, @@ -651,6 +649,14 @@ bool CompilerInstance::setUpModuleLoaders() { return false; } +bool CompilerInstance::setUpPluginLoader() { + /// FIXME: If Invocation has 'PluginRegistry', we can set it. But should we? + auto loader = + std::make_unique(*Context, getDependencyTracker()); + Context->setPluginLoader(std::move(loader)); + return false; +} + Optional CompilerInstance::setUpIDEInspectionTargetBuffer() { Optional ideInspectionTargetBufferID; auto ideInspectionTarget = Invocation.getIDEInspectionTarget(); diff --git a/lib/FrontendTool/LoadedModuleTrace.cpp b/lib/FrontendTool/LoadedModuleTrace.cpp index 1f64336b1a855..c6dfec7d6d254 100644 --- a/lib/FrontendTool/LoadedModuleTrace.cpp +++ b/lib/FrontendTool/LoadedModuleTrace.cpp @@ -759,10 +759,6 @@ bool swift::emitLoadedModuleTraceIfNeeded(ModuleDecl *mainModule, std::make_pair(loadedDecl->getModuleFilename(), loadedDecl)); } - // Add compiler plugin libraries as dependencies. - for (auto &pluginEntry : ctxt.getLoadedPluginLibraryPaths()) - depTracker->addDependency(pluginEntry.getKey(), /*IsSystem*/ false); - std::vector swiftModules; computeSwiftModuleTraceInfo(ctxt, abiDependencies, pathToModuleDecl, *depTracker, opts.PrebuiltModuleCachePath, diff --git a/lib/IDETool/CompileInstance.cpp b/lib/IDETool/CompileInstance.cpp index 9d17c31404bdc..03dceda62a07e 100644 --- a/lib/IDETool/CompileInstance.cpp +++ b/lib/IDETool/CompileInstance.cpp @@ -16,6 +16,7 @@ #include "swift/AST/ASTContext.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/Module.h" +#include "swift/AST/PluginLoader.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/SourceFile.h" #include "swift/Basic/Defer.h" @@ -303,7 +304,7 @@ bool CompileInstance::setupCI( assert(Diags.hadAnyError()); return false; } - CI->getASTContext().setPluginRegistry(Plugins.get()); + CI->getASTContext().getPluginLoader().setRegistry(Plugins.get()); return true; } diff --git a/lib/IDETool/IDEInspectionInstance.cpp b/lib/IDETool/IDEInspectionInstance.cpp index 41fca55f3ee81..f9580cfa9a985 100644 --- a/lib/IDETool/IDEInspectionInstance.cpp +++ b/lib/IDETool/IDEInspectionInstance.cpp @@ -17,6 +17,7 @@ #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Module.h" +#include "swift/AST/PluginLoader.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/AST/SourceFile.h" #include "swift/Basic/Defer.h" @@ -482,7 +483,7 @@ void IDEInspectionInstance::performNewOperation( InstanceSetupError)); return; } - CI->getASTContext().setPluginRegistry(Plugins.get()); + CI->getASTContext().getPluginLoader().setRegistry(Plugins.get()); CI->getASTContext().CancellationFlag = CancellationFlag; registerIDERequestFunctions(CI->getASTContext().evaluator); diff --git a/test/Driver/loaded_module_trace.swift b/test/Driver/loaded_module_trace.swift index 941b30dc7c975..e2bde7a578123 100644 --- a/test/Driver/loaded_module_trace.swift +++ b/test/Driver/loaded_module_trace.swift @@ -1,3 +1,4 @@ +// REQUIRES: swift_swift_parser // RUN: %empty-directory(%t) // RUN: %empty-directory(%t/cache) // RUN: %target-build-swift -emit-module -module-name Module %S/Inputs/loaded_module_trace_empty.swift -o %t/Module.swiftmodule -module-cache-path %t/cache @@ -34,3 +35,5 @@ // CHECK-CONFIRM-ONELINE: {"name":{{.*}}]} import Module2 + +@freestanding(expression) macro echo(_: T) -> T = #externalMacro(module: "Plugin", type: "EchoMacro") diff --git a/test/Macros/macro_swiftdeps.swift b/test/Macros/macro_swiftdeps.swift new file mode 100644 index 0000000000000..dd969f3d6e9a9 --- /dev/null +++ b/test/Macros/macro_swiftdeps.swift @@ -0,0 +1,125 @@ +// REQUIRES: swift_swift_parser + +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/plugin) +// RUN: %empty-directory(%t/lib) +// RUN: %empty-directory(%t/src) + +// RUN: split-file %s %t/src + +//#-- Prepare the macro dylib plugin. +// RUN: %host-build-swift \ +// RUN: -swift-version 5 \ +// RUN: -emit-library -o %t/plugin/%target-library-name(MacroDefinition) \ +// RUN: -module-name MacroDefinition \ +// RUN: %S/Inputs/syntax_macro_definitions.swift \ +// RUN: -g -no-toolchain-stdlib-rpath + +//#-- Prepare the macro executable plugin. +// RUN: %clang \ +// RUN: -isysroot %host_sdk \ +// RUN: -I %swift_src_root/include \ +// RUN: -L %swift-lib-dir -l_swiftMockPlugin \ +// RUN: -Wl,-rpath,%swift-lib-dir \ +// RUN: -o %t/mock-plugin \ +// RUN: %t/src/plugin.c + +//#-- Prepare the macro library. +// RUN: %target-swift-frontend \ +// RUN: -swift-version 5 \ +// RUN: -emit-module -o %t/lib/MacroLib.swiftmodule \ +// RUN: -module-name MacroLib \ +// RUN: -plugin-path %t/plugin \ +// RUN: -load-plugin-executable %t/mock-plugin#TestPlugin \ +// RUN: -primary-file %t/src/macro_library.swift \ +// RUN: -emit-reference-dependencies-path %t/macro_library.swiftdeps \ +// RUN: -emit-dependencies-path %t/macro_library.d +// RUN: %S/../Inputs/process_fine_grained_swiftdeps.sh %swift-dependency-tool %t/macro_library.swiftdeps %t/macro_library.swiftdeps.processed +// RUN: %FileCheck --check-prefix WITH_PLUGIN %s < %t/macro_library.swiftdeps.processed + +//#-- Without macro (no -D USE_MACRO) +// RUN: %target-swift-frontend \ +// RUN: -swift-version 5 -typecheck \ +// RUN: -primary-file %t/src/test.swift \ +// RUN: %t/src/other.swift \ +// RUN: -I %t/lib -plugin-path %t/plugin \ +// RUN: -load-plugin-executable %t/mock-plugin#TestPlugin \ +// RUN: -emit-reference-dependencies-path %t/without_macro.swiftdeps \ +// RUN: -emit-dependencies-path %t/without_macro.d +// RUN: %S/../Inputs/process_fine_grained_swiftdeps.sh %swift-dependency-tool %t/without_macro.swiftdeps %t/without_macro.swiftdeps.processed +// RUN: %FileCheck --check-prefix WITHOUT_PLUGIN %s < %t/without_macro.swiftdeps.processed + +//#-- With macro - primary (-D USE_MACRO) +// RUN: %target-swift-frontend \ +// RUN: -D USE_MACRO \ +// RUN: -swift-version 5 -typecheck \ +// RUN: -primary-file %t/src/test.swift \ +// RUN: %t/src/other.swift \ +// RUN: -I %t/lib -plugin-path %t/plugin \ +// RUN: -load-plugin-executable %t/mock-plugin#TestPlugin \ +// RUN: -emit-reference-dependencies-path %t/with_macro_primary.swiftdeps \ +// RUN: -emit-dependencies-path %t/with_macro_primary.d +// RUN: %S/../Inputs/process_fine_grained_swiftdeps.sh %swift-dependency-tool %t/with_macro_primary.swiftdeps %t/with_macro_primary.swiftdeps.processed +// RUN: %FileCheck --check-prefix WITH_PLUGIN %s < %t/with_macro_primary.swiftdeps.processed + +//#-- With macro - non-primary (-D USE_MACRO) +// RUN: %target-swift-frontend \ +// RUN: -D USE_MACRO \ +// RUN: -swift-version 5 -typecheck \ +// RUN: %t/src/test.swift \ +// RUN: -primary-file %t/src/other.swift \ +// RUN: -I %t/lib -plugin-path %t/plugin \ +// RUN: -load-plugin-executable %t/mock-plugin#TestPlugin \ +// RUN: -emit-reference-dependencies-path %t/with_macro_nonprimary.swiftdeps \ +// RUN: -emit-dependencies-path %t/with_macro_nonprimary.d +// RUN: %S/../Inputs/process_fine_grained_swiftdeps.sh %swift-dependency-tool %t/with_macro_nonprimary.swiftdeps %t/with_macro_nonprimary.swiftdeps.processed +// RUN: %FileCheck --check-prefix WITHOUT_PLUGIN %s < %t/with_macro_nonprimary.swiftdeps.processed + +// WITH_PLUGIN: externalDepend interface '' 'BUILD_DIR{{.*}}mock-plugin' false +// WITH_PLUGIN: externalDepend interface '' 'BUILD_DIR{{.*}}libMacroDefinition.dylib' false + +// WITHOUT_PLUGIN-NOT: MacroDefinition +// WITHOUT_PLUGIN-NOT: mock-plugin + +//--- macro_library.swift +@freestanding(expression) public macro stringify(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro") +@freestanding(expression) public macro testString(_: Any) -> String = #externalMacro(module: "TestPlugin", type: "TestStringMacro") + +public func funcInMacroLib() {} + +//--- test.swift +import MacroLib + +func test(a: Int, b: Int) { + // Just using MacroLib without macro + funcInMacroLib() + +#if USE_MACRO + _ = #stringify(a + b) + _ = #testString(123) +#endif +} + +//--- other.swift +import MacroLib + +func test() { + // Just using MacroLib without macro + funcInMacroLib() +} + +//--- plugin.c +#include "swift-c/MockPlugin/MockPlugin.h" + +MOCK_PLUGIN([ + { + "expect": {"getCapability": {}}, + "response": {"getCapabilityResult": {"capability": {"protocolVersion": 1}}} + }, + { + "expect": {"expandFreestandingMacro": { + "macro": {"moduleName": "TestPlugin", "typeName": "TestStringMacro"}, + "syntax": {"kind": "expression", "source": "#testString(123)"}}}, + "response": {"expandFreestandingMacroResult": {"expandedSource": "\"test\"", "diagnostics": []}} + } +]) diff --git a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp index ef667aa9c54aa..8ce56fa2d46be 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp @@ -20,6 +20,7 @@ #include "SourceKit/Support/Logging.h" #include "SourceKit/Support/Tracing.h" +#include "swift/AST/PluginLoader.h" #include "swift/Basic/Cache.h" #include "swift/Driver/FrontendUtil.h" #include "swift/Frontend/Frontend.h" @@ -1077,7 +1078,8 @@ ASTUnitRef ASTBuildOperation::buildASTUnit(std::string &Error) { } return nullptr; } - CompIns.getASTContext().setPluginRegistry(ASTManager->Impl.Plugins.get()); + CompIns.getASTContext().getPluginLoader().setRegistry( + ASTManager->Impl.Plugins.get()); CompIns.getASTContext().CancellationFlag = CancellationFlag; registerIDERequestFunctions(CompIns.getASTContext().evaluator); if (TracedOp.enabled()) {