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