mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Dependency Scanning] Query package-only dependencies from adjacent binary modules when necessary
When '.package.swiftinterface' loading ('-experimental-package-interface-load') is disabled and when '-scanner-module-validation' is disabled, the scanner defaults to locating the non-package textual interface and may specify its adjacent binary module as a valid candidate binary module to use. If said candidate is up-to-date and ends up getting used, and belongs to the same package as the loading Swift source, then the source compilation may attempt to load its package-only dependencies. Since the scanner only parsed the non-package textual interface, those dependencies are not located and specified as inputs to compilation. This change causes the scanner, in such cases, to also lookup package-only dependencies in adjacent binary Swift modules of textual Swift module dependencies, if such dependency belongs to the same package as the source target being scanned.
Resolves rdar://135215789
This commit is contained in:
@@ -179,7 +179,18 @@ protected:
|
||||
/// Load the module file into a buffer and also collect its module name.
|
||||
static std::unique_ptr<llvm::MemoryBuffer>
|
||||
getModuleName(ASTContext &Ctx, StringRef modulePath, std::string &Name);
|
||||
|
||||
|
||||
/// If the module has a package name matching the one
|
||||
/// specified, return a set of package-only imports for this module.
|
||||
static llvm::ErrorOr<llvm::StringSet<>>
|
||||
getMatchingPackageOnlyImportsOfModule(Twine modulePath,
|
||||
bool isFramework,
|
||||
bool isRequiredOSSAModules,
|
||||
StringRef SDKName,
|
||||
StringRef packageName,
|
||||
llvm::vfs::FileSystem *fileSystem,
|
||||
PathObfuscator &recoverer);
|
||||
|
||||
public:
|
||||
virtual ~SerializedModuleLoaderBase();
|
||||
SerializedModuleLoaderBase(const SerializedModuleLoaderBase &) = delete;
|
||||
|
||||
@@ -149,6 +149,7 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
|
||||
StringRef sdkPath = Ctx.SearchPathOpts.getSDKPath();
|
||||
llvm::SmallString<32> modulePath = realModuleName.str();
|
||||
llvm::sys::path::replace_extension(modulePath, newExt);
|
||||
auto ScannerPackageName = Ctx.LangOpts.PackageName;
|
||||
std::optional<ModuleDependencyInfo> Result;
|
||||
std::error_code code = astDelegate.runInSubContext(
|
||||
realModuleName.str(), moduleInterfacePath.str(), sdkPath,
|
||||
@@ -272,6 +273,34 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
|
||||
&alreadyAddedModules, &Ctx.SourceMgr);
|
||||
}
|
||||
|
||||
// If this is a dependency that belongs to the same package, and we have not yet enabled Package Textual interfaces,
|
||||
// scan the adjacent binary module for package dependencies.
|
||||
if (!ScannerPackageName.empty() &&
|
||||
!Ctx.LangOpts.EnablePackageInterfaceLoad) {
|
||||
auto adjacentBinaryModule = std::find_if(
|
||||
compiledCandidates.begin(), compiledCandidates.end(),
|
||||
[moduleInterfacePath](const std::string &candidate) {
|
||||
return llvm::sys::path::parent_path(candidate) ==
|
||||
llvm::sys::path::parent_path(moduleInterfacePath.str());
|
||||
});
|
||||
|
||||
if (adjacentBinaryModule != compiledCandidates.end()) {
|
||||
auto adjacentBinaryModulePackageOnlyImports = getMatchingPackageOnlyImportsOfModule(
|
||||
*adjacentBinaryModule, isFramework,
|
||||
isRequiredOSSAModules(), Ctx.LangOpts.SDKName,
|
||||
ScannerPackageName, Ctx.SourceMgr.getFileSystem().get(),
|
||||
Ctx.SearchPathOpts.DeserializedPathRecoverer);
|
||||
|
||||
if (!adjacentBinaryModulePackageOnlyImports)
|
||||
return adjacentBinaryModulePackageOnlyImports.getError();
|
||||
|
||||
for (const auto &requiredImport : *adjacentBinaryModulePackageOnlyImports)
|
||||
if (!alreadyAddedModules.contains(requiredImport.getKey()))
|
||||
Result->addModuleImport(requiredImport.getKey(),
|
||||
&alreadyAddedModules);
|
||||
}
|
||||
}
|
||||
|
||||
return std::error_code();
|
||||
});
|
||||
|
||||
|
||||
@@ -301,6 +301,45 @@ SerializedModuleLoaderBase::getModuleName(ASTContext &Ctx, StringRef modulePath,
|
||||
return ModuleFile::getModuleName(Ctx, modulePath, Name);
|
||||
}
|
||||
|
||||
llvm::ErrorOr<llvm::StringSet<>>
|
||||
SerializedModuleLoaderBase::getMatchingPackageOnlyImportsOfModule(
|
||||
Twine modulePath, bool isFramework, bool isRequiredOSSAModules,
|
||||
StringRef SDKName, StringRef packageName, llvm::vfs::FileSystem *fileSystem,
|
||||
PathObfuscator &recoverer) {
|
||||
auto moduleBuf = fileSystem->getBufferForFile(modulePath);
|
||||
if (!moduleBuf)
|
||||
return moduleBuf.getError();
|
||||
|
||||
llvm::StringSet<> importedModuleNames;
|
||||
// Load the module file without validation.
|
||||
std::shared_ptr<const ModuleFileSharedCore> loadedModuleFile;
|
||||
serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(
|
||||
"", "", std::move(moduleBuf.get()), nullptr, nullptr, isFramework,
|
||||
isRequiredOSSAModules, SDKName, recoverer, loadedModuleFile);
|
||||
|
||||
if (loadedModuleFile->getModulePackageName() != packageName)
|
||||
return importedModuleNames;
|
||||
|
||||
for (const auto &dependency : loadedModuleFile->getDependencies()) {
|
||||
if (dependency.isHeader())
|
||||
continue;
|
||||
if (!dependency.isPackageOnly())
|
||||
continue;
|
||||
|
||||
// Find the top-level module name.
|
||||
auto modulePathStr = dependency.getPrettyPrintedPath();
|
||||
StringRef moduleName = modulePathStr;
|
||||
auto dotPos = moduleName.find('.');
|
||||
if (dotPos != std::string::npos)
|
||||
moduleName = moduleName.slice(0, dotPos);
|
||||
|
||||
importedModuleNames.insert(moduleName);
|
||||
}
|
||||
|
||||
return importedModuleNames;
|
||||
}
|
||||
|
||||
|
||||
std::error_code
|
||||
SerializedModuleLoaderBase::openModuleSourceInfoFileIfPresent(
|
||||
ImportPath::Element ModuleID,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// REQUIRES: executable_test
|
||||
// REQUIRES: objc_interop
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %empty-directory(%t/clang-module-cache)
|
||||
// RUN: %empty-directory(%t/Foo.swiftmodule)
|
||||
// RUN: %empty-directory(%t/Bar.swiftmodule)
|
||||
// RUN: split-file %s %t
|
||||
|
||||
// Step 1: build Bar swift interface and swift module side by side
|
||||
// RUN: %target-swift-frontend -emit-module %t/Bar.swift -emit-module-path %t/Bar.swiftmodule/%target-swiftmodule-name -module-name Bar -emit-module-interface-path %t/Bar.swiftmodule/%target-swiftinterface-name -I %S/Inputs/CHeaders -I %S/Inputs/Swift
|
||||
|
||||
// Step 2: build Foo swift interface and swift module side by side belonging to package 'Test'
|
||||
// RUN: %target-swift-frontend -emit-module %t/Foo.swift -emit-module-path %t/Foo.swiftmodule/%target-swiftmodule-name -module-name Foo -emit-module-interface-path %t/Foo.swiftmodule/%target-swiftinterface-name -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %t -package-name Test
|
||||
|
||||
// Step 3: scan dependencies with '-no-scanner-module-validation' and '-package-name Test'
|
||||
// RUN: %target-swift-frontend -scan-dependencies %t/Client.swift -o %t/deps.json -no-scanner-module-validation -I %t -sdk %t -prebuilt-module-cache-path %t/clang-module-cache -I %S/Inputs/CHeaders -I %S/Inputs/Swift -package-name Test
|
||||
// Step 4: Ensure that same-package scan can see package-only dependencies
|
||||
// RUN: %FileCheck %s --input-file=%t/deps.json --check-prefix CHECK-SAME-PACKAGE
|
||||
|
||||
// Step 5: scan dependencies with '-no-scanner-module-validation' and no package name
|
||||
// RUN: %target-swift-frontend -scan-dependencies %t/Client.swift -o %t/deps_no_package.json -no-scanner-module-validation -I %t -sdk %t -prebuilt-module-cache-path %t/clang-module-cache -I %S/Inputs/CHeaders -I %S/Inputs/Swift
|
||||
// Step 6: Ensure that non-same-package scan can not see package-only dependencies
|
||||
// RUN: %FileCheck %s --input-file=%t/deps_no_package.json --check-prefix CHECK-NO-PACKAGE
|
||||
|
||||
|
||||
// CHECK-SAME-PACKAGE: "swift": "Bar"
|
||||
// CHECK-NO-PACKAGE-NOT: "swift": "Bar"
|
||||
|
||||
//--- Bar.swift
|
||||
enum PubEnum {
|
||||
case red, green
|
||||
}
|
||||
|
||||
//--- Foo.swift
|
||||
package import Bar
|
||||
|
||||
//--- Client.swift
|
||||
import Foo
|
||||
|
||||
|
||||
Reference in New Issue
Block a user