Skip to content

Commit 1c8f295

Browse files
authored
Merge pull request #68849 from artemcm/ReQueryFromCacheImportResolutionFailure
[Dependency Scanning] Post-process imports that fail to resolve against the cache entries added by other resolved imports
2 parents 829694f + 64b18f5 commit 1c8f295

File tree

9 files changed

+99
-20
lines changed

9 files changed

+99
-20
lines changed

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -548,8 +548,8 @@ void ModuleDependencyScanner::resolveImportDependencies(
548548
// A scanning task to query a module by-name. If the module already exists
549549
// in the cache, do nothing and return.
550550
auto scanForModuleDependency = [this, &cache, &moduleLookupResult](
551-
StringRef moduleName, bool onlyClangModule,
552-
bool isTestable) {
551+
StringRef moduleName, bool onlyClangModule,
552+
bool isTestable) {
553553
// If this is already in the cache, no work to do here
554554
if (onlyClangModule) {
555555
if (cache.hasDependency(moduleName, ModuleDependencyKind::Clang))
@@ -587,9 +587,10 @@ void ModuleDependencyScanner::resolveImportDependencies(
587587
}
588588
ScanningThreadPool.wait();
589589

590+
std::vector<std::string> unresolvedImports;
590591
// Aggregate both previously-cached and freshly-scanned module results
591592
auto recordResolvedModuleImport =
592-
[this, &cache, &moduleLookupResult, &directDependencies,
593+
[&cache, &moduleLookupResult, &unresolvedImports, &directDependencies,
593594
moduleID](const std::string &moduleName, bool optionalImport) {
594595
bool underlyingClangModule = moduleID.ModuleName == moduleName;
595596
auto lookupResult = moduleLookupResult[moduleName];
@@ -606,19 +607,56 @@ void ModuleDependencyScanner::resolveImportDependencies(
606607
directDependencies.insert({moduleName, cachedInfo->getKind()});
607608
} else {
608609
// Cache discovered module dependencies.
609-
cache.recordDependencies(lookupResult.value());
610-
if (!lookupResult.value().empty())
610+
if (!lookupResult.value().empty()) {
611+
cache.recordDependencies(lookupResult.value());
611612
directDependencies.insert(
612613
{moduleName, lookupResult.value()[0].first.Kind});
613-
else if (!optionalImport)
614-
diagnoseScannerFailure(moduleName, Diagnostics, cache, moduleID);
614+
} else if (!optionalImport) {
615+
// Otherwise, we failed to resolve this dependency. We will try
616+
// again using the cache after all other imports have been resolved.
617+
// If that fails too, a scanning failure will be diagnosed.
618+
unresolvedImports.push_back(moduleName);
619+
}
615620
}
616621
};
617-
for (const auto &dependsOn : moduleDependencyInfo->getModuleImports())
618-
recordResolvedModuleImport(dependsOn, false);
619-
for (const auto &optionallyDependsOn :
620-
moduleDependencyInfo->getOptionalModuleImports())
621-
recordResolvedModuleImport(optionallyDependsOn, true);
622+
for (const auto &import : moduleDependencyInfo->getModuleImports())
623+
recordResolvedModuleImport(import, /* optionalImport */ false);
624+
for (const auto &import : moduleDependencyInfo->getOptionalModuleImports())
625+
recordResolvedModuleImport(import, /* optionalImport */ true);
626+
627+
// It is possible that import resolution failed because we are attempting to
628+
// resolve a module which can only be brought in via a modulemap of a
629+
// different Clang module dependency which is not otherwise on the current
630+
// search paths. For example, suppose we are scanning a `.swiftinterface` for
631+
// module `Foo`, which contains:
632+
// -----
633+
// @_exported import Foo
634+
// import Bar
635+
// ...
636+
// -----
637+
// Where `Foo` is the underlying Framework clang module whose .modulemap
638+
// defines an auxiliary module `Bar`. Because Foo is a framework, its
639+
// modulemap is under
640+
// `<some_framework_search_path>/Foo.framework/Modules/module.modulemap`.
641+
// Which means that lookup of `Bar` alone from Swift will not be able to
642+
// locate the module in it. However, the lookup of Foo will itself bring in
643+
// the auxiliary module becuase the Clang scanner instance scanning for clang
644+
// module Foo will be able to find it in the corresponding framework module's
645+
// modulemap and register it as a dependency which means it will be registered
646+
// with the scanner's cache in the step above. To handle such cases, we
647+
// first add all successfully-resolved modules and (for Clang modules) their
648+
// transitive dependencies to the cache, and then attempt to re-query imports
649+
// for which resolution originally failed from the cache. If this fails, then
650+
// the scanner genuinely failed to resolve this dependency.
651+
for (const auto &moduleName : unresolvedImports) {
652+
auto optionalCachedModuleInfo =
653+
cache.findDependency({moduleName, ModuleDependencyKind::Clang});
654+
if (optionalCachedModuleInfo.has_value())
655+
directDependencies.insert(
656+
{moduleName, optionalCachedModuleInfo.value()->getKind()});
657+
else
658+
diagnoseScannerFailure(moduleName, Diagnostics, cache, moduleID);
659+
}
622660
}
623661

624662
void ModuleDependencyScanner::resolveBridgingHeaderDependencies(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-compiler-version: Apple Swift version 5.9
3+
// swift-module-flags: -target arm64-apple-macos10.13 -enable-library-evolution -swift-version 5 -module-name ScannerTestKit
4+
import Swift
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-compiler-version: Apple Swift version 5.9
3+
// swift-module-flags: -target arm64e-apple-macos10.13 -enable-library-evolution -swift-version 5 -module-name ScannerTestKit
4+
import Swift
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-compiler-version: Apple Swift version 5.9
3+
// swift-module-flags: -target x86_64-apple-macos10.13 -enable-library-evolution -swift-version 5 -module-name ScannerTestKit
4+
import Swift
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
void funcAux(void);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "WithAuxClangModule/AuxClangModule.h"
2+
void funcWithAux(void);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
framework module WithAuxClangModule {
2+
header "WithAuxClangModule.h"
3+
export *
4+
}
5+
6+
framework module AuxClangModule {
7+
header "AuxClangModule.h"
8+
export *
9+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// REQUIRES: OS=macosx
2+
// RUN: %empty-directory(%t)
3+
// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks -verify
4+
// Check the contents of the JSON output
5+
// RUN: %validate-json %t/deps.json | %FileCheck %s
6+
7+
// Ensure that round-trip serialization does not affect result
8+
// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks -verify
9+
// RUN: %validate-json %t/deps.json | %FileCheck %s
10+
11+
import WithAuxClangModule
12+
import AuxClangModule
13+
14+
// CHECK: "mainModuleName": "deps"
15+
// CHECK: directDependencies
16+
// CHECK-DAG: "clang": "WithAuxClangModule"
17+
// CHECK-DAG: "clang": "AuxClangModule"
18+
// CHECK-DAG: "swift": "Swift"
19+
// CHECK-DAG: "swift": "SwiftOnoneSupport"
20+
// CHECK: ],
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,20 @@
1+
// REQUIRES: OS=macosx
12
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -Xcc -Xclang
3+
// RUN: %target-swift-frontend -scan-dependencies %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks
34
// Check the contents of the JSON output
45
// RUN: %validate-json %t/deps.json | %FileCheck %s
56

67
// Ensure that round-trip serialization does not affect result
7-
// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -swift-version 4 -Xcc -Xclang
8+
// RUN: %target-swift-frontend -scan-dependencies -test-dependency-scan-cache-serialization %s -o %t/deps.json -emit-dependencies -emit-dependencies-path %t/deps.d -disable-implicit-concurrency-module-import -disable-implicit-string-processing-module-import -F %S/Inputs/Frameworks
89
// RUN: %validate-json %t/deps.json | %FileCheck %s
910

10-
// REQUIRES: OS=macosx
11-
12-
import CryptoKit
11+
import ScannerTestKit
1312

1413
// CHECK: "mainModuleName": "deps"
1514
// CHECK: directDependencies
16-
// CHECK-DAG: "swift": "CryptoKit"
15+
// CHECK-DAG: "swift": "ScannerTestKit"
1716
// CHECK-DAG: "swift": "Swift"
1817
// CHECK-DAG: "swift": "SwiftOnoneSupport"
19-
// CHECK-DAG: "swift": "_Concurrency"
20-
// CHECK-DAG: "swift": "_StringProcessing"
2118
// CHECK: ],
2219

2320
// CHECK: "isFramework": true

0 commit comments

Comments
 (0)