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+ 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,60 +78,56 @@ 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-
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+ }
10189 ret.push_back (&module );
90+ llvm::SmallVector<swift::Decl*> topLevelDecls;
10291 if (primaryFile) {
103- primaryFile->getTopLevelDecls (ret);
104- } else if (module .isBuiltinModule ()) {
105- getBuiltinDecls (module , ret);
92+ primaryFile->getTopLevelDecls (topLevelDecls);
10693 } else {
107- module .getTopLevelDecls (ret );
94+ module .getTopLevelDecls (topLevelDecls );
10895 }
96+ ret.insert (ret.end (), topLevelDecls.data (), topLevelDecls.data () + topLevelDecls.size ());
10997 return ret;
11098}
11199
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+
112110static std::unordered_set<swift::ModuleDecl*> extractDeclarations (
113111 SwiftExtractorState& state,
114112 swift::CompilerInstance& compiler,
115113 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);
118117 if (primaryFile) {
119118 state.sourceFiles .push_back (filename);
120119 }
121120
122121 // The extractor can be called several times from different processes with
123122 // the same input file(s). Using `TargetFile` the first process will win, and the following
124123 // will just skip the work
125- const auto trapType = primaryFile ? TrapType::source : TrapType:: module ;
124+ const auto trapType = getTrapType ( primaryFile, lazyDeclaration) ;
126125 auto trap = createTargetTrapDomain (state, filename, trapType);
127126 if (!trap) {
128127 // another process arrived first, nothing to do for us
128+ if (lazyDeclaration) {
129+ state.emittedDeclarations .insert (lazyDeclaration);
130+ }
129131 return {};
130132 }
131133
@@ -143,9 +145,10 @@ static std::unordered_set<swift::ModuleDecl*> extractDeclarations(
143145
144146 SwiftLocationExtractor locationExtractor (*trap);
145147 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);
149152 for (auto decl : topLevelDecls) {
150153 visitor.extract (decl);
151154 }
@@ -198,10 +201,12 @@ void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstan
198201 continue ;
199202 }
200203 archiveFile (state.configuration , *sourceFile);
201- encounteredModules = extractDeclarations (state, compiler, *module , sourceFile);
204+ encounteredModules =
205+ extractDeclarations (state, compiler, *module , sourceFile, /* lazy declaration*/ nullptr );
202206 }
203207 if (!isFromSourceFile) {
204- encounteredModules = extractDeclarations (state, compiler, *module );
208+ encounteredModules = extractDeclarations (state, compiler, *module , /* source file*/ nullptr ,
209+ /* lazy declaration*/ nullptr );
205210 }
206211 for (auto encountered : encounteredModules) {
207212 if (state.encounteredModules .count (encountered) == 0 ) {
@@ -211,3 +216,37 @@ void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstan
211216 }
212217 }
213218}
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