Skip to content

Commit f383fd1

Browse files
committed
Swift: introduce module disambuigation via linkage awareness
1 parent d7feb00 commit f383fd1

File tree

4 files changed

+171
-1
lines changed

4 files changed

+171
-1
lines changed

swift/extractor/infra/TargetDomains.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ static std::filesystem::path getRelativeTrapPath(const std::filesystem::path& ta
2626
return trap;
2727
}
2828

29+
std::filesystem::path getTrapPath(const SwiftExtractorState& state,
30+
const std::filesystem::path& target,
31+
TrapType type) {
32+
return state.configuration.trapDir / getRelativeTrapPath(target, type);
33+
}
34+
2935
std::optional<TrapDomain> createTargetTrapDomain(SwiftExtractorState& state,
3036
const std::filesystem::path& target,
3137
TrapType type) {

swift/extractor/infra/TargetDomains.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ enum class TrapType {
1414
linkage,
1515
};
1616

17+
std::filesystem::path getTrapPath(const SwiftExtractorState& state,
18+
const std::filesystem::path& target,
19+
TrapType type);
20+
1721
std::optional<TrapDomain> createTargetTrapDomain(SwiftExtractorState& state,
1822
const std::filesystem::path& target,
1923
TrapType type);

swift/extractor/invocation/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ swift_cc_library(
88
deps = [
99
"//swift/extractor/config",
1010
"//swift/extractor/infra",
11+
"//swift/extractor/remapping",
1112
],
1213
)
Lines changed: 160 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,166 @@
11
#include "swift/extractor/invocation/SwiftInvocationExtractor.h"
2+
#include "swift/extractor/remapping/SwiftFileInterception.h"
3+
#include "swift/extractor/infra/TargetDomains.h"
4+
#include "swift/extractor/trap/generated/TrapTags.h"
5+
#include "swift/extractor/infra/file/TargetFile.h"
6+
#include "swift/extractor/infra/file/Path.h"
7+
#include "swift/extractor/trap/LinkDomain.h"
8+
9+
namespace fs = std::filesystem;
10+
using namespace std::string_literals;
211

312
namespace codeql {
13+
namespace {
14+
std::string getModuleId(const std::string_view& name, const std::string_view& hash) {
15+
auto ret = "module:"s;
16+
ret += name;
17+
ret += ':';
18+
ret += hash;
19+
return ret;
20+
}
21+
22+
std::string getModuleId(const swift::ModuleDecl* module, const std::string_view& hash) {
23+
return getModuleId(module->getRealName().str(), hash);
24+
}
25+
26+
fs::path getModuleTarget(const std::string_view& name, const std::string_view& hash) {
27+
fs::path ret{"modules"};
28+
ret /= name;
29+
ret += '_';
30+
ret += hash;
31+
ret /= "module";
32+
return ret;
33+
}
34+
35+
std::optional<std::string> getModuleHash(const fs::path& moduleFile) {
36+
return getHashOfRealFile(moduleFile);
37+
}
38+
39+
std::optional<std::string> getModuleHash(const swift::ModuleDecl* module) {
40+
return getModuleHash(std::string_view{module->getModuleFilename()});
41+
}
42+
43+
std::string getSourceId(const fs::path& file) {
44+
return "source:"s + file.c_str();
45+
}
46+
47+
std::string getSourceId(const swift::InputFile& input) {
48+
return getSourceId(resolvePath(input.getFileName()));
49+
}
50+
51+
fs::path getSourceTarget(const fs::path& file) {
52+
return "sources" / file.relative_path();
53+
}
54+
55+
struct ModuleInfo {
56+
fs::path target;
57+
std::string id;
58+
};
59+
60+
std::vector<ModuleInfo> emitModuleImplementations(SwiftExtractorState& state,
61+
const std::string& moduleName) {
62+
std::vector<ModuleInfo> ret;
63+
ret.reserve(state.originalOutputModules.size());
64+
for (const auto& modulePath : state.originalOutputModules) {
65+
if (auto hash = getModuleHash(modulePath)) {
66+
auto target = getModuleTarget(moduleName, *hash);
67+
if (auto moduleTrap = createTargetTrapDomain(state, target, TrapType::linkage)) {
68+
moduleTrap->createLabelWithImplementationId<ModuleDeclTag>(*hash, moduleName);
69+
ret.push_back({target, getModuleId(moduleName, *hash)});
70+
}
71+
}
72+
}
73+
return ret;
74+
}
75+
76+
void emitLinkFile(const SwiftExtractorState& state, const fs::path& target, const std::string& id) {
77+
if (auto link = createTargetLinkDomain(state, target)) {
78+
link->emitTarget(id);
79+
link->emitObjectDependency(id);
80+
}
81+
}
82+
83+
void emitSourceObjectDependencies(const SwiftExtractorState& state,
84+
const fs::path& target,
85+
const std::string& id) {
86+
if (auto object = createTargetObjectDomain(state, target)) {
87+
object->emitObject(id);
88+
for (auto encounteredModule : state.encounteredModules) {
89+
if (auto depHash = getModuleHash(encounteredModule)) {
90+
object->emitObjectDependency(getModuleId(encounteredModule, *depHash));
91+
}
92+
}
93+
for (const auto& requestedTrap : state.traps) {
94+
object->emitTrapDependency(requestedTrap);
95+
}
96+
}
97+
}
98+
99+
void replaceMergedModulesImplementation(const SwiftExtractorState& state,
100+
const std::string& name,
101+
const fs::path& mergeTarget,
102+
const std::string& mergedPartHash) {
103+
std::error_code ec;
104+
auto mergedPartTarget = getModuleTarget(name, mergedPartHash);
105+
fs::copy(getTrapPath(state, mergeTarget, TrapType::linkage),
106+
getTrapPath(state, mergedPartTarget, TrapType::linkage),
107+
fs::copy_options::overwrite_existing, ec);
108+
if (ec) {
109+
std::cerr << "unable to replace merged module trap implementation id (" << ec.message() << ")";
110+
}
111+
}
112+
113+
void emitModuleObjectDependencies(const SwiftExtractorState& state,
114+
const swift::FrontendOptions& options,
115+
const fs::path& target,
116+
const std::string& id) {
117+
if (auto object = createTargetObjectDomain(state, target)) {
118+
object->emitObject(id);
119+
for (auto encounteredModule : state.encounteredModules) {
120+
if (auto depHash = getModuleHash(encounteredModule)) {
121+
object->emitObjectDependency(getModuleId(encounteredModule, *depHash));
122+
}
123+
}
124+
if (options.RequestedAction == swift::FrontendOptions::ActionType::MergeModules) {
125+
for (const auto& input : options.InputsAndOutputs.getAllInputs()) {
126+
if (auto mergedHash = getModuleHash(input.getFileName())) {
127+
object->emitObjectDependency(getModuleId(options.ModuleName, *mergedHash));
128+
replaceMergedModulesImplementation(state, options.ModuleName, target, *mergedHash);
129+
}
130+
}
131+
} else {
132+
for (const auto& input : options.InputsAndOutputs.getAllInputs()) {
133+
object->emitObjectDependency(getSourceId(input));
134+
}
135+
}
136+
for (const auto& requestedTrap : state.traps) {
137+
object->emitTrapDependency(requestedTrap);
138+
}
139+
}
140+
}
141+
} // namespace
142+
4143
void extractSwiftInvocation(SwiftExtractorState& state,
5144
swift::CompilerInstance& compiler,
6-
codeql::TrapDomain& trap) {}
145+
TrapDomain& trap) {
146+
const auto& options = compiler.getInvocation().getFrontendOptions();
147+
148+
// notice that there is only one unique module name per frontend run, even when outputting
149+
// multiples `swiftmodule` files
150+
// this step must be executed first so that we can capture in `state` the emitted trap files
151+
// that will be used in following steps
152+
auto modules = emitModuleImplementations(state, options.ModuleName);
153+
154+
for (const auto& input : state.sourceFiles) {
155+
auto path = resolvePath(input);
156+
auto target = getSourceTarget(path);
157+
auto inputId = getSourceId(path);
158+
emitSourceObjectDependencies(state, target, inputId);
159+
}
160+
161+
for (const auto& [target, moduleId] : modules) {
162+
emitLinkFile(state, target, moduleId);
163+
emitModuleObjectDependencies(state, options, target, moduleId);
164+
}
165+
}
7166
} // namespace codeql

0 commit comments

Comments
 (0)