Skip to content

Commit 42cc989

Browse files
committed
DependenciesScanner: teach the scanner to handle cross-import overlays
1 parent b996a21 commit 42cc989

File tree

9 files changed

+164
-33
lines changed

9 files changed

+164
-33
lines changed

include/swift/AST/DiagnosticsCommon.def

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,11 +159,11 @@ NOTE(circular_type_resolution_note,none,
159159
// MARK: Cross-import overlay loading diagnostics
160160
//------------------------------------------------------------------------------
161161
ERROR(cannot_load_swiftoverlay_file, none,
162-
"cannot load cross-import overlay for %0 and %1: %2 (declared by '%3')",
163-
(Identifier, Identifier, StringRef, StringRef))
162+
"cannot load cross-import overlay for '%0' and '%1': %2 (declared by '%3')",
163+
(StringRef, StringRef, StringRef, StringRef))
164164
ERROR(cannot_list_swiftcrossimport_dir, none,
165-
"cannot list cross-import overlays for %0: %1 (declared in '%2')",
166-
(Identifier, StringRef, StringRef))
165+
"cannot list cross-import overlays for '%0': %1 (declared in '%2')",
166+
(StringRef, StringRef, StringRef))
167167
WARNING(cross_imported_by_both_modules, none,
168168
"modules %0 and %1 both declare module %2 as a cross-import overlay, "
169169
"which may cause paradoxical behavior when looking up names in them; "

include/swift/AST/Module.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,11 @@ class ModuleDecl : public DeclContext, public TypeDecl {
391391
/// Add a file declaring a cross-import overlay.
392392
void addCrossImportOverlayFile(StringRef file);
393393

394+
/// Collect cross-import overlay names from a given YAML file path.
395+
static llvm::SmallSetVector<Identifier, 4>
396+
collectCrossImportOverlay(ASTContext &ctx, StringRef file,
397+
StringRef moduleName, StringRef& bystandingModule);
398+
394399
/// If this method returns \c false, the module does not declare any
395400
/// cross-import overlays.
396401
///

include/swift/AST/ModuleDependencies.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ namespace swift {
2929

3030
class ClangModuleDependenciesCacheImpl;
3131
class SourceFile;
32+
class ASTContext;
33+
class Identifier;
3234

3335
/// Which kind of module dependencies we are looking for.
3436
enum class ModuleDependenciesKind : int8_t {
@@ -246,6 +248,11 @@ class ModuleDependencies {
246248
/// Add (Clang) module on which the bridging header depends.
247249
void addBridgingModuleDependency(StringRef module,
248250
llvm::StringSet<> &alreadyAddedModules);
251+
252+
/// Collect a map from a secondary module name to a list of cross-import
253+
/// overlays, when this current module serves as the primary module.
254+
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>>
255+
collectCrossImportOverlayNames(ASTContext &ctx, StringRef moduleName);
249256
};
250257

251258
using ModuleDependencyID = std::pair<std::string, ModuleDependenciesKind>;

lib/AST/Module.cpp

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@ const clang::Module *ModuleDecl::findUnderlyingClangModule() const {
15201520
namespace swift {
15211521
/// Represents a file containing information about cross-module overlays.
15221522
class OverlayFile {
1523+
friend class ModuleDecl;
15231524
/// The file that data should be loaded from.
15241525
StringRef filePath;
15251526

@@ -1536,7 +1537,10 @@ class OverlayFile {
15361537
/// before returning.
15371538
bool loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
15381539
Identifier bystandingModule);
1539-
1540+
bool loadOverlayModuleNames(ASTContext &ctx,
1541+
StringRef module,
1542+
StringRef bystandingModule,
1543+
SourceLoc diagLoc);
15401544
public:
15411545
// Only allocate in ASTContexts.
15421546
void *operator new(size_t bytes) = delete;
@@ -1577,6 +1581,21 @@ void ModuleDecl::addCrossImportOverlayFile(StringRef file) {
15771581
.push_back(new (ctx) OverlayFile(ctx.AllocateCopy(file)));
15781582
}
15791583

1584+
llvm::SmallSetVector<Identifier, 4>
1585+
ModuleDecl::collectCrossImportOverlay(ASTContext &ctx,
1586+
StringRef file,
1587+
StringRef moduleName,
1588+
StringRef &bystandingModule) {
1589+
OverlayFile ovFile(file);
1590+
bystandingModule = llvm::sys::path::stem(file);
1591+
ovFile.loadOverlayModuleNames(ctx, moduleName, bystandingModule, SourceLoc());
1592+
llvm::SmallSetVector<Identifier, 4> result;
1593+
for (auto Id: ovFile.overlayModuleNames) {
1594+
result.insert(Id);
1595+
}
1596+
return result;
1597+
}
1598+
15801599
bool ModuleDecl::mightDeclareCrossImportOverlays() const {
15811600
return !declaredCrossImports.empty();
15821601
}
@@ -1803,15 +1822,15 @@ OverlayFileContents::load(std::unique_ptr<llvm::MemoryBuffer> input,
18031822
}
18041823

18051824
bool
1806-
OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
1807-
Identifier bystanderName) {
1808-
auto &ctx = M->getASTContext();
1825+
OverlayFile::loadOverlayModuleNames(ASTContext &ctx, StringRef module,
1826+
StringRef bystanderName,
1827+
SourceLoc diagLoc) {
18091828
llvm::vfs::FileSystem &fs = *ctx.SourceMgr.getFileSystem();
18101829

18111830
auto bufOrError = fs.getBufferForFile(filePath);
18121831
if (!bufOrError) {
18131832
ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
1814-
M->getName(), bystanderName,
1833+
module, bystanderName,
18151834
bufOrError.getError().message(), filePath);
18161835
return false;
18171836
}
@@ -1825,7 +1844,7 @@ OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
18251844

18261845
for (auto message : errorMessages)
18271846
ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
1828-
M->getName(), bystanderName, message, filePath);
1847+
module, bystanderName, message, filePath);
18291848
return false;
18301849
}
18311850

@@ -1839,6 +1858,15 @@ OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
18391858
return true;
18401859
}
18411860

1861+
bool
1862+
OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
1863+
Identifier bystanderName) {
1864+
return loadOverlayModuleNames(M->getASTContext(),
1865+
M->getName().str(),
1866+
bystanderName.str(),
1867+
diagLoc);
1868+
}
1869+
18421870
//===----------------------------------------------------------------------===//
18431871
// SourceFile Implementation
18441872
//===----------------------------------------------------------------------===//

lib/AST/ModuleLoader.cpp

Lines changed: 68 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,13 @@ DependencyTracker::getClangCollector() {
5959
return clangCollector;
6060
}
6161

62-
static bool findOverlayFilesInDirectory(SourceLoc diagLoc, StringRef path,
63-
ModuleDecl *module,
64-
DependencyTracker * const tracker) {
62+
static bool findOverlayFilesInDirectory(ASTContext &ctx, StringRef path,
63+
StringRef moduleName,
64+
SourceLoc diagLoc,
65+
llvm::function_ref<void(StringRef)> callback) {
6566
using namespace llvm::sys;
6667
using namespace file_types;
6768

68-
ASTContext &ctx = module->getASTContext();
6969
auto fs = ctx.SourceMgr.getFileSystem();
7070

7171
std::error_code error;
@@ -76,27 +76,23 @@ static bool findOverlayFilesInDirectory(SourceLoc diagLoc, StringRef path,
7676
if (lookupTypeForExtension(path::extension(file)) != TY_SwiftOverlayFile)
7777
continue;
7878

79-
module->addCrossImportOverlayFile(file);
80-
81-
// FIXME: Better to add it only if we load it.
82-
if (tracker)
83-
tracker->addDependency(file, module->isSystemModule());
79+
callback(file);
8480
}
8581

8682
if (error && error != std::errc::no_such_file_or_directory) {
8783
ctx.Diags.diagnose(diagLoc, diag::cannot_list_swiftcrossimport_dir,
88-
module->getName(), error.message(), path);
84+
moduleName, error.message(), path);
8985
}
9086
return !error;
9187
}
9288

93-
void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
94-
FileUnit *file) {
89+
static void findOverlayFilesInternal(ASTContext &ctx, StringRef moduleDefiningPath,
90+
StringRef moduleName,
91+
SourceLoc diagLoc,
92+
llvm::function_ref<void(StringRef)> callback) {
9593
using namespace llvm::sys;
9694
using namespace file_types;
97-
98-
auto &langOpts = module->getASTContext().LangOpts;
99-
95+
auto &langOpts = ctx.LangOpts;
10096
// This method constructs several paths to directories near the module and
10197
// scans them for .swiftoverlay files. These paths can be in various
10298
// directories and have a few different filenames at the end, but I'll
@@ -106,19 +102,17 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
106102
// /usr/lib/swift/FooKit.swiftmodule/x86_64-apple-macos.swiftinterface
107103

108104
// dirPath = /usr/lib/swift/FooKit.swiftmodule
109-
SmallString<64> dirPath{file->getModuleDefiningPath()};
110-
if (dirPath.empty())
111-
return;
105+
SmallString<64> dirPath{moduleDefiningPath};
112106

113107
// dirPath = /usr/lib/swift/
114108
path::remove_filename(dirPath);
115109

116110
// dirPath = /usr/lib/swift/FooKit.swiftcrossimport
117-
path::append(dirPath, file->getExportedModuleName());
111+
path::append(dirPath, moduleName);
118112
path::replace_extension(dirPath, getExtension(TY_SwiftCrossImportDir));
119113

120114
// Search for swiftoverlays that apply to all platforms.
121-
if (!findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker))
115+
if (!findOverlayFilesInDirectory(ctx, dirPath, moduleName, diagLoc, callback))
122116
// If we diagnosed an error, or we didn't find the directory at all, don't
123117
// bother trying the target-specific directories.
124118
return;
@@ -128,7 +122,7 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
128122
path::append(dirPath, moduleTriple.str());
129123

130124
// Search for swiftoverlays specific to the target triple's platform.
131-
findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker);
125+
findOverlayFilesInDirectory(ctx, dirPath, moduleName, diagLoc, callback);
132126

133127
// The rest of this handles target variant triples, which are only used for
134128
// certain MacCatalyst builds.
@@ -142,7 +136,59 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
142136
path::append(dirPath, moduleVariantTriple.str());
143137

144138
// Search for swiftoverlays specific to the target variant's platform.
145-
findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker);
139+
findOverlayFilesInDirectory(ctx, dirPath, moduleName, diagLoc, callback);
140+
}
141+
142+
void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
143+
FileUnit *file) {
144+
using namespace llvm::sys;
145+
using namespace file_types;
146+
147+
if (file->getModuleDefiningPath().empty())
148+
return;
149+
findOverlayFilesInternal(module->getASTContext(),
150+
file->getModuleDefiningPath(),
151+
module->getName().str(),
152+
diagLoc,
153+
[&](StringRef file) {
154+
module->addCrossImportOverlayFile(file);
155+
// FIXME: Better to add it only if we load it.
156+
if (dependencyTracker)
157+
dependencyTracker->addDependency(file, module->isSystemModule());
158+
});
146159
}
147160

161+
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>>
162+
ModuleDependencies::collectCrossImportOverlayNames(ASTContext &ctx,
163+
StringRef moduleName) {
164+
using namespace llvm::sys;
165+
using namespace file_types;
166+
Optional<std::string> modulePath;
167+
// Mimic getModuleDefiningPath() for Swift and Clang module.
168+
if (auto *swiftDep = dyn_cast<SwiftModuleDependenciesStorage>(storage.get())) {
169+
// Prefer interface path to binary module path if we have it.
170+
modulePath = swiftDep->swiftInterfaceFile;
171+
if (!modulePath.hasValue())
172+
modulePath = swiftDep->compiledModulePath;
173+
assert(modulePath.hasValue());
174+
StringRef parentDir = llvm::sys::path::parent_path(*modulePath);
175+
if (llvm::sys::path::extension(parentDir) == ".swiftmodule") {
176+
modulePath = parentDir.str();
177+
}
178+
} else {
179+
modulePath = cast<ClangModuleDependenciesStorage>(storage.get())->moduleMapFile;
180+
assert(modulePath.hasValue());
181+
}
182+
// A map from secondary module name to a vector of overlay names.
183+
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>> result;
184+
findOverlayFilesInternal(ctx, *modulePath, moduleName, SourceLoc(),
185+
[&](StringRef file) {
186+
StringRef bystandingModule;
187+
auto overlayNames =
188+
ModuleDecl::collectCrossImportOverlay(ctx, file, moduleName,
189+
bystandingModule);
190+
result[bystandingModule] = std::move(overlayNames);
191+
});
192+
return result;
193+
}
148194
} // namespace swift

lib/FrontendTool/ScanDependencies.cpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,38 @@ static std::vector<ModuleDependencyID> resolveDirectDependencies(
138138
}
139139
}
140140
}
141-
141+
// Only resolve cross-import overlays when this is the main module.
142+
// For other modules, these overlays are explicitly written.
143+
bool isMainModule =
144+
instance.getMainModule()->getName().str() == module.first &&
145+
module.second == ModuleDependenciesKind::Swift;
146+
if (isMainModule) {
147+
// Modules explicitly imported. Only these can be secondary module.
148+
std::vector<ModuleDependencyID> explicitImports = result;
149+
for (unsigned I = 0; I != result.size(); ++I) {
150+
auto dep = result[I];
151+
auto moduleName = dep.first;
152+
auto dependencies = *cache.findDependencies(moduleName, dep.second);
153+
// Collect a map from secondary module name to cross-import overlay names.
154+
auto overlayMap = dependencies.collectCrossImportOverlayNames(
155+
instance.getASTContext(), moduleName);
156+
if (overlayMap.empty())
157+
continue;
158+
std::for_each(explicitImports.begin(), explicitImports.end(),
159+
[&](ModuleDependencyID Id) {
160+
// check if any explicitly imported modules can serve as a secondary
161+
// module, and add the overlay names to the dependencies list.
162+
for (auto overlayName: overlayMap[Id.first]) {
163+
if (auto found = ctx.getModuleDependencies(overlayName.str(),
164+
/*onlyClangModule=*/false,
165+
cache,
166+
ASTDelegate)) {
167+
result.push_back({overlayName.str(), found->getKind()});
168+
}
169+
}
170+
});
171+
}
172+
}
142173
return result;
143174
}
144175

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
%YAML 1.2
2+
---
3+
version: 1
4+
modules:
5+
- name: _cross_import_E
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-module-flags: -module-name _cross_import_E
3+
import Swift
4+
import E
5+
import SubE
6+
public func funcCrossImportE() {}

test/ScanDependencies/module_deps.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ import SubE
8080
// CHECK-NEXT: {
8181
// CHECK-NEXT: "swift": "A"
8282
// CHECK-NEXT: }
83+
// CHECK-NEXT: {
84+
// CHECK-NEXT: "swift": "_cross_import_E"
85+
// CHECK-NEXT: }
8386

8487
// CHECK: "bridgingHeader":
8588
// CHECK-NEXT: "path":

0 commit comments

Comments
 (0)