Skip to content

Commit 8682ed3

Browse files
authored
Merge pull request #82934 from artemcm/DepScanExplicitInput
[Dependency Scanning] Consider `-swift-module-file` inputs when looking for dependencies
2 parents e9c5542 + bd14089 commit 8682ed3

File tree

10 files changed

+126
-24
lines changed

10 files changed

+126
-24
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ ERROR(error_stdlib_module_name,none,
211211
"module name \"%0\" is reserved for the standard library"
212212
"%select{|; use -module-name flag to specify an alternate name}1",
213213
(StringRef, bool))
214+
WARNING(warn_multiple_module_inputs_same_name,none,
215+
"multiple Swift module file inputs with identifier \"%0\": replacing '%1' with '%2'",
216+
(StringRef, StringRef, StringRef))
214217

215218
ERROR(error_bad_export_as_name,none,
216219
"export-as name \"%0\" is not a valid identifier",

include/swift/AST/SearchPathOptions.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -518,11 +518,8 @@ class SearchPathOptions {
518518
std::string ExplicitSwiftModuleMapPath;
519519

520520
/// Module inputs specified with -swift-module-input,
521-
/// <ModuleName, Path to .swiftmodule file>
522-
std::vector<std::pair<std::string, std::string>> ExplicitSwiftModuleInputs;
523-
524-
/// A map of placeholder Swift module dependency information.
525-
std::string PlaceholderDependencyModuleMap;
521+
/// ModuleName: Path to .swiftmodule file
522+
llvm::StringMap<std::string> ExplicitSwiftModuleInputs;
526523

527524
/// A file containing a list of protocols whose conformances require const value extraction.
528525
std::string ConstGatherProtocolListFilePath;

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase {
176176
create(ASTContext &ctx,
177177
DependencyTracker *tracker, ModuleLoadingMode loadMode,
178178
StringRef ExplicitSwiftModuleMap,
179-
const std::vector<std::pair<std::string, std::string>> &ExplicitSwiftModuleInputs,
179+
const llvm::StringMap<std::string> &ExplicitSwiftModuleInputs,
180180
bool IgnoreSwiftSourceInfoFile);
181181

182182
/// Append visible module names to \p names. Note that names are possibly
@@ -224,8 +224,7 @@ class ExplicitCASModuleLoader : public SerializedModuleLoaderBase {
224224
create(ASTContext &ctx, llvm::cas::ObjectStore &CAS,
225225
llvm::cas::ActionCache &cache, DependencyTracker *tracker,
226226
ModuleLoadingMode loadMode, StringRef ExplicitSwiftModuleMap,
227-
const std::vector<std::pair<std::string, std::string>>
228-
&ExplicitSwiftModuleInputs,
227+
const llvm::StringMap<std::string> &ExplicitSwiftModuleInputs,
229228
bool IgnoreSwiftSourceInfoFile);
230229

231230
/// Append visible module names to \p names. Note that names are possibly

include/swift/Serialization/ScanningLoaders.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase {
6666
bool SkipBuildingInterface, bool IsFramework,
6767
bool IsTestableDependencyLookup) override;
6868

69+
bool canImportModule(ImportPath::Module named, SourceLoc loc,
70+
ModuleVersionInfo *versionInfo,
71+
bool isTestableImport) override;
72+
6973
virtual void collectVisibleTopLevelModuleNames(
7074
SmallVectorImpl<Identifier> &names) const override {
7175
llvm_unreachable("Not used");
@@ -80,6 +84,9 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase {
8084
/// Clang-specific (-Xcc) command-line flags to include on
8185
/// Swift module compilation commands
8286
std::vector<std::string> swiftModuleClangCC1CommandLineArgs;
87+
/// Module inputs specified with -swift-module-input,
88+
/// <ModuleName, Path to .swiftmodule file>
89+
llvm::StringMap<std::string> explicitSwiftModuleInputs;
8390

8491
/// Constituents of a result of a given Swift module query,
8592
/// reset at the end of every query.
@@ -91,12 +98,14 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase {
9198
ASTContext &ctx, ModuleLoadingMode LoadMode,
9299
InterfaceSubContextDelegate &astDelegate, StringRef moduleOutputPath,
93100
StringRef sdkModuleOutputPath,
94-
std::vector<std::string> swiftModuleClangCC1CommandLineArgs)
101+
std::vector<std::string> swiftModuleClangCC1CommandLineArgs,
102+
llvm::StringMap<std::string> &explicitSwiftModuleInputs)
95103
: SerializedModuleLoaderBase(ctx, nullptr, LoadMode,
96104
/*IgnoreSwiftSourceInfoFile=*/true),
97105
astDelegate(astDelegate), moduleOutputPath(moduleOutputPath),
98106
sdkModuleOutputPath(sdkModuleOutputPath),
99-
swiftModuleClangCC1CommandLineArgs(swiftModuleClangCC1CommandLineArgs) {
107+
swiftModuleClangCC1CommandLineArgs(swiftModuleClangCC1CommandLineArgs),
108+
explicitSwiftModuleInputs(explicitSwiftModuleInputs) {
100109
}
101110

102111
/// Perform a filesystem search for a Swift module with a given name

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,8 @@ ModuleDependencyScanningWorker::ModuleDependencyScanningWorker(
294294
*workerASTContext,
295295
workerCompilerInvocation->getSearchPathOptions().ModuleLoadMode,
296296
*scanningASTDelegate, moduleOutputPath, sdkModuleOutputPath,
297-
swiftModuleClangCC1CommandLineArgs);
297+
swiftModuleClangCC1CommandLineArgs,
298+
workerCompilerInvocation->getSearchPathOptions().ExplicitSwiftModuleInputs);
298299
}
299300

300301
SwiftModuleScannerQueryResult

lib/Frontend/CompilerInvocation.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2297,7 +2297,7 @@ static void ParseSymbolGraphArgs(symbolgraphgen::SymbolGraphOptions &Opts,
22972297

22982298
static bool validateSwiftModuleFileArgumentAndAdd(const std::string &swiftModuleArgument,
22992299
DiagnosticEngine &Diags,
2300-
std::vector<std::pair<std::string, std::string>> &ExplicitSwiftModuleInputs) {
2300+
llvm::StringMap<std::string> &ExplicitSwiftModuleInputs) {
23012301
std::size_t foundDelimeterPos = swiftModuleArgument.find_first_of("=");
23022302
if (foundDelimeterPos == std::string::npos) {
23032303
Diags.diagnose(SourceLoc(), diag::error_swift_module_file_requires_delimeter,
@@ -2310,7 +2310,15 @@ static bool validateSwiftModuleFileArgumentAndAdd(const std::string &swiftModule
23102310
Diags.diagnose(SourceLoc(), diag::error_bad_module_name, moduleName, false);
23112311
return true;
23122312
}
2313-
ExplicitSwiftModuleInputs.emplace_back(std::make_pair(moduleName, modulePath));
2313+
2314+
auto priorEntryIt = ExplicitSwiftModuleInputs.find(moduleName);
2315+
if (priorEntryIt != ExplicitSwiftModuleInputs.end()) {
2316+
Diags.diagnose(SourceLoc(), diag::warn_multiple_module_inputs_same_name,
2317+
moduleName, priorEntryIt->getValue(), modulePath);
2318+
ExplicitSwiftModuleInputs[moduleName] = modulePath;
2319+
} else
2320+
ExplicitSwiftModuleInputs.insert(std::make_pair(moduleName, modulePath));
2321+
23142322
return false;
23152323
}
23162324

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2246,11 +2246,10 @@ struct ExplicitSwiftModuleLoader::Implementation {
22462246
}
22472247

22482248
void addCommandLineExplicitInputs(
2249-
const std::vector<std::pair<std::string, std::string>>
2250-
&commandLineExplicitInputs) {
2249+
const llvm::StringMap<std::string> &commandLineExplicitInputs) {
22512250
for (const auto &moduleInput : commandLineExplicitInputs) {
2252-
ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}, {});
2253-
ExplicitModuleMap.try_emplace(moduleInput.first, std::move(entry));
2251+
ExplicitSwiftModuleInputInfo entry(moduleInput.getValue(), {}, {}, {});
2252+
ExplicitModuleMap.try_emplace(moduleInput.first(), std::move(entry));
22542253
}
22552254
}
22562255
};
@@ -2422,7 +2421,7 @@ std::unique_ptr<ExplicitSwiftModuleLoader>
24222421
ExplicitSwiftModuleLoader::create(ASTContext &ctx,
24232422
DependencyTracker *tracker, ModuleLoadingMode loadMode,
24242423
StringRef ExplicitSwiftModuleMap,
2425-
const std::vector<std::pair<std::string, std::string>> &ExplicitSwiftModuleInputs,
2424+
const llvm::StringMap<std::string> &ExplicitSwiftModuleInputs,
24262425
bool IgnoreSwiftSourceInfoFile) {
24272426
auto result = std::unique_ptr<ExplicitSwiftModuleLoader>(
24282427
new ExplicitSwiftModuleLoader(ctx, tracker, loadMode,
@@ -2536,11 +2535,10 @@ struct ExplicitCASModuleLoader::Implementation {
25362535
}
25372536

25382537
void addCommandLineExplicitInputs(
2539-
const std::vector<std::pair<std::string, std::string>>
2540-
&commandLineExplicitInputs) {
2538+
const llvm::StringMap<std::string> &commandLineExplicitInputs) {
25412539
for (const auto &moduleInput : commandLineExplicitInputs) {
2542-
ExplicitSwiftModuleInputInfo entry(moduleInput.second, {}, {}, {});
2543-
ExplicitModuleMap.try_emplace(moduleInput.first, std::move(entry));
2540+
ExplicitSwiftModuleInputInfo entry(moduleInput.getValue(), {}, {}, {});
2541+
ExplicitModuleMap.try_emplace(moduleInput.getKey(), std::move(entry));
25442542
}
25452543
}
25462544

@@ -2777,8 +2775,7 @@ std::unique_ptr<ExplicitCASModuleLoader> ExplicitCASModuleLoader::create(
27772775
ASTContext &ctx, llvm::cas::ObjectStore &CAS, llvm::cas::ActionCache &cache,
27782776
DependencyTracker *tracker, ModuleLoadingMode loadMode,
27792777
StringRef ExplicitSwiftModuleMap,
2780-
const std::vector<std::pair<std::string, std::string>>
2781-
&ExplicitSwiftModuleInputs,
2778+
const llvm::StringMap<std::string> &ExplicitSwiftModuleInputs,
27822779
bool IgnoreSwiftSourceInfoFile) {
27832780
auto result =
27842781
std::unique_ptr<ExplicitCASModuleLoader>(new ExplicitCASModuleLoader(

lib/Serialization/ScanningLoaders.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,30 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory(
8383
return dependencyInfo.getError();
8484
}
8585

86+
bool SwiftModuleScanner::canImportModule(
87+
ImportPath::Module path, SourceLoc loc, ModuleVersionInfo *versionInfo,
88+
bool isTestableDependencyLookup) {
89+
if (path.hasSubmodule())
90+
return false;
91+
92+
// Check explicitly-provided Swift modules with '-swift-module-file'
93+
ImportPath::Element mID = path.front();
94+
auto it =
95+
explicitSwiftModuleInputs.find(Ctx.getRealModuleName(mID.Item).str());
96+
if (it != explicitSwiftModuleInputs.end()) {
97+
auto dependencyInfo = scanBinaryModuleFile(
98+
mID.Item, it->getValue(), /* isFramework */ false,
99+
isTestableDependencyLookup, /* isCandidateForTextualModule */ false);
100+
if (dependencyInfo) {
101+
this->foundDependencyInfo = std::move(dependencyInfo.get());
102+
return true;
103+
}
104+
}
105+
106+
return SerializedModuleLoaderBase::canImportModule(
107+
path, loc, versionInfo, isTestableDependencyLookup);
108+
}
109+
86110
static std::vector<std::string> getCompiledCandidates(ASTContext &ctx,
87111
StringRef moduleName,
88112
StringRef interfacePath) {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/module-cache)
3+
// RUN: %empty-directory(%t/Inputs/Foo.swiftmodule)
4+
// RUN: split-file %s %t
5+
6+
// Step 1: build swift interface and swift module side by side
7+
// RUN: %target-swift-frontend -emit-module %t/Foo.swift -emit-module-path %t/Inputs/Foo.swiftmodule/%target-swiftmodule-name -module-name Foo -user-module-version 22
8+
9+
// Step 2: scan dependency should give us the binary module we specify with 'swift-module-file'
10+
// RUN: %target-swift-frontend -scan-dependencies %t/test.swift -o %t/deps.json -scanner-module-validation -swift-module-file=Foo=%t/Inputs/Foo.swiftmodule/%target-swiftmodule-name
11+
// RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=CHECK-INPUT
12+
13+
// Step 3: ensure that versioned canImport still applies with direct -swift-module-file
14+
// RUN: %target-swift-frontend -scan-dependencies %t/test_too_new.swift -o %t/deps.json -scanner-module-validation -swift-module-file=Foo=%t/Inputs/Foo.swiftmodule/%target-swiftmodule-name
15+
// RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=CHECK-MISSING
16+
17+
// CHECK-INPUT: "swiftPrebuiltExternal": "Foo"
18+
// CHECK-MISSING-NOT: "swiftPrebuiltExternal": "Foo"
19+
20+
//--- Foo.swift
21+
public func foo() {}
22+
23+
//--- test.swift
24+
#if canImport(Foo)
25+
import Foo
26+
#endif
27+
28+
//--- test_too_new.swift
29+
#if canImport(Foo, _version: 23)
30+
import Foo
31+
#endif
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/module-cache)
3+
// RUN: %empty-directory(%t/Inputs/Foo.swiftmodule)
4+
// RUN: split-file %s %t
5+
6+
// Step 1: build swift interface and swift module side by side
7+
// RUN: %target-swift-frontend -emit-module %t/Foo.swift -emit-module-path %t/Inputs/Foo.swiftmodule/%target-swiftmodule-name -module-name Foo
8+
9+
// Step 2: scan dependency should give us the binary module we specify with 'swift-module-file'
10+
// RUN: %target-swift-frontend -scan-dependencies %t/test.swift -o %t/deps.json -scanner-module-validation -swift-module-file=Foo=%t/Inputs/Foo.swiftmodule/%target-swiftmodule-name
11+
// RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=CHECK-INPUT
12+
13+
// Step 3: ensure that if multiple inputs for the same module are specified then a warning is emitted and the latter is preferred
14+
// RUN: echo "Gibberish" > %t/Inputs/Foo.swiftmodule/NotAModule.swiftmodule
15+
// RUN: %target-swift-frontend -scan-dependencies %t/test.swift -o %t/deps.json -scanner-module-validation -swift-module-file=Foo=%t/Inputs/Foo.swiftmodule/NotAModule.swiftmodule -swift-module-file=Foo=%t/Inputs/Foo.swiftmodule/%target-swiftmodule-name -diagnostic-style llvm 2>&1 | %FileCheck %s -check-prefix=CHECK-WARN-MULTIPLE
16+
// RUN: %validate-json %t/deps.json | %FileCheck %s -check-prefix=CHECK-INPUT
17+
18+
// Step 4: verify that the usual invalid module candidate diagnostics apply
19+
// RUN: echo "Not Really a module" > %t/Inputs/Foo.swiftmodule/%target-swiftmodule-name
20+
// RUN: %target-swift-frontend -scan-dependencies %t/test.swift -o %t/deps.json -scanner-module-validation -swift-module-file=Foo=%t/Inputs/Foo.swiftmodule/%target-swiftmodule-name -diagnostic-style llvm 2>&1 | %FileCheck %s -check-prefix=CHECK-INVALID-MODULE-DIAG
21+
22+
// CHECK-INPUT: "swiftPrebuiltExternal": "Foo"
23+
// CHECK-WARN-MULTIPLE: warning: multiple Swift module file inputs with identifier "Foo": replacing '{{.*}}NotAModule.swiftmodule'
24+
// CHECK-INVALID-MODULE-DIAG: error: unable to resolve Swift module dependency to a compatible module: 'Foo'
25+
// CHECK-INVALID-MODULE-DIAG: note: found incompatible module '{{.*}}': malformed
26+
27+
//--- Foo.swift
28+
public func foo() {}
29+
30+
//--- test.swift
31+
#if canImport(Foo)
32+
import Foo
33+
#endif

0 commit comments

Comments
 (0)