1515#include " swift/AST/DiagnosticEngine.h"
1616#include " swift/AST/DiagnosticsFrontend.h"
1717#include " swift/Basic/SourceManager.h"
18+ #include " swift/Parse/Lexer.h"
1819#include " llvm/Config/config.h"
1920
2021using namespace swift ;
2122
22- void PluginLoader::createModuleToExecutablePluginMap () {
23- for (auto &elem : Ctx.SearchPathOpts .PluginSearchOpts ) {
24- if (auto *arg = elem.dyn_cast <PluginSearchOption::LoadPluginExecutable>()) {
25- // Create a moduleName -> pluginPath mapping.
26- assert (!arg->ExecutablePath .empty () && " empty plugin path" );
27- StringRef pathStr = Ctx.AllocateCopy (arg->ExecutablePath );
28- for (auto moduleName : arg->ModuleNames ) {
29- ExecutablePluginPaths[Ctx.getIdentifier (moduleName)] = pathStr;
30- }
31- }
32- }
33- }
34-
3523void PluginLoader::setRegistry (PluginRegistry *newValue) {
3624 assert (Registry == nullptr && " Too late to set a new plugin registry" );
3725 Registry = newValue;
@@ -48,65 +36,121 @@ PluginRegistry *PluginLoader::getRegistry() {
4836 return Registry;
4937}
5038
51- std::pair<std::string, std::string>
52- PluginLoader::lookupPluginByModuleName (Identifier moduleName) {
53- auto fs = Ctx.SourceMgr .getFileSystem ();
54-
55- // Look for 'lib${module name}(.dylib|.so)'.
39+ // / Get plugin module name from \p path if the path looks like a shared library
40+ // / path. Otherwise, returns an empty string.
41+ static StringRef pluginModuleNameStringFromPath (StringRef path) {
42+ // Plugin library must be named 'lib${module name}(.dylib|.so|.dll)'.
5643 // FIXME: Shared library prefix might be different between platforms.
57- SmallString<64 > pluginLibBasename;
58- pluginLibBasename.append (" lib" );
59- pluginLibBasename.append (moduleName.str ());
60- pluginLibBasename.append (LTDL_SHLIB_EXT);
44+ constexpr StringRef libPrefix = " lib" ;
45+ constexpr StringRef libSuffix = LTDL_SHLIB_EXT;
46+
47+ StringRef filename = llvm::sys::path::filename (path);
48+ if (filename.starts_with (libPrefix) && filename.ends_with (libSuffix)) {
49+ // We don't check if the result it a valid identifier. Even if we put
50+ // invalid name in the lookup table, clients wound not be able to lookup
51+ // that name, thus harmless.
52+ return filename.drop_front (libPrefix.size ()).drop_back (libSuffix.size ());
53+ }
54+ return " " ;
55+ }
56+
57+ llvm::DenseMap<Identifier, PluginLoader::PluginEntry> &
58+ PluginLoader::getPluginMap () {
59+ if (PluginMap.has_value ()) {
60+ return PluginMap.value ();
61+ }
62+
63+ // Create and populate the map.
64+ PluginMap.emplace ();
65+ auto &map = PluginMap.value ();
66+
67+ // Helper function to try inserting an entry if there's no existing entry
68+ // associated with the module name.
69+ auto try_emplace = [&](StringRef moduleName, StringRef libPath,
70+ StringRef execPath) {
71+ auto moduleNameIdentifier = Ctx.getIdentifier (moduleName);
72+ if (map.find (moduleNameIdentifier) != map.end ()) {
73+ // Specified module name is already in the map.
74+ return ;
75+ }
76+
77+ libPath = libPath.empty () ? " " : Ctx.AllocateCopy (libPath);
78+ execPath = execPath.empty () ? " " : Ctx.AllocateCopy (execPath);
79+ auto result = map.insert ({moduleNameIdentifier, {libPath, execPath}});
80+ assert (result.second );
81+ (void )result;
82+ };
83+
84+ auto fs = Ctx.SourceMgr .getFileSystem ();
85+ std::error_code ec;
6186
62- // FIXME: Should we create a lookup table keyed by module name?
6387 for (auto &entry : Ctx.SearchPathOpts .PluginSearchOpts ) {
6488 switch (entry.getKind ()) {
65- // Try '-load-plugin-library'.
89+
90+ // '-load-plugin-library <library path>'.
6691 case PluginSearchOption::Kind::LoadPluginLibrary: {
6792 auto &val = entry.get <PluginSearchOption::LoadPluginLibrary>();
68- if (llvm::sys::path::filename (val.LibraryPath ) == pluginLibBasename) {
69- return {val.LibraryPath , " " };
93+ auto moduleName = pluginModuleNameStringFromPath (val.LibraryPath );
94+ if (!moduleName.empty ()) {
95+ try_emplace (moduleName, val.LibraryPath , /* executablePath=*/ " " );
7096 }
7197 continue ;
7298 }
7399
74- // Try '-load-plugin-executable'.
100+ // '-load-plugin-executable <executable path>#<module name>, ... '.
75101 case PluginSearchOption::Kind::LoadPluginExecutable: {
76102 auto &val = entry.get <PluginSearchOption::LoadPluginExecutable>();
77- auto found = ExecutablePluginPaths.find (moduleName);
78- if (found != ExecutablePluginPaths.end () &&
79- found->second == val.ExecutablePath ) {
80- return {" " , val.ExecutablePath };
103+ assert (!val.ExecutablePath .empty () && " empty plugin path" );
104+ for (auto &moduleName : val.ModuleNames ) {
105+ try_emplace (moduleName, /* libraryPath=*/ " " , val.ExecutablePath );
81106 }
82107 continue ;
83108 }
84109
85- // Try '-plugin-path'.
110+ // '-plugin-path <library search path> '.
86111 case PluginSearchOption::Kind::PluginPath: {
87112 auto &val = entry.get <PluginSearchOption::PluginPath>();
88- SmallString<128 > fullPath (val.SearchPath );
89- llvm::sys::path::append (fullPath, pluginLibBasename);
90- if (fs->exists (fullPath)) {
91- return {std::string (fullPath), " " };
113+ for (auto i = fs->dir_begin (val.SearchPath , ec);
114+ i != llvm::vfs::directory_iterator (); i = i.increment (ec)) {
115+ auto libPath = i->path ();
116+ auto moduleName = pluginModuleNameStringFromPath (libPath);
117+ if (!moduleName.empty ()) {
118+ try_emplace (moduleName, libPath, /* executablePath=*/ " " );
119+ }
92120 }
93121 continue ;
94122 }
95123
96- // Try '-external-plugin-path'.
124+ // '-external-plugin-path <library search path>#<server path> '.
97125 case PluginSearchOption::Kind::ExternalPluginPath: {
98126 auto &val = entry.get <PluginSearchOption::ExternalPluginPath>();
99- SmallString<128 > fullPath (val.SearchPath );
100- llvm::sys::path::append (fullPath, pluginLibBasename);
101- if (fs->exists (fullPath)) {
102- return {std::string (fullPath), val.ServerPath };
127+ for (auto i = fs->dir_begin (val.SearchPath , ec);
128+ i != llvm::vfs::directory_iterator (); i = i.increment (ec)) {
129+ auto libPath = i->path ();
130+ auto moduleName = pluginModuleNameStringFromPath (libPath);
131+ if (!moduleName.empty ()) {
132+ try_emplace (moduleName, libPath, val.ServerPath );
133+ }
103134 }
104135 continue ;
105136 }
106137 }
138+ llvm_unreachable (" unhandled PluginSearchOption::Kind" );
107139 }
108140
109- return {};
141+ return map;
142+ }
143+
144+ const PluginLoader::PluginEntry &
145+ PluginLoader::lookupPluginByModuleName (Identifier moduleName) {
146+ auto &map = getPluginMap ();
147+ auto found = map.find (moduleName);
148+ if (found != map.end ()) {
149+ return found->second ;
150+ } else {
151+ static PluginEntry notFound{" " , " " };
152+ return notFound;
153+ }
110154}
111155
112156LoadedLibraryPlugin *PluginLoader::loadLibraryPlugin (StringRef path) {
0 commit comments