Skip to content

Commit 39cb996

Browse files
Merge pull request #73421 from cachemeifyoucan/eng/PR-127116512
[ScanDependencies] Get accurate macro dependency
2 parents b8c308d + 4125e8c commit 39cb996

File tree

5 files changed

+110
-86
lines changed

5 files changed

+110
-86
lines changed

include/swift/AST/ModuleDependencies.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ enum class ModuleDependencyKind : int8_t {
9090
LastKind = SwiftPlaceholder + 1
9191
};
9292

93+
/// This is used to idenfity a specific macro plugin dependency.
94+
struct MacroPluginDependency {
95+
std::string LibraryPath;
96+
std::string ExecutablePath;
97+
};
98+
9399
/// This is used to identify a specific module.
94100
struct ModuleDependencyID {
95101
std::string ModuleName;
@@ -246,6 +252,9 @@ struct CommonSwiftTextualModuleDependencyDetails {
246252
/// (Clang) modules on which the bridging header depends.
247253
std::vector<std::string> bridgingModuleDependencies;
248254

255+
/// The macro dependencies.
256+
llvm::StringMap<MacroPluginDependency> macroDependencies;
257+
249258
/// The Swift frontend invocation arguments to build the Swift module from the
250259
/// interface.
251260
std::vector<std::string> buildCommandLine;
@@ -311,6 +320,12 @@ class SwiftInterfaceModuleDependenciesStorage
311320
void updateCommandLine(const std::vector<std::string> &newCommandLine) {
312321
textualModuleDetails.buildCommandLine = newCommandLine;
313322
}
323+
324+
void addMacroDependency(StringRef macroModuleName, StringRef libraryPath,
325+
StringRef executablePath) {
326+
textualModuleDetails.macroDependencies.insert(
327+
{macroModuleName, {libraryPath.str(), executablePath.str()}});
328+
}
314329
};
315330

316331
/// Describes the dependencies of a Swift module
@@ -361,6 +376,12 @@ class SwiftSourceModuleDependenciesStorage
361376
void addTestableImport(ImportPath::Module module) {
362377
testableImports.insert(module.front().Item.str());
363378
}
379+
380+
void addMacroDependency(StringRef macroModuleName, StringRef libraryPath,
381+
StringRef executablePath) {
382+
textualModuleDetails.macroDependencies.insert(
383+
{macroModuleName, {libraryPath.str(), executablePath.str()}});
384+
}
364385
};
365386

366387
/// Describes the dependencies of a pre-built Swift module (with no
@@ -759,6 +780,10 @@ class ModuleDependencyInfo {
759780
/// For a Source dependency, register a `Testable` import
760781
void addTestableImport(ImportPath::Module module);
761782

783+
/// For a Source dependency, register a macro dependency.
784+
void addMacroDependency(StringRef macroModuleName, StringRef libraryPath,
785+
StringRef executablePath);
786+
762787
/// Whether or not a queried module name is a `@Testable` import dependency
763788
/// of this module. Can only return `true` for Swift source modules.
764789
bool isTestableImport(StringRef moduleName) const;

lib/AST/ModuleDependencies.cpp

Lines changed: 56 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
#include "swift/AST/Decl.h"
1818
#include "swift/AST/DiagnosticsFrontend.h"
1919
#include "swift/AST/DiagnosticsSema.h"
20+
#include "swift/AST/MacroDefinition.h"
21+
#include "swift/AST/PluginLoader.h"
2022
#include "swift/AST/SourceFile.h"
21-
#include "swift/Basic/Assertions.h"
2223
#include "swift/Frontend/Frontend.h"
2324
#include "llvm/CAS/CASProvidingFileSystem.h"
2425
#include "llvm/CAS/CachingOnDiskFileSystem.h"
@@ -104,6 +105,21 @@ void ModuleDependencyInfo::addTestableImport(ImportPath::Module module) {
104105
dyn_cast<SwiftSourceModuleDependenciesStorage>(storage.get())->addTestableImport(module);
105106
}
106107

108+
void ModuleDependencyInfo::addMacroDependency(StringRef macroModuleName,
109+
StringRef libraryPath,
110+
StringRef executablePath) {
111+
if (auto swiftSourceStorage =
112+
dyn_cast<SwiftSourceModuleDependenciesStorage>(storage.get()))
113+
swiftSourceStorage->addMacroDependency(macroModuleName, libraryPath,
114+
executablePath);
115+
else if (auto swiftInterfaceStorage =
116+
dyn_cast<SwiftInterfaceModuleDependenciesStorage>(storage.get()))
117+
swiftInterfaceStorage->addMacroDependency(macroModuleName, libraryPath,
118+
executablePath);
119+
else
120+
llvm_unreachable("Unexpected dependency kind");
121+
}
122+
107123
bool ModuleDependencyInfo::isTestableImport(StringRef moduleName) const {
108124
if (auto swiftSourceDepStorage = getAsSwiftSourceModule())
109125
return swiftSourceDepStorage->testableImports.contains(moduleName);
@@ -184,35 +200,45 @@ void ModuleDependencyInfo::addModuleImports(
184200
SmallVector<Decl *, 32> decls;
185201
sourceFile.getTopLevelDecls(decls);
186202
for (auto decl : decls) {
187-
auto importDecl = dyn_cast<ImportDecl>(decl);
188-
if (!importDecl)
189-
continue;
190-
191-
ImportPath::Builder scratch;
192-
auto realPath = importDecl->getRealModulePath(scratch);
193-
194-
// Explicit 'Builtin' import is not a part of the module's
195-
// dependency set, does not exist on the filesystem,
196-
// and is resolved within the compiler during compilation.
197-
SmallString<64> importedModuleName;
198-
realPath.getString(importedModuleName);
199-
if (importedModuleName == BUILTIN_NAME)
200-
continue;
201-
202-
// Ignore/diagnose tautological imports akin to import resolution
203-
if (!swift::dependencies::checkImportNotTautological(
204-
realPath, importDecl->getLoc(), sourceFile,
205-
importDecl->isExported()))
206-
continue;
207-
208-
addModuleImport(realPath, &alreadyAddedModules,
209-
sourceManager, importDecl->getLoc());
210-
211-
// Additionally, keep track of which dependencies of a Source
212-
// module are `@Testable`.
213-
if (getKind() == swift::ModuleDependencyKind::SwiftSource &&
214-
importDecl->isTestable())
215-
addTestableImport(realPath);
203+
if (auto importDecl = dyn_cast<ImportDecl>(decl)) {
204+
ImportPath::Builder scratch;
205+
auto realPath = importDecl->getRealModulePath(scratch);
206+
207+
// Explicit 'Builtin' import is not a part of the module's
208+
// dependency set, does not exist on the filesystem,
209+
// and is resolved within the compiler during compilation.
210+
SmallString<64> importedModuleName;
211+
realPath.getString(importedModuleName);
212+
if (importedModuleName == BUILTIN_NAME)
213+
continue;
214+
215+
// Ignore/diagnose tautological imports akin to import resolution
216+
if (!swift::dependencies::checkImportNotTautological(
217+
realPath, importDecl->getLoc(), sourceFile,
218+
importDecl->isExported()))
219+
continue;
220+
221+
addModuleImport(realPath, &alreadyAddedModules, sourceManager,
222+
importDecl->getLoc());
223+
224+
// Additionally, keep track of which dependencies of a Source
225+
// module are `@Testable`.
226+
if (getKind() == swift::ModuleDependencyKind::SwiftSource &&
227+
importDecl->isTestable())
228+
addTestableImport(realPath);
229+
} else if (auto macroDecl = dyn_cast<MacroDecl>(decl)) {
230+
auto macroDef = macroDecl->getDefinition();
231+
auto &ctx = macroDecl->getASTContext();
232+
if (macroDef.kind != MacroDefinition::Kind::External)
233+
continue;
234+
auto external = macroDef.getExternalMacro();
235+
PluginLoader &loader = ctx.getPluginLoader();
236+
auto &entry = loader.lookupPluginByModuleName(external.moduleName);
237+
if (entry.libraryPath.empty() && entry.executablePath.empty())
238+
continue;
239+
addMacroDependency(external.moduleName.str(), entry.libraryPath,
240+
entry.executablePath);
241+
}
216242
}
217243

218244
auto fileName = sourceFile.getFilename();
@@ -609,58 +635,6 @@ void SwiftDependencyTracker::addCommonSearchPathDeps(
609635
// Add VFSOverlay file.
610636
for (auto &Overlay: Opts.VFSOverlayFiles)
611637
FS->status(Overlay);
612-
613-
// Add plugin dylibs from the toolchain only by look through the plugin search
614-
// directory.
615-
auto recordFiles = [&](StringRef Path) {
616-
std::error_code EC;
617-
for (auto I = FS->dir_begin(Path, EC);
618-
!EC && I != llvm::vfs::directory_iterator(); I = I.increment(EC)) {
619-
if (I->type() != llvm::sys::fs::file_type::regular_file)
620-
continue;
621-
#if defined(_WIN32)
622-
constexpr StringRef libPrefix{};
623-
constexpr StringRef libSuffix = ".dll";
624-
#else
625-
constexpr StringRef libPrefix = "lib";
626-
constexpr StringRef libSuffix = LTDL_SHLIB_EXT;
627-
#endif
628-
StringRef filename = llvm::sys::path::filename(I->path());
629-
if (filename.starts_with(libPrefix) && filename.ends_with(libSuffix))
630-
FS->status(I->path());
631-
}
632-
};
633-
for (auto &entry : Opts.PluginSearchOpts) {
634-
switch (entry.getKind()) {
635-
636-
// '-load-plugin-library <library path>'.
637-
case PluginSearchOption::Kind::LoadPluginLibrary: {
638-
auto &val = entry.get<PluginSearchOption::LoadPluginLibrary>();
639-
FS->status(val.LibraryPath);
640-
break;
641-
}
642-
643-
// '-load-plugin-executable <executable path>#<module name>, ...'.
644-
case PluginSearchOption::Kind::LoadPluginExecutable: {
645-
// We don't have executable plugin in toolchain.
646-
break;
647-
}
648-
649-
// '-plugin-path <library search path>'.
650-
case PluginSearchOption::Kind::PluginPath: {
651-
auto &val = entry.get<PluginSearchOption::PluginPath>();
652-
recordFiles(val.SearchPath);
653-
break;
654-
}
655-
656-
// '-external-plugin-path <library search path>#<server path>'.
657-
case PluginSearchOption::Kind::ExternalPluginPath: {
658-
auto &val = entry.get<PluginSearchOption::ExternalPluginPath>();
659-
recordFiles(val.SearchPath);
660-
break;
661-
}
662-
}
663-
}
664638
}
665639

666640
void SwiftDependencyTracker::startTracking() {

lib/DependencyScan/ScanDependencies.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ static llvm::Error resolveExplicitModuleInputs(
244244
return E;
245245

246246
std::vector<std::string> commandLine = resolvingDepInfo.getCommandline();
247+
auto dependencyInfoCopy = resolvingDepInfo;
247248
for (const auto &depModuleID : dependencies) {
248249
const auto &depInfo = cache.findKnownDependency(depModuleID);
249250
switch (depModuleID.Kind) {
@@ -255,6 +256,14 @@ static llvm::Error resolveExplicitModuleInputs(
255256
: interfaceDepDetails->moduleCacheKey;
256257
commandLine.push_back("-swift-module-file=" + depModuleID.ModuleName + "=" +
257258
path);
259+
// Add the exported macro from interface into current module.
260+
llvm::for_each(
261+
interfaceDepDetails->textualModuleDetails.macroDependencies,
262+
[&](const auto &entry) {
263+
dependencyInfoCopy.addMacroDependency(entry.first(),
264+
entry.second.LibraryPath,
265+
entry.second.ExecutablePath);
266+
});
258267
} break;
259268
case swift::ModuleDependencyKind::SwiftBinary: {
260269
auto binaryDepDetails = depInfo.getAsSwiftBinaryModule();
@@ -319,7 +328,6 @@ static llvm::Error resolveExplicitModuleInputs(
319328
}
320329

321330
// Update the dependency in the cache with the modified command-line.
322-
auto dependencyInfoCopy = resolvingDepInfo;
323331
if (resolvingDepInfo.isSwiftInterfaceModule() ||
324332
resolvingDepInfo.isClangModule()) {
325333
if (service.hasPathMapping())
@@ -345,6 +353,10 @@ static llvm::Error resolveExplicitModuleInputs(
345353
llvm::for_each(
346354
sourceDep->auxiliaryFiles,
347355
[&tracker](const std::string &file) { tracker->trackFile(file); });
356+
llvm::for_each(sourceDep->textualModuleDetails.macroDependencies,
357+
[&tracker](const auto &entry) {
358+
tracker->trackFile(entry.second.LibraryPath);
359+
});
348360
auto root = tracker->createTreeFromDependencies();
349361
if (!root)
350362
return root.takeError();

lib/Sema/TypeCheckMacros.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ static llvm::Expected<CompilerPlugin *>
239239
initializePlugin(ASTContext &ctx, CompilerPlugin *plugin, StringRef libraryPath,
240240
Identifier moduleName) {
241241
// Lock the plugin while initializing.
242-
// Note that'executablePlugn' can be shared between multiple ASTContext.
242+
// Note that 'executablePlugin' can be shared between multiple ASTContext.
243243
plugin->lock();
244244
SWIFT_DEFER { plugin->unlock(); };
245245

test/CAS/macro_plugin_external.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
// RUN: %empty-directory(%t)
77
// RUN: %empty-directory(%t/plugins)
8+
// RUN: split-file %s %t
89
//
910
//== Build the plugin library
1011
// RUN: %host-build-swift \
@@ -15,9 +16,17 @@
1516
// RUN: %S/../Macros/Inputs/syntax_macro_definitions.swift \
1617
// RUN: -g -no-toolchain-stdlib-rpath
1718

19+
/// No macro plugin when macro not used.
1820
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \
1921
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
20-
// RUN: %s -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -external-plugin-path %t/plugins#%swift-plugin-server
22+
// RUN: %t/nomacro.swift -o %t/deps1.json -swift-version 5 -cache-compile-job -cas-path %t/cas -external-plugin-path %t/plugins#%swift-plugin-server
23+
// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps1.json MyApp casFSRootID > %t/no_macro_fs.casid
24+
// RUN: llvm-cas -cas %t/cas -ls-tree-recursive @%t/no_macro_fs.casid | %FileCheck %s --check-prefix=NO-MACRO
25+
// NO-MACRO-NOT: MacroDefinition
26+
27+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-serialized -module-name MyApp -module-cache-path %t/clang-module-cache -O \
28+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
29+
// RUN: %t/macro.swift -o %t/deps.json -swift-version 5 -cache-compile-job -cas-path %t/cas -external-plugin-path %t/plugins#%swift-plugin-server
2130

2231
// RUN: %S/Inputs/SwiftDepsExtractor.py %t/deps.json MyApp casFSRootID > %t/fs.casid
2332
// RUN: llvm-cas -cas %t/cas -ls-tree-recursive @%t/fs.casid | %FileCheck %s --check-prefix=FS
@@ -37,8 +46,12 @@
3746
// RUN: -external-plugin-path %t/plugins/#%swift-plugin-server \
3847
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
3948
// RUN: -module-name MyApp -explicit-swift-module-map-file @%t/map.casid \
40-
// RUN: %s @%t/MyApp.cmd
49+
// RUN: %t/macro.swift @%t/MyApp.cmd
50+
51+
//--- nomacro.swift
52+
func test() {}
4153

54+
//--- macro.swift
4255
@attached(extension, conformances: P, names: named(requirement))
4356
macro DelegatedConformance() = #externalMacro(module: "MacroDefinition", type: "DelegatedConformanceViaExtensionMacro")
4457

0 commit comments

Comments
 (0)