Skip to content

Commit 4a2521f

Browse files
committed
[Dependency Scanning] Refine cross-import overlay detection algorithm
The algorithm already performs pairwise checks on module dependencies brought into compilation per-source-file. Previously, the algorithm considered the entire sub-graph of a given source file. Actual source compiles do not consider the full transitive module dependency set for cross-import-overlay lookup, but rather only directly-imported modules in a given source file, and '@_exported import' Swift transitive dependencies. This change adds tracking of whether a given import statement is 'exported' to the dependency scanner and then refines the cross-import overlay lookup logic to only consider transitive modules that are exported by directly-imported dependencies.
1 parent 809dbf0 commit 4a2521f

File tree

6 files changed

+54
-21
lines changed

6 files changed

+54
-21
lines changed

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -590,18 +590,19 @@ static void discoverCrossImportOverlayFiles(
590590
mainModuleName.str(), ModuleDependencyKind::SwiftSource});
591591

592592
llvm::StringMap<ModuleDependencyIDSet> perSourceFileDependencies;
593-
const ModuleDependencyIDSet directSwiftDepsSet{
593+
const ModuleDependencyIDSet mainModuleDirectSwiftDepsSet{
594594
mainModuleInfo.getImportedSwiftDependencies().begin(),
595595
mainModuleInfo.getImportedSwiftDependencies().end()};
596-
const ModuleDependencyIDSet directClangDepsSet{
596+
const ModuleDependencyIDSet mainModuleDirectClangDepsSet{
597597
mainModuleInfo.getImportedClangDependencies().begin(),
598598
mainModuleInfo.getImportedClangDependencies().end()};
599599

600600
// A utility to map an import identifier to one of the
601601
// known resolved module dependencies
602602
auto getModuleIDForImportIdentifier =
603-
[directSwiftDepsSet, directClangDepsSet](
604-
const std::string &importIdentifierStr) -> ModuleDependencyID {
603+
[](const std::string &importIdentifierStr,
604+
const ModuleDependencyIDSet &directSwiftDepsSet,
605+
const ModuleDependencyIDSet &directClangDepsSet) -> ModuleDependencyID {
605606
if (auto textualDepIt = directSwiftDepsSet.find(
606607
{importIdentifierStr, ModuleDependencyKind::SwiftInterface});
607608
textualDepIt != directSwiftDepsSet.end())
@@ -621,8 +622,9 @@ static void discoverCrossImportOverlayFiles(
621622
// Collect the set of directly-imported module dependencies
622623
// for each source file in the source module under scan.
623624
for (const auto &import : mainModuleInfo.getModuleImports()) {
624-
auto importResolvedModuleID =
625-
getModuleIDForImportIdentifier(import.importIdentifier);
625+
auto importResolvedModuleID = getModuleIDForImportIdentifier(
626+
import.importIdentifier, mainModuleDirectSwiftDepsSet,
627+
mainModuleDirectClangDepsSet);
626628
for (const auto &importLocation : import.importLocations)
627629
perSourceFileDependencies[importLocation.bufferIdentifier].insert(
628630
importResolvedModuleID);
@@ -640,19 +642,29 @@ static void discoverCrossImportOverlayFiles(
640642
auto moduleID = worklist.pop_back_val();
641643
perSourceFileDependencies[bufferIdentifier].insert(moduleID);
642644
if (isSwiftDependencyKind(moduleID.Kind)) {
643-
for (const auto &directSwiftDepID :
644-
cache.getImportedSwiftDependencies(moduleID)) {
645-
if (perSourceFileDependencies[bufferIdentifier].count(directSwiftDepID))
646-
continue;
647-
worklist.push_back(directSwiftDepID);
645+
auto moduleInfo = cache.findKnownDependency(moduleID);
646+
if (llvm::any_of(moduleInfo.getModuleImports(),
647+
[](const ScannerImportStatementInfo &importInfo) {
648+
return importInfo.isExported;
649+
})) {
650+
const ModuleDependencyIDSet directSwiftDepsSet{
651+
moduleInfo.getImportedSwiftDependencies().begin(),
652+
moduleInfo.getImportedSwiftDependencies().end()};
653+
const ModuleDependencyIDSet directClangDepsSet{
654+
moduleInfo.getImportedClangDependencies().begin(),
655+
moduleInfo.getImportedClangDependencies().end()};
656+
for (const auto &import : moduleInfo.getModuleImports()) {
657+
if (import.isExported) {
658+
auto importResolvedDepID = getModuleIDForImportIdentifier(
659+
import.importIdentifier, directSwiftDepsSet,
660+
directClangDepsSet);
661+
if (!perSourceFileDependencies[bufferIdentifier].count(
662+
importResolvedDepID))
663+
worklist.push_back(importResolvedDepID);
664+
}
665+
}
648666
}
649667
}
650-
for (const auto &directClangDepID :
651-
cache.getImportedClangDependencies(moduleID)) {
652-
if (perSourceFileDependencies[bufferIdentifier].count(directClangDepID))
653-
continue;
654-
worklist.push_back(directClangDepID);
655-
}
656668
}
657669
}
658670

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// swift-interface-format-version: 1.0
22
// swift-module-flags: -module-name EWrapper
33
import Swift
4-
import E
4+
@_exported import E
55
public func funcEWrapper() { }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// swift-interface-format-version: 1.0
2+
// swift-module-flags: -module-name EWrapperNonExported
3+
import Swift
4+
import E
5+
public func funcEWrapperNonExported() { }
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// swift-interface-format-version: 1.0
22
// swift-module-flags: -module-name SubEWrapper
33
import Swift
4-
import SubE
4+
@_exported import SubE
55
public func funcSubEWrapper() { }

test/ScanDependencies/module_deps_cross_import_overlay.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// RUN: %empty-directory(%t)
22
// RUN: mkdir -p %t/clang-module-cache
3-
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -module-name CrossImportTestModule -enable-cross-import-overlays
3+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -module-name CrossImportTestModule -enable-cross-import-overlays
44
// Check the contents of the JSON output
55
// RUN: %validate-json %t/deps.json | %FileCheck %s
66

77
// Ensure that round-trip serialization does not affect result
8-
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -module-name CrossImportTestModule -enable-cross-import-overlays
8+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -module-name CrossImportTestModule -enable-cross-import-overlays
99
// RUN: %validate-json %t/deps.json | %FileCheck %s
1010

1111
// REQUIRES: executable_test
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %empty-directory(%t)
3+
// RUN: %empty-directory(%t/clang-module-cache)
4+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -module-name CrossImportTestModule -enable-cross-import-overlays
5+
// Check the contents of the JSON output
6+
// RUN: %validate-json %t/deps.json | %FileCheck %s
7+
8+
// Ensure that round-trip serialization does not affect result
9+
// RUN: %target-swift-frontend -scan-dependencies -module-load-mode prefer-interface -test-dependency-scan-cache-serialization -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -I %S/Inputs/CHeaders/ExtraCModules -module-name CrossImportTestModule -enable-cross-import-overlays
10+
// RUN: %validate-json %t/deps.json | %FileCheck %s
11+
12+
// Ensure that if one of the two components of a cross-import overlay is a transitive (non-exported) Swift dependency, then no overlay is required to be brought in.
13+
import EWrapperNonExported
14+
import SubEWrapper
15+
16+
// CHECK-NOT: "swift": "_cross_import_E"

0 commit comments

Comments
 (0)