6
6
#include < queue>
7
7
8
8
#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>
13
10
14
- #include " swift/extractor/trap/generated/TrapClasses.h"
15
11
#include " swift/extractor/trap/TrapDomain.h"
16
12
#include " swift/extractor/visitors/SwiftVisitor.h"
17
13
#include " swift/extractor/TargetTrapFile.h"
14
+ #include " swift/extractor/SwiftBuiltinSymbols.h"
18
15
19
16
using namespace codeql ;
20
17
using namespace std ::string_literals;
@@ -65,7 +62,40 @@ static std::string getFilename(swift::ModuleDecl& module, swift::SourceFile* pri
65
62
filename += module .getName ().str ();
66
63
return filename;
67
64
}
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 ());
69
99
}
70
100
71
101
static llvm::SmallVector<swift::Decl*> getTopLevelDecls (swift::ModuleDecl& module ,
@@ -74,16 +104,19 @@ static llvm::SmallVector<swift::Decl*> getTopLevelDecls(swift::ModuleDecl& modul
74
104
ret.push_back (&module );
75
105
if (primaryFile) {
76
106
primaryFile->getTopLevelDecls (ret);
107
+ } else if (module .isBuiltinModule ()) {
108
+ getBuiltinDecls (module , ret);
77
109
} else {
78
110
module .getTopLevelDecls (ret);
79
111
}
80
112
return ret;
81
113
}
82
114
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 ) {
87
120
auto filename = getFilename (module , primaryFile);
88
121
89
122
// The extractor can be called several times from different processes with
@@ -92,7 +125,7 @@ static void extractDeclarations(const SwiftExtractorConfiguration& config,
92
125
auto trapTarget = createTargetTrapFile (config, filename);
93
126
if (!trapTarget) {
94
127
// another process arrived first, nothing to do for us
95
- return ;
128
+ return {} ;
96
129
}
97
130
TrapDomain trap{*trapTarget};
98
131
@@ -116,6 +149,7 @@ static void extractDeclarations(const SwiftExtractorConfiguration& config,
116
149
for (auto & comment : comments) {
117
150
visitor.extract (comment);
118
151
}
152
+ return std::move (visitor).getEncounteredModules ();
119
153
}
120
154
121
155
static std::unordered_set<std::string> collectInputFilenames (swift::CompilerInstance& compiler) {
@@ -132,40 +166,27 @@ static std::unordered_set<std::string> collectInputFilenames(swift::CompilerInst
132
166
return sourceFiles;
133
167
}
134
168
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 );
158
174
}
159
- return allModules ;
175
+ return ret ;
160
176
}
161
177
162
178
void codeql::extractSwiftFiles (const SwiftExtractorConfiguration& config,
163
179
swift::CompilerInstance& compiler) {
164
180
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 ()};
166
183
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 ' ;
168
188
bool isFromSourceFile = false ;
189
+ std::unordered_set<swift::ModuleDecl*> encounteredModules;
169
190
for (auto file : module ->getFiles ()) {
170
191
auto sourceFile = llvm::dyn_cast<swift::SourceFile>(file);
171
192
if (!sourceFile) {
@@ -176,10 +197,16 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
176
197
continue ;
177
198
}
178
199
archiveFile (config, *sourceFile);
179
- extractDeclarations (config, compiler, *module , sourceFile);
200
+ encounteredModules = extractDeclarations (config, compiler, *module , sourceFile);
180
201
}
181
202
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
+ }
183
210
}
184
211
}
185
212
}
0 commit comments