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
+ static 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,57 +78,48 @@ 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
81
static llvm::SmallVector<swift::Decl*> getTopLevelDecls (swift::ModuleDecl& module ,
99
- swift::SourceFile* primaryFile = nullptr ) {
82
+ swift::SourceFile* primaryFile,
83
+ const swift::Decl* lazyDeclaration) {
100
84
llvm::SmallVector<swift::Decl*> ret;
85
+ if (lazyDeclaration) {
86
+ ret.push_back (const_cast <swift::Decl*>(lazyDeclaration));
87
+ return ret;
88
+ }
101
89
ret.push_back (&module );
102
90
if (primaryFile) {
103
91
primaryFile->getTopLevelDecls (ret);
104
- } else if (module .isBuiltinModule ()) {
105
- getBuiltinDecls (module , ret);
106
92
} else {
107
93
module .getTopLevelDecls (ret);
108
94
}
109
95
return ret;
110
96
}
111
97
98
+ static TrapType getTrapType (swift::SourceFile* primaryFile, const swift::Decl* lazyDeclaration) {
99
+ if (primaryFile) {
100
+ return TrapType::source;
101
+ }
102
+ if (lazyDeclaration) {
103
+ return TrapType::lazy_declarations;
104
+ }
105
+ return TrapType::module ;
106
+ }
107
+
112
108
static std::unordered_set<swift::ModuleDecl*> extractDeclarations (
113
109
SwiftExtractorState& state,
114
110
swift::CompilerInstance& compiler,
115
111
swift::ModuleDecl& module ,
116
- swift::SourceFile* primaryFile = nullptr ) {
117
- auto filename = getFilename (module , primaryFile);
112
+ swift::SourceFile* primaryFile,
113
+ const swift::Decl* lazyDeclaration) {
114
+ auto filename = getFilename (module , primaryFile, lazyDeclaration);
118
115
if (primaryFile) {
119
116
state.sourceFiles .push_back (filename);
120
117
}
121
118
122
119
// The extractor can be called several times from different processes with
123
120
// the same input file(s). Using `TargetFile` the first process will win, and the following
124
121
// will just skip the work
125
- const auto trapType = primaryFile ? TrapType::source : TrapType:: module ;
122
+ const auto trapType = getTrapType ( primaryFile, lazyDeclaration) ;
126
123
auto trap = createTargetTrapDomain (state, filename, trapType);
127
124
if (!trap) {
128
125
// another process arrived first, nothing to do for us
@@ -143,9 +140,10 @@ static std::unordered_set<swift::ModuleDecl*> extractDeclarations(
143
140
144
141
SwiftLocationExtractor locationExtractor (*trap);
145
142
locationExtractor.emitFile (primaryFile);
146
- SwiftBodyEmissionStrategy bodyEmissionStrategy (module , primaryFile);
147
- SwiftVisitor visitor (compiler.getSourceMgr (), *trap, locationExtractor, bodyEmissionStrategy);
148
- auto topLevelDecls = getTopLevelDecls (module , primaryFile);
143
+ SwiftBodyEmissionStrategy bodyEmissionStrategy (module , primaryFile, lazyDeclaration);
144
+ SwiftVisitor visitor (compiler.getSourceMgr (), state, *trap, locationExtractor,
145
+ bodyEmissionStrategy);
146
+ auto topLevelDecls = getTopLevelDecls (module , primaryFile, lazyDeclaration);
149
147
for (auto decl : topLevelDecls) {
150
148
visitor.extract (decl);
151
149
}
@@ -198,10 +196,10 @@ void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstan
198
196
continue ;
199
197
}
200
198
archiveFile (state.configuration , *sourceFile);
201
- encounteredModules = extractDeclarations (state, compiler, *module , sourceFile);
199
+ encounteredModules = extractDeclarations (state, compiler, *module , sourceFile, nullptr );
202
200
}
203
201
if (!isFromSourceFile) {
204
- encounteredModules = extractDeclarations (state, compiler, *module );
202
+ encounteredModules = extractDeclarations (state, compiler, *module , nullptr , nullptr );
205
203
}
206
204
for (auto encountered : encounteredModules) {
207
205
if (state.encounteredModules .count (encountered) == 0 ) {
@@ -211,3 +209,40 @@ void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstan
211
209
}
212
210
}
213
211
}
212
+
213
+ static void cleanupPendingDeclarations (SwiftExtractorState& state) {
214
+ std::vector<const swift::Decl*> worklist;
215
+ std::copy (std::begin (state.pendingDeclarations ), std::end (state.pendingDeclarations ),
216
+ std::back_inserter (worklist));
217
+
218
+ for (auto decl : worklist) {
219
+ if (state.emittedDeclarations .count (decl)) {
220
+ state.pendingDeclarations .erase (decl);
221
+ }
222
+ }
223
+ }
224
+
225
+ static void extractLazy (SwiftExtractorState& state, swift::CompilerInstance& compiler) {
226
+ cleanupPendingDeclarations (state);
227
+ std::vector<const swift::Decl*> worklist;
228
+ std::copy (std::begin (state.pendingDeclarations ), std::end (state.pendingDeclarations ),
229
+ std::back_inserter (worklist));
230
+
231
+ for (auto pending : worklist) {
232
+ extractDeclarations (state, compiler, *pending->getModuleContext (), nullptr , pending);
233
+ }
234
+ }
235
+
236
+ void codeql::extractExtractLazyDeclarations (SwiftExtractorState& state,
237
+ swift::CompilerInstance& compiler) {
238
+ // Just in case
239
+ const int upperBound = 100 ;
240
+ int iteration = 0 ;
241
+ while (!state.pendingDeclarations .empty () && iteration++ < upperBound) {
242
+ extractLazy (state, compiler);
243
+ }
244
+ if (iteration >= upperBound) {
245
+ std::cerr << " Swift extractor reach upper bound while extracting lazy declarations\n " ;
246
+ abort ();
247
+ }
248
+ }
0 commit comments