Skip to content

Commit 0e8d794

Browse files
[Dependency Scanning] Scan embedded header content if file doesn't exist
Fallback to scan embedded header content when the bridging header path encoded in the swift binary module doesn't exit on the disk. rdar://144261730
1 parent e17556a commit 0e8d794

File tree

2 files changed

+126
-6
lines changed

2 files changed

+126
-6
lines changed

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "llvm/CAS/CachingOnDiskFileSystem.h"
3737
#include "llvm/Support/Error.h"
3838
#include "llvm/Support/MemoryBuffer.h"
39+
#include "llvm/Support/MemoryBufferRef.h"
3940
#include "llvm/Support/Path.h"
4041
#include "llvm/Support/Threading.h"
4142
#include "llvm/Support/VersionTuple.h"
@@ -1063,6 +1064,42 @@ void ModuleDependencyScanner::resolveHeaderDependenciesForModule(
10631064
if (!isTextualModuleWithABridgingHeader && !isBinaryModuleWithHeaderInput)
10641065
return;
10651066

1067+
1068+
std::optional<std::string> headerPath;
1069+
std::unique_ptr<llvm::MemoryBuffer> sourceBuffer;
1070+
std::optional<llvm::MemoryBufferRef> sourceBufferRef;
1071+
1072+
auto extractHeaderContent =
1073+
[&](const SwiftBinaryModuleDependencyStorage &binaryMod)
1074+
-> std::unique_ptr<llvm::MemoryBuffer> {
1075+
auto header = binaryMod.headerImport;
1076+
// Check to see if the header input exists on disk.
1077+
auto FS = ScanASTContext.SourceMgr.getFileSystem();
1078+
if (FS->exists(header))
1079+
return nullptr;
1080+
1081+
auto moduleBuf = FS->getBufferForFile(binaryMod.compiledModulePath);
1082+
if (!moduleBuf)
1083+
return nullptr;
1084+
1085+
auto content = extractEmbeddedBridgingHeaderContent(std::move(*moduleBuf),
1086+
ScanASTContext);
1087+
if (content.empty())
1088+
return nullptr;
1089+
1090+
return llvm::MemoryBuffer::getMemBufferCopy(content, header);
1091+
};
1092+
1093+
if (isBinaryModuleWithHeaderInput) {
1094+
auto &binaryMod = *moduleDependencyInfo.getAsSwiftBinaryModule();
1095+
if (auto embeddedHeader = extractHeaderContent(binaryMod)) {
1096+
sourceBuffer = std::move(embeddedHeader);
1097+
sourceBufferRef = sourceBuffer->getMemBufferRef();
1098+
} else
1099+
headerPath = binaryMod.headerImport;
1100+
} else
1101+
headerPath = *moduleDependencyInfo.getBridgingHeader();
1102+
10661103
withDependencyScanningWorker(
10671104
[&](ModuleDependencyScanningWorker *ScanningWorker) {
10681105
auto clangImporter = static_cast<ClangImporter *>(
@@ -1072,12 +1109,9 @@ void ModuleDependencyScanner::resolveHeaderDependenciesForModule(
10721109
std::optional<std::string> includeTreeID;
10731110
std::vector<std::string> bridgingHeaderCommandLine;
10741111
auto headerScan = clangImporter->getHeaderDependencies(
1075-
moduleID,
1076-
isTextualModuleWithABridgingHeader
1077-
? *moduleDependencyInfo.getBridgingHeader()
1078-
: moduleDependencyInfo.getAsSwiftBinaryModule()->headerImport,
1079-
/*sourceBuffer=*/std::nullopt, ScanningWorker->clangScanningTool,
1080-
cache, headerClangModuleDependencies, headerFileInputs,
1112+
moduleID, headerPath, sourceBufferRef,
1113+
ScanningWorker->clangScanningTool, cache,
1114+
headerClangModuleDependencies, headerFileInputs,
10811115
bridgingHeaderCommandLine, includeTreeID);
10821116
if (!headerScan) {
10831117
// Record direct header Clang dependencies
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// REQUIRES: objc_interop
2+
// RUN: %empty-directory(%t)
3+
// RUN: split-file %s %t
4+
5+
// RUN: %target-swift-frontend -emit-module -module-name Test -module-cache-path %t/clang-module-cache -O \
6+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
7+
// RUN: %t/test.swift -o %t/Test.swiftmodule \
8+
// RUN: -Xcc -fmodule-map-file=%t/a.modulemap -Xcc -fmodule-map-file=%t/b.modulemap -import-objc-header %t/Bridging.h
9+
10+
// RUN: %target-swift-frontend -scan-dependencies -module-name User -module-cache-path %t/clang-module-cache -O \
11+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
12+
// RUN: %t/user.swift -o %t/deps.json \
13+
// RUN: -Xcc -fmodule-map-file=%t/a.modulemap -Xcc -fmodule-map-file=%t/b.modulemap -I %t
14+
15+
/// Remove bridging header from disk and rescan
16+
// RUN: rm -rf %t/Bridging.h %t/Foo.h %t/Foo2.h
17+
// RUN: %target-swift-frontend -scan-dependencies -module-name User -module-cache-path %t/clang-module-cache -O \
18+
// RUN: -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import \
19+
// RUN: %t/user.swift -o %t/deps2.json \
20+
// RUN: -Xcc -fmodule-map-file=%t/a.modulemap -Xcc -fmodule-map-file=%t/b.modulemap -I %t
21+
22+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps.json swiftPrebuiltExternal:Test headerModuleDependencies | %FileCheck %s --check-prefix=MODULE
23+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps.json swiftPrebuiltExternal:Test headerDependenciesSourceFiles | %FileCheck %s --check-prefix=FILE
24+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps2.json swiftPrebuiltExternal:Test headerModuleDependencies | %FileCheck %s --check-prefix=MODULE
25+
// RUN: %{python} %S/../CAS/Inputs/SwiftDepsExtractor.py %t/deps2.json swiftPrebuiltExternal:Test headerDependenciesSourceFiles | %FileCheck %s --check-prefix=FILE
26+
27+
// MODULE: "A"
28+
// FILE: Bridging.h
29+
30+
//--- test.swift
31+
public func test() {
32+
b()
33+
}
34+
public class TestB: B {}
35+
36+
//--- user.swift
37+
import Test
38+
39+
func user() {
40+
var b: TestB
41+
test()
42+
}
43+
44+
extension A {
45+
public func testA() {}
46+
}
47+
48+
//--- Bridging.h
49+
#include "Foo.h"
50+
#include "Foo2.h"
51+
52+
//--- Foo.h
53+
#import "a.h"
54+
#ifndef IMPORT_FOO
55+
#define IMPORT_FOO
56+
int Foo = 0;
57+
#endif
58+
59+
//--- Foo2.h
60+
#ifndef IMPORT_FOO2
61+
#define IMPORT_FOO2
62+
int Foo2 = 0;
63+
#endif
64+
65+
//--- a.h
66+
#include "b.h"
67+
struct A {
68+
int a;
69+
};
70+
71+
//--- b.h
72+
void b(void);
73+
@interface B
74+
@end
75+
76+
//--- a.modulemap
77+
module A {
78+
header "a.h"
79+
export *
80+
}
81+
82+
//--- b.modulemap
83+
module B {
84+
header "b.h"
85+
export *
86+
}

0 commit comments

Comments
 (0)