@@ -49,14 +49,15 @@ static void archiveFile(const SwiftExtractorConfiguration& config, swift::Source
4949 }
5050}
5151
52- static void extractFile (const SwiftExtractorConfiguration& config,
53- swift::CompilerInstance& compiler,
54- swift::SourceFile& file) {
52+ static void extractDeclarations (const SwiftExtractorConfiguration& config,
53+ swift::CompilerInstance& compiler,
54+ llvm::StringRef filename,
55+ llvm::ArrayRef<swift::Decl*> topLevelDecls) {
5556 // The extractor can be called several times from different processes with
5657 // the same input file(s)
5758 // We are using PID to avoid concurrent access
5859 // TODO: find a more robust approach to avoid collisions?
59- std::string tempTrapName = file. getFilename () .str () + ' .' + std::to_string (getpid ()) + " .trap" ;
60+ std::string tempTrapName = filename .str () + ' .' + std::to_string (getpid ()) + " .trap" ;
6061 llvm::SmallString<PATH_MAX> tempTrapPath (config.trapDir );
6162 llvm::sys::path::append (tempTrapPath, tempTrapName);
6263
@@ -84,7 +85,7 @@ static void extractFile(const SwiftExtractorConfiguration& config,
8485 TrapOutput trap{trapStream};
8586 TrapArena arena{};
8687
87- // TODO move default location emission elsewhere, possibly in a separate global trap file
88+ // TODO: move default location emission elsewhere, possibly in a separate global trap file
8889 auto unknownFileLabel = arena.allocateLabel <FileTag>();
8990 // the following cannot conflict with actual files as those have an absolute path starting with /
9091 trap.assignKey (unknownFileLabel, " unknown" );
@@ -93,22 +94,23 @@ static void extractFile(const SwiftExtractorConfiguration& config,
9394 trap.assignKey (unknownLocationLabel, " unknown" );
9495 trap.emit (LocationsTrap{unknownLocationLabel, unknownFileLabel});
9596
96- // In the case of emtpy files, the dispatcher is not called, but we still want to 'record' the
97- // fact that the file was extracted
98- // TODO: to be moved elsewhere
99- llvm::SmallString<PATH_MAX> srcFilePath (file.getFilename ());
100- llvm::sys::fs::make_absolute (srcFilePath);
101- auto fileLabel = arena.allocateLabel <FileTag>();
102- trap.assignKey (fileLabel, srcFilePath.str ().str ());
103- trap.emit (FilesTrap{fileLabel, srcFilePath.str ().str ()});
104-
10597 SwiftVisitor visitor (compiler.getSourceMgr (), arena, trap);
106- for (swift::Decl* decl : file. getTopLevelDecls () ) {
98+ for (swift::Decl* decl : topLevelDecls ) {
10799 visitor.extract (decl);
108100 }
101+ if (topLevelDecls.empty ()) {
102+ // In the case of emtpy files, the dispatcher is not called, but we still want to 'record' the
103+ // fact that the file was extracted
104+ // TODO: to be moved elsewhere
105+ llvm::SmallString<PATH_MAX> srcFilePath (filename);
106+ llvm::sys::fs::make_absolute (srcFilePath);
107+ auto fileLabel = arena.allocateLabel <FileTag>();
108+ trap.assignKey (fileLabel, srcFilePath.str ().str ());
109+ trap.emit (FilesTrap{fileLabel, srcFilePath.str ().str ()});
110+ }
109111
110112 // TODO: Pick a better name to avoid collisions
111- std::string trapName = file. getFilename () .str () + " .trap" ;
113+ std::string trapName = filename .str () + " .trap" ;
112114 llvm::SmallString<PATH_MAX> trapPath (config.trapDir );
113115 llvm::sys::path::append (trapPath, trapName);
114116
@@ -121,10 +123,24 @@ static void extractFile(const SwiftExtractorConfiguration& config,
121123
122124void codeql::extractSwiftFiles (const SwiftExtractorConfiguration& config,
123125 swift::CompilerInstance& compiler) {
124- // The extraction will only work if one (or more) `-primary-file` CLI option is provided, which
125- // is what always happen in case of `swift build` and `xcodebuild`
126- for (auto s : compiler.getPrimarySourceFiles ()) {
127- archiveFile (config, *s);
128- extractFile (config, compiler, *s);
126+ for (auto & [_, module ] : compiler.getASTContext ().getLoadedModules ()) {
127+ // We only extract system and builtin modules here as the other "user" modules can be built
128+ // during the build process and then re-used at a later stage. In this case, we extract the
129+ // user code twice: once during the module build in a form of a source file, and then as
130+ // a pre-built module during building of the dependent source files.
131+ if (module ->isSystemModule () || module ->isBuiltinModule ()) {
132+ llvm::SmallVector<swift::Decl*> decls;
133+ module ->getTopLevelDecls (decls);
134+ // TODO: pass ModuleDecl directly when we have module extraction in place?
135+ extractDeclarations (config, compiler, module ->getModuleFilename (), decls);
136+ } else {
137+ // The extraction will only work if one (or more) `-primary-file` CLI option is provided,
138+ // which is what always happens in case of `swift build` and `xcodebuild`
139+ for (auto primaryFile : module ->getPrimarySourceFiles ()) {
140+ archiveFile (config, *primaryFile);
141+ extractDeclarations (config, compiler, primaryFile->getFilename (),
142+ primaryFile->getTopLevelDecls ());
143+ }
144+ }
129145 }
130146}
0 commit comments