Skip to content

Commit b70824c

Browse files
authored
Merge pull request #76321 from artemcm/PackageOnlyAdjacentScanFix
[Dependency Scanning] Query package-only dependencies from adjacent binary modules when necessary
2 parents 08e339b + 12e2fb6 commit b70824c

File tree

4 files changed

+120
-1
lines changed

4 files changed

+120
-1
lines changed

include/swift/Serialization/SerializedModuleLoader.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,18 @@ class SerializedModuleLoaderBase : public ModuleLoader {
179179
/// Load the module file into a buffer and also collect its module name.
180180
static std::unique_ptr<llvm::MemoryBuffer>
181181
getModuleName(ASTContext &Ctx, StringRef modulePath, std::string &Name);
182-
182+
183+
/// If the module has a package name matching the one
184+
/// specified, return a set of package-only imports for this module.
185+
static llvm::ErrorOr<llvm::StringSet<>>
186+
getMatchingPackageOnlyImportsOfModule(Twine modulePath,
187+
bool isFramework,
188+
bool isRequiredOSSAModules,
189+
StringRef SDKName,
190+
StringRef packageName,
191+
llvm::vfs::FileSystem *fileSystem,
192+
PathObfuscator &recoverer);
193+
183194
public:
184195
virtual ~SerializedModuleLoaderBase();
185196
SerializedModuleLoaderBase(const SerializedModuleLoaderBase &) = delete;

lib/Serialization/ScanningLoaders.cpp

+29
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
149149
StringRef sdkPath = Ctx.SearchPathOpts.getSDKPath();
150150
llvm::SmallString<32> modulePath = realModuleName.str();
151151
llvm::sys::path::replace_extension(modulePath, newExt);
152+
auto ScannerPackageName = Ctx.LangOpts.PackageName;
152153
std::optional<ModuleDependencyInfo> Result;
153154
std::error_code code = astDelegate.runInSubContext(
154155
realModuleName.str(), moduleInterfacePath.str(), sdkPath,
@@ -272,6 +273,34 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
272273
&alreadyAddedModules, &Ctx.SourceMgr);
273274
}
274275

276+
// If this is a dependency that belongs to the same package, and we have not yet enabled Package Textual interfaces,
277+
// scan the adjacent binary module for package dependencies.
278+
if (!ScannerPackageName.empty() &&
279+
!Ctx.LangOpts.EnablePackageInterfaceLoad) {
280+
auto adjacentBinaryModule = std::find_if(
281+
compiledCandidates.begin(), compiledCandidates.end(),
282+
[moduleInterfacePath](const std::string &candidate) {
283+
return llvm::sys::path::parent_path(candidate) ==
284+
llvm::sys::path::parent_path(moduleInterfacePath.str());
285+
});
286+
287+
if (adjacentBinaryModule != compiledCandidates.end()) {
288+
auto adjacentBinaryModulePackageOnlyImports = getMatchingPackageOnlyImportsOfModule(
289+
*adjacentBinaryModule, isFramework,
290+
isRequiredOSSAModules(), Ctx.LangOpts.SDKName,
291+
ScannerPackageName, Ctx.SourceMgr.getFileSystem().get(),
292+
Ctx.SearchPathOpts.DeserializedPathRecoverer);
293+
294+
if (!adjacentBinaryModulePackageOnlyImports)
295+
return adjacentBinaryModulePackageOnlyImports.getError();
296+
297+
for (const auto &requiredImport : *adjacentBinaryModulePackageOnlyImports)
298+
if (!alreadyAddedModules.contains(requiredImport.getKey()))
299+
Result->addModuleImport(requiredImport.getKey(),
300+
&alreadyAddedModules);
301+
}
302+
}
303+
275304
return std::error_code();
276305
});
277306

lib/Serialization/SerializedModuleLoader.cpp

+39
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,45 @@ SerializedModuleLoaderBase::getModuleName(ASTContext &Ctx, StringRef modulePath,
301301
return ModuleFile::getModuleName(Ctx, modulePath, Name);
302302
}
303303

304+
llvm::ErrorOr<llvm::StringSet<>>
305+
SerializedModuleLoaderBase::getMatchingPackageOnlyImportsOfModule(
306+
Twine modulePath, bool isFramework, bool isRequiredOSSAModules,
307+
StringRef SDKName, StringRef packageName, llvm::vfs::FileSystem *fileSystem,
308+
PathObfuscator &recoverer) {
309+
auto moduleBuf = fileSystem->getBufferForFile(modulePath);
310+
if (!moduleBuf)
311+
return moduleBuf.getError();
312+
313+
llvm::StringSet<> importedModuleNames;
314+
// Load the module file without validation.
315+
std::shared_ptr<const ModuleFileSharedCore> loadedModuleFile;
316+
serialization::ValidationInfo loadInfo = ModuleFileSharedCore::load(
317+
"", "", std::move(moduleBuf.get()), nullptr, nullptr, isFramework,
318+
isRequiredOSSAModules, SDKName, recoverer, loadedModuleFile);
319+
320+
if (loadedModuleFile->getModulePackageName() != packageName)
321+
return importedModuleNames;
322+
323+
for (const auto &dependency : loadedModuleFile->getDependencies()) {
324+
if (dependency.isHeader())
325+
continue;
326+
if (!dependency.isPackageOnly())
327+
continue;
328+
329+
// Find the top-level module name.
330+
auto modulePathStr = dependency.getPrettyPrintedPath();
331+
StringRef moduleName = modulePathStr;
332+
auto dotPos = moduleName.find('.');
333+
if (dotPos != std::string::npos)
334+
moduleName = moduleName.slice(0, dotPos);
335+
336+
importedModuleNames.insert(moduleName);
337+
}
338+
339+
return importedModuleNames;
340+
}
341+
342+
304343
std::error_code
305344
SerializedModuleLoaderBase::openModuleSourceInfoFileIfPresent(
306345
ImportPath::Element ModuleID,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// REQUIRES: executable_test
2+
// REQUIRES: objc_interop
3+
// RUN: %empty-directory(%t)
4+
// RUN: %empty-directory(%t/clang-module-cache)
5+
// RUN: %empty-directory(%t/Foo.swiftmodule)
6+
// RUN: %empty-directory(%t/Bar.swiftmodule)
7+
// RUN: split-file %s %t
8+
9+
// Step 1: build Bar swift interface and swift module side by side
10+
// 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
11+
12+
// Step 2: build Foo swift interface and swift module side by side belonging to package 'Test'
13+
// 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
14+
15+
// Step 3: scan dependencies with '-no-scanner-module-validation' and '-package-name Test'
16+
// 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
17+
// Step 4: Ensure that same-package scan can see package-only dependencies
18+
// RUN: %FileCheck %s --input-file=%t/deps.json --check-prefix CHECK-SAME-PACKAGE
19+
20+
// Step 5: scan dependencies with '-no-scanner-module-validation' and no package name
21+
// 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
22+
// Step 6: Ensure that non-same-package scan can not see package-only dependencies
23+
// RUN: %FileCheck %s --input-file=%t/deps_no_package.json --check-prefix CHECK-NO-PACKAGE
24+
25+
26+
// CHECK-SAME-PACKAGE: "swift": "Bar"
27+
// CHECK-NO-PACKAGE-NOT: "swift": "Bar"
28+
29+
//--- Bar.swift
30+
enum PubEnum {
31+
case red, green
32+
}
33+
34+
//--- Foo.swift
35+
package import Bar
36+
37+
//--- Client.swift
38+
import Foo
39+
40+

0 commit comments

Comments
 (0)