1010
1111#include " swift/extractor/translators/SwiftVisitor.h"
1212#include " swift/extractor/infra/TargetDomains.h"
13- #include " swift/extractor/SwiftBuiltinSymbols.h"
1413#include " swift/extractor/infra/file/Path.h"
1514#include " swift/extractor/infra/SwiftLocationExtractor.h"
1615#include " swift/extractor/infra/SwiftBodyEmissionStrategy.h"
16+ #include " swift/extractor/mangler/SwiftMangler.h"
1717
1818using namespace codeql ;
1919using namespace std ::string_literals;
@@ -43,10 +43,16 @@ static void archiveFile(const SwiftExtractorConfiguration& config, swift::Source
4343 }
4444}
4545
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) {
4749 if (primaryFile) {
4850 return resolvePath (primaryFile->getFilename ());
4951 }
52+ if (lazyDeclaration) {
53+ static SwiftMangler mangler;
54+ return mangler.mangledName (*lazyDeclaration);
55+ }
5056 // PCM clang module
5157 if (module .isNonSwiftModule ()) {
5258 // 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
7278 return resolvePath (filename);
7379}
7480
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-
9881static llvm::SmallVector<swift::Decl*> getTopLevelDecls (swift::ModuleDecl& module ,
99- swift::SourceFile* primaryFile = nullptr ) {
82+ swift::SourceFile* primaryFile,
83+ const swift::Decl* lazyDeclaration) {
10084 llvm::SmallVector<swift::Decl*> ret;
85+ if (lazyDeclaration) {
86+ ret.push_back (const_cast <swift::Decl*>(lazyDeclaration));
87+ return ret;
88+ }
10189 ret.push_back (&module );
10290 if (primaryFile) {
10391 primaryFile->getTopLevelDecls (ret);
104- } else if (module .isBuiltinModule ()) {
105- getBuiltinDecls (module , ret);
10692 } else {
10793 module .getTopLevelDecls (ret);
10894 }
10995 return ret;
11096}
11197
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+
112108static std::unordered_set<swift::ModuleDecl*> extractDeclarations (
113109 SwiftExtractorState& state,
114110 swift::CompilerInstance& compiler,
115111 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);
118115 if (primaryFile) {
119116 state.sourceFiles .push_back (filename);
120117 }
121118
122119 // The extractor can be called several times from different processes with
123120 // the same input file(s). Using `TargetFile` the first process will win, and the following
124121 // will just skip the work
125- const auto trapType = primaryFile ? TrapType::source : TrapType:: module ;
122+ const auto trapType = getTrapType ( primaryFile, lazyDeclaration) ;
126123 auto trap = createTargetTrapDomain (state, filename, trapType);
127124 if (!trap) {
128125 // another process arrived first, nothing to do for us
@@ -143,9 +140,10 @@ static std::unordered_set<swift::ModuleDecl*> extractDeclarations(
143140
144141 SwiftLocationExtractor locationExtractor (*trap);
145142 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);
149147 for (auto decl : topLevelDecls) {
150148 visitor.extract (decl);
151149 }
@@ -198,10 +196,10 @@ void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstan
198196 continue ;
199197 }
200198 archiveFile (state.configuration , *sourceFile);
201- encounteredModules = extractDeclarations (state, compiler, *module , sourceFile);
199+ encounteredModules = extractDeclarations (state, compiler, *module , sourceFile, nullptr );
202200 }
203201 if (!isFromSourceFile) {
204- encounteredModules = extractDeclarations (state, compiler, *module );
202+ encounteredModules = extractDeclarations (state, compiler, *module , nullptr , nullptr );
205203 }
206204 for (auto encountered : encounteredModules) {
207205 if (state.encounteredModules .count (encountered) == 0 ) {
@@ -211,3 +209,40 @@ void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstan
211209 }
212210 }
213211}
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