Skip to content

Commit 7887f66

Browse files
authored
Merge pull request #10175 from github/redsun82/swift-missing-extractions
Swift: fix missing extractions
2 parents bb167a3 + b5d18b0 commit 7887f66

21 files changed

+333
-150
lines changed

swift/codegen/schema.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,8 @@ ModuleDecl:
11211121
_extends: TypeDecl
11221122
is_builtin_module: predicate
11231123
is_system_module: predicate
1124+
imported_modules: ModuleDecl*
1125+
exported_modules: ModuleDecl*
11241126

11251127
ConstructorRefCallExpr:
11261128
_extends: SelfApplyExpr

swift/extractor/SwiftBuiltinSymbols.h

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#pragma once
2+
3+
#include <array>
4+
5+
namespace codeql {
6+
constexpr std::array swiftBuiltins = {
7+
"zeroInitializer",
8+
"BridgeObject",
9+
"Word",
10+
"NativeObject",
11+
"RawPointer",
12+
"Executor",
13+
"Job",
14+
"RawUnsafeContinuation",
15+
"addressof",
16+
"initialize",
17+
"reinterpretCast",
18+
"Int1",
19+
"Int8",
20+
"Int16",
21+
"Int32",
22+
"Int64",
23+
"IntLiteral",
24+
"FPIEEE16",
25+
"FPIEEE32",
26+
"FPIEEE64",
27+
"FPIEEE80",
28+
"Vec2xInt8",
29+
"Vec4xInt8",
30+
"Vec8xInt8",
31+
"Vec16xInt8",
32+
"Vec32xInt8",
33+
"Vec64xInt8",
34+
"Vec2xInt16",
35+
"Vec4xInt16",
36+
"Vec8xInt16",
37+
"Vec16xInt16",
38+
"Vec32xInt16",
39+
"Vec64xInt16",
40+
"Vec2xInt32",
41+
"Vec4xInt32",
42+
"Vec8xInt32",
43+
"Vec16xInt32",
44+
"Vec32xInt32",
45+
"Vec64xInt32",
46+
"Vec2xInt64",
47+
"Vec4xInt64",
48+
"Vec8xInt64",
49+
"Vec16xInt64",
50+
"Vec32xInt64",
51+
"Vec64xInt64",
52+
"Vec2xFPIEEE16",
53+
"Vec4xFPIEEE16",
54+
"Vec8xFPIEEE16",
55+
"Vec16xFPIEEE16",
56+
"Vec32xFPIEEE16",
57+
"Vec64xFPIEEE16",
58+
"Vec2xFPIEEE32",
59+
"Vec4xFPIEEE32",
60+
"Vec8xFPIEEE32",
61+
"Vec16xFPIEEE32",
62+
"Vec32xFPIEEE32",
63+
"Vec64xFPIEEE32",
64+
"Vec2xFPIEEE64",
65+
"Vec4xFPIEEE64",
66+
"Vec8xFPIEEE64",
67+
"Vec16xFPIEEE64",
68+
"Vec32xFPIEEE64",
69+
"Vec64xFPIEEE64",
70+
};
71+
}

swift/extractor/SwiftExtractor.cpp

Lines changed: 66 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@
66
#include <queue>
77

88
#include <swift/AST/SourceFile.h>
9-
#include <swift/Basic/FileTypes.h>
10-
#include <llvm/ADT/SmallString.h>
11-
#include <llvm/Support/FileSystem.h>
12-
#include <llvm/Support/Path.h>
9+
#include <swift/AST/Builtins.h>
1310

14-
#include "swift/extractor/trap/generated/TrapClasses.h"
1511
#include "swift/extractor/trap/TrapDomain.h"
1612
#include "swift/extractor/visitors/SwiftVisitor.h"
1713
#include "swift/extractor/TargetTrapFile.h"
14+
#include "swift/extractor/SwiftBuiltinSymbols.h"
1815

1916
using namespace codeql;
2017
using namespace std::string_literals;
@@ -65,7 +62,40 @@ static std::string getFilename(swift::ModuleDecl& module, swift::SourceFile* pri
6562
filename += module.getName().str();
6663
return filename;
6764
}
68-
return module.getModuleFilename().str();
65+
if (module.isBuiltinModule()) {
66+
// The Builtin module has an empty filename, let's fix that
67+
return "/__Builtin__";
68+
}
69+
auto filename = module.getModuleFilename().str();
70+
// there is a special case of a module without an actual filename reporting `<imports>`: in this
71+
// case we want to avoid the `<>` characters, in case a dirty DB is imported on Windows
72+
if (filename == "<imports>") {
73+
return "/__imports__";
74+
}
75+
return filename;
76+
}
77+
78+
/* The builtin module is special, as it does not publish any top-level declaration
79+
* It creates (and caches) declarations on demand when a lookup is carried out
80+
* (see BuiltinUnit in swift/AST/FileUnit.h for the cache details, and getBuiltinValueDecl in
81+
* swift/AST/Builtins.h for the creation details)
82+
* As we want to create the Builtin trap file once and for all so that it works for other
83+
* extraction runs, rather than collecting what we need we pre-populate the builtin trap with
84+
* what we expect. This list might need thus to be expanded.
85+
* Notice, that while swift/AST/Builtins.def has a list of builtin symbols, it does not contain
86+
* all information required to instantiate builtin variants.
87+
* Other possible approaches:
88+
* * create one trap per builtin declaration when encountered
89+
* * expand the list to all possible builtins (of which there are a lot)
90+
*/
91+
static void getBuiltinDecls(swift::ModuleDecl& builtinModule,
92+
llvm::SmallVector<swift::Decl*>& decls) {
93+
llvm::SmallVector<swift::ValueDecl*> values;
94+
for (auto symbol : swiftBuiltins) {
95+
builtinModule.lookupValue(builtinModule.getASTContext().getIdentifier(symbol),
96+
swift::NLKind::QualifiedLookup, values);
97+
}
98+
decls.insert(decls.end(), values.begin(), values.end());
6999
}
70100

71101
static llvm::SmallVector<swift::Decl*> getTopLevelDecls(swift::ModuleDecl& module,
@@ -74,16 +104,19 @@ static llvm::SmallVector<swift::Decl*> getTopLevelDecls(swift::ModuleDecl& modul
74104
ret.push_back(&module);
75105
if (primaryFile) {
76106
primaryFile->getTopLevelDecls(ret);
107+
} else if (module.isBuiltinModule()) {
108+
getBuiltinDecls(module, ret);
77109
} else {
78110
module.getTopLevelDecls(ret);
79111
}
80112
return ret;
81113
}
82114

83-
static void extractDeclarations(const SwiftExtractorConfiguration& config,
84-
swift::CompilerInstance& compiler,
85-
swift::ModuleDecl& module,
86-
swift::SourceFile* primaryFile = nullptr) {
115+
static std::unordered_set<swift::ModuleDecl*> extractDeclarations(
116+
const SwiftExtractorConfiguration& config,
117+
swift::CompilerInstance& compiler,
118+
swift::ModuleDecl& module,
119+
swift::SourceFile* primaryFile = nullptr) {
87120
auto filename = getFilename(module, primaryFile);
88121

89122
// The extractor can be called several times from different processes with
@@ -92,7 +125,7 @@ static void extractDeclarations(const SwiftExtractorConfiguration& config,
92125
auto trapTarget = createTargetTrapFile(config, filename);
93126
if (!trapTarget) {
94127
// another process arrived first, nothing to do for us
95-
return;
128+
return {};
96129
}
97130
TrapDomain trap{*trapTarget};
98131

@@ -116,6 +149,7 @@ static void extractDeclarations(const SwiftExtractorConfiguration& config,
116149
for (auto& comment : comments) {
117150
visitor.extract(comment);
118151
}
152+
return std::move(visitor).getEncounteredModules();
119153
}
120154

121155
static std::unordered_set<std::string> collectInputFilenames(swift::CompilerInstance& compiler) {
@@ -132,40 +166,27 @@ static std::unordered_set<std::string> collectInputFilenames(swift::CompilerInst
132166
return sourceFiles;
133167
}
134168

135-
static std::unordered_set<swift::ModuleDecl*> collectModules(swift::CompilerInstance& compiler) {
136-
// getASTContext().getLoadedModules() does not provide all the modules available within the
137-
// program.
138-
// We need to iterate over all the imported modules (recursively) to see the whole "universe."
139-
std::unordered_set<swift::ModuleDecl*> allModules;
140-
std::queue<swift::ModuleDecl*> worklist;
141-
for (auto& [_, module] : compiler.getASTContext().getLoadedModules()) {
142-
worklist.push(module);
143-
allModules.insert(module);
144-
}
145-
146-
while (!worklist.empty()) {
147-
auto module = worklist.front();
148-
worklist.pop();
149-
llvm::SmallVector<swift::ImportedModule> importedModules;
150-
// TODO: we may need more than just Exported ones
151-
module->getImportedModules(importedModules, swift::ModuleDecl::ImportFilterKind::Exported);
152-
for (auto& imported : importedModules) {
153-
if (allModules.count(imported.importedModule) == 0) {
154-
worklist.push(imported.importedModule);
155-
allModules.insert(imported.importedModule);
156-
}
157-
}
169+
static std::vector<swift::ModuleDecl*> collectLoadedModules(swift::CompilerInstance& compiler) {
170+
std::vector<swift::ModuleDecl*> ret;
171+
for (const auto& [id, module] : compiler.getASTContext().getLoadedModules()) {
172+
std::ignore = id;
173+
ret.push_back(module);
158174
}
159-
return allModules;
175+
return ret;
160176
}
161177

162178
void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
163179
swift::CompilerInstance& compiler) {
164180
auto inputFiles = collectInputFilenames(compiler);
165-
auto modules = collectModules(compiler);
181+
std::vector<swift::ModuleDecl*> todo = collectLoadedModules(compiler);
182+
std::unordered_set<swift::ModuleDecl*> seen{todo.begin(), todo.end()};
166183

167-
for (auto& module : modules) {
184+
while (!todo.empty()) {
185+
auto module = todo.back();
186+
todo.pop_back();
187+
llvm::errs() << "processing module " << module->getName() << '\n';
168188
bool isFromSourceFile = false;
189+
std::unordered_set<swift::ModuleDecl*> encounteredModules;
169190
for (auto file : module->getFiles()) {
170191
auto sourceFile = llvm::dyn_cast<swift::SourceFile>(file);
171192
if (!sourceFile) {
@@ -176,10 +197,16 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
176197
continue;
177198
}
178199
archiveFile(config, *sourceFile);
179-
extractDeclarations(config, compiler, *module, sourceFile);
200+
encounteredModules = extractDeclarations(config, compiler, *module, sourceFile);
180201
}
181202
if (!isFromSourceFile) {
182-
extractDeclarations(config, compiler, *module);
203+
encounteredModules = extractDeclarations(config, compiler, *module);
204+
}
205+
for (auto encountered : encounteredModules) {
206+
if (seen.count(encountered) == 0) {
207+
todo.push_back(encountered);
208+
seen.insert(encountered);
209+
}
183210
}
184211
}
185212
}

swift/extractor/infra/SwiftDispatcher.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ class SwiftDispatcher {
5555
}
5656
}
5757

58+
const std::unordered_set<swift::ModuleDecl*> getEncounteredModules() && {
59+
return std::move(encounteredModules);
60+
}
61+
5862
template <typename Entry>
5963
void emit(const Entry& entry) {
6064
trap.emit(entry);
@@ -228,8 +232,16 @@ class SwiftDispatcher {
228232
// - extracting a primary source file: in this mode, we extract several files belonging to the
229233
// same module one by one. In this mode, we restrict emission only to the same file ignoring
230234
// all the other files.
235+
// This is also used to register the modules we encounter.
236+
// TODO calls to this function should be taken away from `DeclVisitor` and moved around with a
237+
// clearer separation between naming entities (some decls, all types), deciding whether to emit
238+
// them and finally visiting emitting the contents of the entity (which should remain in the
239+
// visitors). Then this double responsibility (carrying out the test and registering encountered
240+
// modules) should also be cleared out
231241
bool shouldEmitDeclBody(const swift::Decl& decl) {
232-
if (decl.getModuleContext() != &currentModule) {
242+
auto module = decl.getModuleContext();
243+
if (module != &currentModule) {
244+
encounteredModules.insert(module);
233245
return false;
234246
}
235247
// ModuleDecl is a special case: if it passed the previous test, it is the current module
@@ -333,6 +345,7 @@ class SwiftDispatcher {
333345
Store::Handle waitingForNewLabel{std::monostate{}};
334346
swift::ModuleDecl& currentModule;
335347
swift::SourceFile* currentPrimarySourceFile;
348+
std::unordered_set<swift::ModuleDecl*> encounteredModules;
336349
};
337350

338351
} // namespace codeql

0 commit comments

Comments
 (0)