@@ -49,14 +49,15 @@ static void archiveFile(const SwiftExtractorConfiguration& config, swift::Source
49
49
}
50
50
}
51
51
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) {
55
56
// The extractor can be called several times from different processes with
56
57
// the same input file(s)
57
58
// We are using PID to avoid concurrent access
58
59
// 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" ;
60
61
llvm::SmallString<PATH_MAX> tempTrapPath (config.trapDir );
61
62
llvm::sys::path::append (tempTrapPath, tempTrapName);
62
63
@@ -84,7 +85,7 @@ static void extractFile(const SwiftExtractorConfiguration& config,
84
85
TrapOutput trap{trapStream};
85
86
TrapArena arena{};
86
87
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
88
89
auto unknownFileLabel = arena.allocateLabel <FileTag>();
89
90
// the following cannot conflict with actual files as those have an absolute path starting with /
90
91
trap.assignKey (unknownFileLabel, " unknown" );
@@ -93,22 +94,23 @@ static void extractFile(const SwiftExtractorConfiguration& config,
93
94
trap.assignKey (unknownLocationLabel, " unknown" );
94
95
trap.emit (LocationsTrap{unknownLocationLabel, unknownFileLabel});
95
96
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
-
105
97
SwiftVisitor visitor (compiler.getSourceMgr (), arena, trap);
106
- for (swift::Decl* decl : file. getTopLevelDecls () ) {
98
+ for (swift::Decl* decl : topLevelDecls ) {
107
99
visitor.extract (decl);
108
100
}
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
+ }
109
111
110
112
// TODO: Pick a better name to avoid collisions
111
- std::string trapName = file. getFilename () .str () + " .trap" ;
113
+ std::string trapName = filename .str () + " .trap" ;
112
114
llvm::SmallString<PATH_MAX> trapPath (config.trapDir );
113
115
llvm::sys::path::append (trapPath, trapName);
114
116
@@ -121,10 +123,24 @@ static void extractFile(const SwiftExtractorConfiguration& config,
121
123
122
124
void codeql::extractSwiftFiles (const SwiftExtractorConfiguration& config,
123
125
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
+ }
129
145
}
130
146
}
0 commit comments