mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
DependenciesScanner: teach the scanner to handle cross-import overlays
This commit is contained in:
@@ -159,11 +159,11 @@ NOTE(circular_type_resolution_note,none,
|
|||||||
// MARK: Cross-import overlay loading diagnostics
|
// MARK: Cross-import overlay loading diagnostics
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
ERROR(cannot_load_swiftoverlay_file, none,
|
ERROR(cannot_load_swiftoverlay_file, none,
|
||||||
"cannot load cross-import overlay for %0 and %1: %2 (declared by '%3')",
|
"cannot load cross-import overlay for '%0' and '%1': %2 (declared by '%3')",
|
||||||
(Identifier, Identifier, StringRef, StringRef))
|
(StringRef, StringRef, StringRef, StringRef))
|
||||||
ERROR(cannot_list_swiftcrossimport_dir, none,
|
ERROR(cannot_list_swiftcrossimport_dir, none,
|
||||||
"cannot list cross-import overlays for %0: %1 (declared in '%2')",
|
"cannot list cross-import overlays for '%0': %1 (declared in '%2')",
|
||||||
(Identifier, StringRef, StringRef))
|
(StringRef, StringRef, StringRef))
|
||||||
WARNING(cross_imported_by_both_modules, none,
|
WARNING(cross_imported_by_both_modules, none,
|
||||||
"modules %0 and %1 both declare module %2 as a cross-import overlay, "
|
"modules %0 and %1 both declare module %2 as a cross-import overlay, "
|
||||||
"which may cause paradoxical behavior when looking up names in them; "
|
"which may cause paradoxical behavior when looking up names in them; "
|
||||||
|
|||||||
@@ -391,6 +391,11 @@ public:
|
|||||||
/// Add a file declaring a cross-import overlay.
|
/// Add a file declaring a cross-import overlay.
|
||||||
void addCrossImportOverlayFile(StringRef file);
|
void addCrossImportOverlayFile(StringRef file);
|
||||||
|
|
||||||
|
/// Collect cross-import overlay names from a given YAML file path.
|
||||||
|
static llvm::SmallSetVector<Identifier, 4>
|
||||||
|
collectCrossImportOverlay(ASTContext &ctx, StringRef file,
|
||||||
|
StringRef moduleName, StringRef& bystandingModule);
|
||||||
|
|
||||||
/// If this method returns \c false, the module does not declare any
|
/// If this method returns \c false, the module does not declare any
|
||||||
/// cross-import overlays.
|
/// cross-import overlays.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ namespace swift {
|
|||||||
|
|
||||||
class ClangModuleDependenciesCacheImpl;
|
class ClangModuleDependenciesCacheImpl;
|
||||||
class SourceFile;
|
class SourceFile;
|
||||||
|
class ASTContext;
|
||||||
|
class Identifier;
|
||||||
|
|
||||||
/// Which kind of module dependencies we are looking for.
|
/// Which kind of module dependencies we are looking for.
|
||||||
enum class ModuleDependenciesKind : int8_t {
|
enum class ModuleDependenciesKind : int8_t {
|
||||||
@@ -246,6 +248,11 @@ public:
|
|||||||
/// Add (Clang) module on which the bridging header depends.
|
/// Add (Clang) module on which the bridging header depends.
|
||||||
void addBridgingModuleDependency(StringRef module,
|
void addBridgingModuleDependency(StringRef module,
|
||||||
llvm::StringSet<> &alreadyAddedModules);
|
llvm::StringSet<> &alreadyAddedModules);
|
||||||
|
|
||||||
|
/// Collect a map from a secondary module name to a list of cross-import
|
||||||
|
/// overlays, when this current module serves as the primary module.
|
||||||
|
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>>
|
||||||
|
collectCrossImportOverlayNames(ASTContext &ctx, StringRef moduleName);
|
||||||
};
|
};
|
||||||
|
|
||||||
using ModuleDependencyID = std::pair<std::string, ModuleDependenciesKind>;
|
using ModuleDependencyID = std::pair<std::string, ModuleDependenciesKind>;
|
||||||
|
|||||||
@@ -1520,6 +1520,7 @@ const clang::Module *ModuleDecl::findUnderlyingClangModule() const {
|
|||||||
namespace swift {
|
namespace swift {
|
||||||
/// Represents a file containing information about cross-module overlays.
|
/// Represents a file containing information about cross-module overlays.
|
||||||
class OverlayFile {
|
class OverlayFile {
|
||||||
|
friend class ModuleDecl;
|
||||||
/// The file that data should be loaded from.
|
/// The file that data should be loaded from.
|
||||||
StringRef filePath;
|
StringRef filePath;
|
||||||
|
|
||||||
@@ -1536,7 +1537,10 @@ class OverlayFile {
|
|||||||
/// before returning.
|
/// before returning.
|
||||||
bool loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
|
bool loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
|
||||||
Identifier bystandingModule);
|
Identifier bystandingModule);
|
||||||
|
bool loadOverlayModuleNames(ASTContext &ctx,
|
||||||
|
StringRef module,
|
||||||
|
StringRef bystandingModule,
|
||||||
|
SourceLoc diagLoc);
|
||||||
public:
|
public:
|
||||||
// Only allocate in ASTContexts.
|
// Only allocate in ASTContexts.
|
||||||
void *operator new(size_t bytes) = delete;
|
void *operator new(size_t bytes) = delete;
|
||||||
@@ -1577,6 +1581,21 @@ void ModuleDecl::addCrossImportOverlayFile(StringRef file) {
|
|||||||
.push_back(new (ctx) OverlayFile(ctx.AllocateCopy(file)));
|
.push_back(new (ctx) OverlayFile(ctx.AllocateCopy(file)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::SmallSetVector<Identifier, 4>
|
||||||
|
ModuleDecl::collectCrossImportOverlay(ASTContext &ctx,
|
||||||
|
StringRef file,
|
||||||
|
StringRef moduleName,
|
||||||
|
StringRef &bystandingModule) {
|
||||||
|
OverlayFile ovFile(file);
|
||||||
|
bystandingModule = llvm::sys::path::stem(file);
|
||||||
|
ovFile.loadOverlayModuleNames(ctx, moduleName, bystandingModule, SourceLoc());
|
||||||
|
llvm::SmallSetVector<Identifier, 4> result;
|
||||||
|
for (auto Id: ovFile.overlayModuleNames) {
|
||||||
|
result.insert(Id);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
bool ModuleDecl::mightDeclareCrossImportOverlays() const {
|
bool ModuleDecl::mightDeclareCrossImportOverlays() const {
|
||||||
return !declaredCrossImports.empty();
|
return !declaredCrossImports.empty();
|
||||||
}
|
}
|
||||||
@@ -1803,15 +1822,15 @@ OverlayFileContents::load(std::unique_ptr<llvm::MemoryBuffer> input,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
|
OverlayFile::loadOverlayModuleNames(ASTContext &ctx, StringRef module,
|
||||||
Identifier bystanderName) {
|
StringRef bystanderName,
|
||||||
auto &ctx = M->getASTContext();
|
SourceLoc diagLoc) {
|
||||||
llvm::vfs::FileSystem &fs = *ctx.SourceMgr.getFileSystem();
|
llvm::vfs::FileSystem &fs = *ctx.SourceMgr.getFileSystem();
|
||||||
|
|
||||||
auto bufOrError = fs.getBufferForFile(filePath);
|
auto bufOrError = fs.getBufferForFile(filePath);
|
||||||
if (!bufOrError) {
|
if (!bufOrError) {
|
||||||
ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
|
ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
|
||||||
M->getName(), bystanderName,
|
module, bystanderName,
|
||||||
bufOrError.getError().message(), filePath);
|
bufOrError.getError().message(), filePath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1825,7 +1844,7 @@ OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
|
|||||||
|
|
||||||
for (auto message : errorMessages)
|
for (auto message : errorMessages)
|
||||||
ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
|
ctx.Diags.diagnose(diagLoc, diag::cannot_load_swiftoverlay_file,
|
||||||
M->getName(), bystanderName, message, filePath);
|
module, bystanderName, message, filePath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1839,6 +1858,15 @@ OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
OverlayFile::loadOverlayModuleNames(const ModuleDecl *M, SourceLoc diagLoc,
|
||||||
|
Identifier bystanderName) {
|
||||||
|
return loadOverlayModuleNames(M->getASTContext(),
|
||||||
|
M->getName().str(),
|
||||||
|
bystanderName.str(),
|
||||||
|
diagLoc);
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// SourceFile Implementation
|
// SourceFile Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|||||||
@@ -59,13 +59,13 @@ DependencyTracker::getClangCollector() {
|
|||||||
return clangCollector;
|
return clangCollector;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool findOverlayFilesInDirectory(SourceLoc diagLoc, StringRef path,
|
static bool findOverlayFilesInDirectory(ASTContext &ctx, StringRef path,
|
||||||
ModuleDecl *module,
|
StringRef moduleName,
|
||||||
DependencyTracker * const tracker) {
|
SourceLoc diagLoc,
|
||||||
|
llvm::function_ref<void(StringRef)> callback) {
|
||||||
using namespace llvm::sys;
|
using namespace llvm::sys;
|
||||||
using namespace file_types;
|
using namespace file_types;
|
||||||
|
|
||||||
ASTContext &ctx = module->getASTContext();
|
|
||||||
auto fs = ctx.SourceMgr.getFileSystem();
|
auto fs = ctx.SourceMgr.getFileSystem();
|
||||||
|
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
@@ -76,27 +76,23 @@ static bool findOverlayFilesInDirectory(SourceLoc diagLoc, StringRef path,
|
|||||||
if (lookupTypeForExtension(path::extension(file)) != TY_SwiftOverlayFile)
|
if (lookupTypeForExtension(path::extension(file)) != TY_SwiftOverlayFile)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
module->addCrossImportOverlayFile(file);
|
callback(file);
|
||||||
|
|
||||||
// FIXME: Better to add it only if we load it.
|
|
||||||
if (tracker)
|
|
||||||
tracker->addDependency(file, module->isSystemModule());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error && error != std::errc::no_such_file_or_directory) {
|
if (error && error != std::errc::no_such_file_or_directory) {
|
||||||
ctx.Diags.diagnose(diagLoc, diag::cannot_list_swiftcrossimport_dir,
|
ctx.Diags.diagnose(diagLoc, diag::cannot_list_swiftcrossimport_dir,
|
||||||
module->getName(), error.message(), path);
|
moduleName, error.message(), path);
|
||||||
}
|
}
|
||||||
return !error;
|
return !error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
|
static void findOverlayFilesInternal(ASTContext &ctx, StringRef moduleDefiningPath,
|
||||||
FileUnit *file) {
|
StringRef moduleName,
|
||||||
|
SourceLoc diagLoc,
|
||||||
|
llvm::function_ref<void(StringRef)> callback) {
|
||||||
using namespace llvm::sys;
|
using namespace llvm::sys;
|
||||||
using namespace file_types;
|
using namespace file_types;
|
||||||
|
auto &langOpts = ctx.LangOpts;
|
||||||
auto &langOpts = module->getASTContext().LangOpts;
|
|
||||||
|
|
||||||
// This method constructs several paths to directories near the module and
|
// This method constructs several paths to directories near the module and
|
||||||
// scans them for .swiftoverlay files. These paths can be in various
|
// scans them for .swiftoverlay files. These paths can be in various
|
||||||
// directories and have a few different filenames at the end, but I'll
|
// directories and have a few different filenames at the end, but I'll
|
||||||
@@ -106,19 +102,17 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
|
|||||||
// /usr/lib/swift/FooKit.swiftmodule/x86_64-apple-macos.swiftinterface
|
// /usr/lib/swift/FooKit.swiftmodule/x86_64-apple-macos.swiftinterface
|
||||||
|
|
||||||
// dirPath = /usr/lib/swift/FooKit.swiftmodule
|
// dirPath = /usr/lib/swift/FooKit.swiftmodule
|
||||||
SmallString<64> dirPath{file->getModuleDefiningPath()};
|
SmallString<64> dirPath{moduleDefiningPath};
|
||||||
if (dirPath.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// dirPath = /usr/lib/swift/
|
// dirPath = /usr/lib/swift/
|
||||||
path::remove_filename(dirPath);
|
path::remove_filename(dirPath);
|
||||||
|
|
||||||
// dirPath = /usr/lib/swift/FooKit.swiftcrossimport
|
// dirPath = /usr/lib/swift/FooKit.swiftcrossimport
|
||||||
path::append(dirPath, file->getExportedModuleName());
|
path::append(dirPath, moduleName);
|
||||||
path::replace_extension(dirPath, getExtension(TY_SwiftCrossImportDir));
|
path::replace_extension(dirPath, getExtension(TY_SwiftCrossImportDir));
|
||||||
|
|
||||||
// Search for swiftoverlays that apply to all platforms.
|
// Search for swiftoverlays that apply to all platforms.
|
||||||
if (!findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker))
|
if (!findOverlayFilesInDirectory(ctx, dirPath, moduleName, diagLoc, callback))
|
||||||
// If we diagnosed an error, or we didn't find the directory at all, don't
|
// If we diagnosed an error, or we didn't find the directory at all, don't
|
||||||
// bother trying the target-specific directories.
|
// bother trying the target-specific directories.
|
||||||
return;
|
return;
|
||||||
@@ -128,7 +122,7 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
|
|||||||
path::append(dirPath, moduleTriple.str());
|
path::append(dirPath, moduleTriple.str());
|
||||||
|
|
||||||
// Search for swiftoverlays specific to the target triple's platform.
|
// Search for swiftoverlays specific to the target triple's platform.
|
||||||
findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker);
|
findOverlayFilesInDirectory(ctx, dirPath, moduleName, diagLoc, callback);
|
||||||
|
|
||||||
// The rest of this handles target variant triples, which are only used for
|
// The rest of this handles target variant triples, which are only used for
|
||||||
// certain MacCatalyst builds.
|
// certain MacCatalyst builds.
|
||||||
@@ -142,7 +136,59 @@ void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
|
|||||||
path::append(dirPath, moduleVariantTriple.str());
|
path::append(dirPath, moduleVariantTriple.str());
|
||||||
|
|
||||||
// Search for swiftoverlays specific to the target variant's platform.
|
// Search for swiftoverlays specific to the target variant's platform.
|
||||||
findOverlayFilesInDirectory(diagLoc, dirPath, module, dependencyTracker);
|
findOverlayFilesInDirectory(ctx, dirPath, moduleName, diagLoc, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModuleLoader::findOverlayFiles(SourceLoc diagLoc, ModuleDecl *module,
|
||||||
|
FileUnit *file) {
|
||||||
|
using namespace llvm::sys;
|
||||||
|
using namespace file_types;
|
||||||
|
|
||||||
|
if (file->getModuleDefiningPath().empty())
|
||||||
|
return;
|
||||||
|
findOverlayFilesInternal(module->getASTContext(),
|
||||||
|
file->getModuleDefiningPath(),
|
||||||
|
module->getName().str(),
|
||||||
|
diagLoc,
|
||||||
|
[&](StringRef file) {
|
||||||
|
module->addCrossImportOverlayFile(file);
|
||||||
|
// FIXME: Better to add it only if we load it.
|
||||||
|
if (dependencyTracker)
|
||||||
|
dependencyTracker->addDependency(file, module->isSystemModule());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>>
|
||||||
|
ModuleDependencies::collectCrossImportOverlayNames(ASTContext &ctx,
|
||||||
|
StringRef moduleName) {
|
||||||
|
using namespace llvm::sys;
|
||||||
|
using namespace file_types;
|
||||||
|
Optional<std::string> modulePath;
|
||||||
|
// Mimic getModuleDefiningPath() for Swift and Clang module.
|
||||||
|
if (auto *swiftDep = dyn_cast<SwiftModuleDependenciesStorage>(storage.get())) {
|
||||||
|
// Prefer interface path to binary module path if we have it.
|
||||||
|
modulePath = swiftDep->swiftInterfaceFile;
|
||||||
|
if (!modulePath.hasValue())
|
||||||
|
modulePath = swiftDep->compiledModulePath;
|
||||||
|
assert(modulePath.hasValue());
|
||||||
|
StringRef parentDir = llvm::sys::path::parent_path(*modulePath);
|
||||||
|
if (llvm::sys::path::extension(parentDir) == ".swiftmodule") {
|
||||||
|
modulePath = parentDir.str();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
modulePath = cast<ClangModuleDependenciesStorage>(storage.get())->moduleMapFile;
|
||||||
|
assert(modulePath.hasValue());
|
||||||
|
}
|
||||||
|
// A map from secondary module name to a vector of overlay names.
|
||||||
|
llvm::StringMap<llvm::SmallSetVector<Identifier, 4>> result;
|
||||||
|
findOverlayFilesInternal(ctx, *modulePath, moduleName, SourceLoc(),
|
||||||
|
[&](StringRef file) {
|
||||||
|
StringRef bystandingModule;
|
||||||
|
auto overlayNames =
|
||||||
|
ModuleDecl::collectCrossImportOverlay(ctx, file, moduleName,
|
||||||
|
bystandingModule);
|
||||||
|
result[bystandingModule] = std::move(overlayNames);
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
} // namespace swift
|
} // namespace swift
|
||||||
|
|||||||
@@ -138,7 +138,38 @@ static std::vector<ModuleDependencyID> resolveDirectDependencies(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Only resolve cross-import overlays when this is the main module.
|
||||||
|
// For other modules, these overlays are explicitly written.
|
||||||
|
bool isMainModule =
|
||||||
|
instance.getMainModule()->getName().str() == module.first &&
|
||||||
|
module.second == ModuleDependenciesKind::Swift;
|
||||||
|
if (isMainModule) {
|
||||||
|
// Modules explicitly imported. Only these can be secondary module.
|
||||||
|
std::vector<ModuleDependencyID> explicitImports = result;
|
||||||
|
for (unsigned I = 0; I != result.size(); ++I) {
|
||||||
|
auto dep = result[I];
|
||||||
|
auto moduleName = dep.first;
|
||||||
|
auto dependencies = *cache.findDependencies(moduleName, dep.second);
|
||||||
|
// Collect a map from secondary module name to cross-import overlay names.
|
||||||
|
auto overlayMap = dependencies.collectCrossImportOverlayNames(
|
||||||
|
instance.getASTContext(), moduleName);
|
||||||
|
if (overlayMap.empty())
|
||||||
|
continue;
|
||||||
|
std::for_each(explicitImports.begin(), explicitImports.end(),
|
||||||
|
[&](ModuleDependencyID Id) {
|
||||||
|
// check if any explicitly imported modules can serve as a secondary
|
||||||
|
// module, and add the overlay names to the dependencies list.
|
||||||
|
for (auto overlayName: overlayMap[Id.first]) {
|
||||||
|
if (auto found = ctx.getModuleDependencies(overlayName.str(),
|
||||||
|
/*onlyClangModule=*/false,
|
||||||
|
cache,
|
||||||
|
ASTDelegate)) {
|
||||||
|
result.push_back({overlayName.str(), found->getKind()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
version: 1
|
||||||
|
modules:
|
||||||
|
- name: _cross_import_E
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// swift-interface-format-version: 1.0
|
||||||
|
// swift-module-flags: -module-name _cross_import_E
|
||||||
|
import Swift
|
||||||
|
import E
|
||||||
|
import SubE
|
||||||
|
public func funcCrossImportE() {}
|
||||||
@@ -80,6 +80,9 @@ import SubE
|
|||||||
// CHECK-NEXT: {
|
// CHECK-NEXT: {
|
||||||
// CHECK-NEXT: "swift": "A"
|
// CHECK-NEXT: "swift": "A"
|
||||||
// CHECK-NEXT: }
|
// CHECK-NEXT: }
|
||||||
|
// CHECK-NEXT: {
|
||||||
|
// CHECK-NEXT: "swift": "_cross_import_E"
|
||||||
|
// CHECK-NEXT: }
|
||||||
|
|
||||||
// CHECK: "bridgingHeader":
|
// CHECK: "bridgingHeader":
|
||||||
// CHECK-NEXT: "path":
|
// CHECK-NEXT: "path":
|
||||||
|
|||||||
Reference in New Issue
Block a user