10
10
11
11
#include " swift/extractor/translators/SwiftVisitor.h"
12
12
#include " swift/extractor/infra/TargetDomains.h"
13
- #include " swift/extractor/SwiftBuiltinSymbols.h"
14
13
#include " swift/extractor/infra/file/Path.h"
15
14
#include " swift/extractor/infra/SwiftLocationExtractor.h"
16
15
#include " swift/extractor/infra/SwiftBodyEmissionStrategy.h"
16
+ #include " swift/extractor/mangler/SwiftMangler.h"
17
17
18
18
using namespace codeql ;
19
19
using namespace std ::string_literals;
@@ -43,10 +43,16 @@ static void archiveFile(const SwiftExtractorConfiguration& config, swift::Source
43
43
}
44
44
}
45
45
46
- static fs::path getFilename (swift::ModuleDecl& module , swift::SourceFile* primaryFile) {
46
+ static fs::path getFilename (swift::ModuleDecl& module ,
47
+ swift::SourceFile* primaryFile,
48
+ const swift::Decl* lazyDeclaration) {
47
49
if (primaryFile) {
48
50
return resolvePath (primaryFile->getFilename ());
49
51
}
52
+ if (lazyDeclaration) {
53
+ SwiftMangler mangler;
54
+ return mangler.mangledName (*lazyDeclaration);
55
+ }
50
56
// PCM clang module
51
57
if (module .isNonSwiftModule ()) {
52
58
// Several modules with different names might come from .pcm (clang module) files
@@ -72,60 +78,56 @@ static fs::path getFilename(swift::ModuleDecl& module, swift::SourceFile* primar
72
78
return resolvePath (filename);
73
79
}
74
80
75
- /* The builtin module is special, as it does not publish any top-level declaration
76
- * It creates (and caches) declarations on demand when a lookup is carried out
77
- * (see BuiltinUnit in swift/AST/FileUnit.h for the cache details, and getBuiltinValueDecl in
78
- * swift/AST/Builtins.h for the creation details)
79
- * As we want to create the Builtin trap file once and for all so that it works for other
80
- * extraction runs, rather than collecting what we need we pre-populate the builtin trap with
81
- * what we expect. This list might need thus to be expanded.
82
- * Notice, that while swift/AST/Builtins.def has a list of builtin symbols, it does not contain
83
- * all information required to instantiate builtin variants.
84
- * Other possible approaches:
85
- * * create one trap per builtin declaration when encountered
86
- * * expand the list to all possible builtins (of which there are a lot)
87
- */
88
- static void getBuiltinDecls (swift::ModuleDecl& builtinModule,
89
- llvm::SmallVector<swift::Decl*>& decls) {
90
- llvm::SmallVector<swift::ValueDecl*> values;
91
- for (auto symbol : swiftBuiltins) {
92
- builtinModule.lookupValue (builtinModule.getASTContext ().getIdentifier (symbol),
93
- swift::NLKind::QualifiedLookup, values);
94
- }
95
- decls.insert (decls.end (), values.begin (), values.end ());
96
- }
97
-
98
- static llvm::SmallVector<swift::Decl*> getTopLevelDecls (swift::ModuleDecl& module ,
99
- swift::SourceFile* primaryFile = nullptr ) {
100
- llvm::SmallVector<swift::Decl*> ret;
81
+ static llvm::SmallVector<const swift::Decl*> getTopLevelDecls (swift::ModuleDecl& module ,
82
+ swift::SourceFile* primaryFile,
83
+ const swift::Decl* lazyDeclaration) {
84
+ llvm::SmallVector<const swift::Decl*> ret;
85
+ if (lazyDeclaration) {
86
+ ret.push_back (lazyDeclaration);
87
+ return ret;
88
+ }
101
89
ret.push_back (&module );
90
+ llvm::SmallVector<swift::Decl*> topLevelDecls;
102
91
if (primaryFile) {
103
- primaryFile->getTopLevelDecls (ret);
104
- } else if (module .isBuiltinModule ()) {
105
- getBuiltinDecls (module , ret);
92
+ primaryFile->getTopLevelDecls (topLevelDecls);
106
93
} else {
107
- module .getTopLevelDecls (ret );
94
+ module .getTopLevelDecls (topLevelDecls );
108
95
}
96
+ ret.insert (ret.end (), topLevelDecls.data (), topLevelDecls.data () + topLevelDecls.size ());
109
97
return ret;
110
98
}
111
99
100
+ static TrapType getTrapType (swift::SourceFile* primaryFile, const swift::Decl* lazyDeclaration) {
101
+ if (primaryFile) {
102
+ return TrapType::source;
103
+ }
104
+ if (lazyDeclaration) {
105
+ return TrapType::lazy_declaration;
106
+ }
107
+ return TrapType::module ;
108
+ }
109
+
112
110
static std::unordered_set<swift::ModuleDecl*> extractDeclarations (
113
111
SwiftExtractorState& state,
114
112
swift::CompilerInstance& compiler,
115
113
swift::ModuleDecl& module ,
116
- swift::SourceFile* primaryFile = nullptr ) {
117
- auto filename = getFilename (module , primaryFile);
114
+ swift::SourceFile* primaryFile,
115
+ const swift::Decl* lazyDeclaration) {
116
+ auto filename = getFilename (module , primaryFile, lazyDeclaration);
118
117
if (primaryFile) {
119
118
state.sourceFiles .push_back (filename);
120
119
}
121
120
122
121
// The extractor can be called several times from different processes with
123
122
// the same input file(s). Using `TargetFile` the first process will win, and the following
124
123
// will just skip the work
125
- const auto trapType = primaryFile ? TrapType::source : TrapType:: module ;
124
+ const auto trapType = getTrapType ( primaryFile, lazyDeclaration) ;
126
125
auto trap = createTargetTrapDomain (state, filename, trapType);
127
126
if (!trap) {
128
127
// another process arrived first, nothing to do for us
128
+ if (lazyDeclaration) {
129
+ state.emittedDeclarations .insert (lazyDeclaration);
130
+ }
129
131
return {};
130
132
}
131
133
@@ -143,9 +145,10 @@ static std::unordered_set<swift::ModuleDecl*> extractDeclarations(
143
145
144
146
SwiftLocationExtractor locationExtractor (*trap);
145
147
locationExtractor.emitFile (primaryFile);
146
- SwiftBodyEmissionStrategy bodyEmissionStrategy (module , primaryFile);
147
- SwiftVisitor visitor (compiler.getSourceMgr (), *trap, locationExtractor, bodyEmissionStrategy);
148
- auto topLevelDecls = getTopLevelDecls (module , primaryFile);
148
+ SwiftBodyEmissionStrategy bodyEmissionStrategy (module , primaryFile, lazyDeclaration);
149
+ SwiftVisitor visitor (compiler.getSourceMgr (), state, *trap, locationExtractor,
150
+ bodyEmissionStrategy);
151
+ auto topLevelDecls = getTopLevelDecls (module , primaryFile, lazyDeclaration);
149
152
for (auto decl : topLevelDecls) {
150
153
visitor.extract (decl);
151
154
}
@@ -198,10 +201,12 @@ void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstan
198
201
continue ;
199
202
}
200
203
archiveFile (state.configuration , *sourceFile);
201
- encounteredModules = extractDeclarations (state, compiler, *module , sourceFile);
204
+ encounteredModules =
205
+ extractDeclarations (state, compiler, *module , sourceFile, /* lazy declaration*/ nullptr );
202
206
}
203
207
if (!isFromSourceFile) {
204
- encounteredModules = extractDeclarations (state, compiler, *module );
208
+ encounteredModules = extractDeclarations (state, compiler, *module , /* source file*/ nullptr ,
209
+ /* lazy declaration*/ nullptr );
205
210
}
206
211
for (auto encountered : encounteredModules) {
207
212
if (state.encounteredModules .count (encountered) == 0 ) {
@@ -211,3 +216,37 @@ void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstan
211
216
}
212
217
}
213
218
}
219
+
220
+ static void cleanupPendingDeclarations (SwiftExtractorState& state) {
221
+ std::vector<const swift::Decl*> worklist (std::begin (state.pendingDeclarations ),
222
+ std::end (state.pendingDeclarations ));
223
+ for (auto decl : worklist) {
224
+ if (state.emittedDeclarations .count (decl)) {
225
+ state.pendingDeclarations .erase (decl);
226
+ }
227
+ }
228
+ }
229
+
230
+ static void extractLazy (SwiftExtractorState& state, swift::CompilerInstance& compiler) {
231
+ cleanupPendingDeclarations (state);
232
+ std::vector<const swift::Decl*> worklist (std::begin (state.pendingDeclarations ),
233
+ std::end (state.pendingDeclarations ));
234
+ for (auto pending : worklist) {
235
+ extractDeclarations (state, compiler, *pending->getModuleContext (), /* source file*/ nullptr ,
236
+ pending);
237
+ }
238
+ }
239
+
240
+ void codeql::extractExtractLazyDeclarations (SwiftExtractorState& state,
241
+ swift::CompilerInstance& compiler) {
242
+ // Just in case
243
+ const int upperBound = 100 ;
244
+ int iteration = 0 ;
245
+ while (!state.pendingDeclarations .empty () && iteration++ < upperBound) {
246
+ extractLazy (state, compiler);
247
+ }
248
+ if (iteration >= upperBound) {
249
+ std::cerr << " Swift extractor reached upper bound while extracting lazy declarations\n " ;
250
+ abort ();
251
+ }
252
+ }
0 commit comments