Skip to content

Commit 065fecc

Browse files
committed
Swift: extract precompiled swiftmodule files
Previously we were not extracting any `swiftmodule` file that was not a system or a built-in one. This was done to avoid re-extracting `swiftmodule` files that were built previously in the same build, but it turned out to be too eager, as there are legitimate cases where a non-system, non-built-in precompiled swift module can be used. An example of that is the `PackageDescription` module used in Swift Package Manager manifest files (`Package.swift`). We now relax the test and trigger module extraction on all loaded modules that do not have source files (we trigger source file extraction for those). The catch, is that we also create empty trap files for current output `swiftmodule` files (including possible alias locations set up by XCode). This means that if a following extractor run loads a previously built `swiftmodule` file, although it will trigger module extraction, this will however be skipped as it will find its target file already present (this is done via the `TargetFile` semantics).
1 parent 9876c39 commit 065fecc

File tree

7 files changed

+46
-16
lines changed

7 files changed

+46
-16
lines changed

swift/extractor/SwiftExtractor.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -165,22 +165,31 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
165165
auto inputFiles = collectInputFilenames(compiler);
166166
auto modules = collectModules(compiler);
167167

168+
// we want to make sure any following extractor run will not try to extract things from
169+
// the swiftmodule files we are creating in this run, as those things will already have been
170+
// extracted from source with more information. We do this by creating empty trap files.
171+
// TargetFile semantics will ensure any following run trying to extract that swiftmodule will just
172+
// skip doing it
173+
auto outputModuleTrapSuffix = "-" + compiler.getMainModule()->getName().str().str() + ".trap";
174+
for (const auto& output : config.outputSwiftModules) {
175+
TargetFile::create(output + outputModuleTrapSuffix, config.trapDir, config.getTempTrapDir());
176+
}
168177
for (auto& module : modules) {
169-
// We only extract system and builtin modules here as the other "user" modules can be built
170-
// during the build process and then re-used at a later stage. In this case, we extract the
171-
// user code twice: once during the module build in a form of a source file, and then as
172-
// a pre-built module during building of the dependent source files.
173-
if (module->isSystemModule() || module->isBuiltinModule()) {
174-
extractDeclarations(config, compiler, *module);
175-
} else {
176-
for (auto file : module->getFiles()) {
177-
auto sourceFile = llvm::dyn_cast<swift::SourceFile>(file);
178-
if (!sourceFile || inputFiles.count(sourceFile->getFilename().str()) == 0) {
179-
continue;
180-
}
181-
archiveFile(config, *sourceFile);
182-
extractDeclarations(config, compiler, *module, sourceFile);
178+
bool isFromSourceFile = false;
179+
for (auto file : module->getFiles()) {
180+
auto sourceFile = llvm::dyn_cast<swift::SourceFile>(file);
181+
if (!sourceFile) {
182+
continue;
183+
}
184+
isFromSourceFile = true;
185+
if (inputFiles.count(sourceFile->getFilename().str()) == 0) {
186+
continue;
183187
}
188+
archiveFile(config, *sourceFile);
189+
extractDeclarations(config, compiler, *module, sourceFile);
190+
}
191+
if (!isFromSourceFile) {
192+
extractDeclarations(config, compiler, *module);
184193
}
185194
}
186195
}

swift/extractor/SwiftExtractorConfiguration.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,9 @@ struct SwiftExtractorConfiguration {
3232
// A temporary directory that contains build artifacts generated by the extractor during the
3333
// overall extraction process.
3434
std::string getTempArtifactDir() const { return scratchDir + "/swift-extraction-artifacts"; }
35+
36+
// Output swiftmodule files. This also includes possible locations where XCode internally moves
37+
// modules
38+
std::vector<std::string> outputSwiftModules;
3539
};
3640
} // namespace codeql

swift/extractor/SwiftOutputRewrite.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ static std::vector<std::string> computeModuleAliases(llvm::StringRef modulePath,
163163
namespace codeql {
164164

165165
std::unordered_map<std::string, std::string> rewriteOutputsInPlace(
166-
SwiftExtractorConfiguration& config,
166+
const SwiftExtractorConfiguration& config,
167167
std::vector<std::string>& CLIArgs) {
168168
std::unordered_map<std::string, std::string> remapping;
169169

@@ -323,5 +323,15 @@ std::vector<std::string> collectVFSFiles(const SwiftExtractorConfiguration& conf
323323

324324
return overlays;
325325
}
326+
std::vector<std::string> getOutputSwiftModules(
327+
const std::unordered_map<std::string, std::string>& remapping) {
328+
std::vector<std::string> ret;
329+
for (const auto& [oldPath, newPath] : remapping) {
330+
if (llvm::StringRef(oldPath).endswith(".swiftmodule")) {
331+
ret.push_back(oldPath);
332+
}
333+
}
334+
return ret;
335+
}
326336

327337
} // namespace codeql

swift/extractor/SwiftOutputRewrite.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ struct SwiftExtractorConfiguration;
1313
// artifacts produced by the actual Swift compiler.
1414
// Returns the map containing remapping oldpath -> newPath.
1515
std::unordered_map<std::string, std::string> rewriteOutputsInPlace(
16-
SwiftExtractorConfiguration& config,
16+
const SwiftExtractorConfiguration& config,
1717
std::vector<std::string>& CLIArgs);
1818

1919
// Create directories for all the redirected new paths as the Swift compiler expects them to exist.
@@ -29,4 +29,7 @@ void storeRemappingForVFS(const SwiftExtractorConfiguration& config,
2929
// This is separate from storeRemappingForVFS as we also collect files produced by other processes.
3030
std::vector<std::string> collectVFSFiles(const SwiftExtractorConfiguration& config);
3131

32+
// Returns a list of output remapped swift module files
33+
std::vector<std::string> getOutputSwiftModules(
34+
const std::unordered_map<std::string, std::string>& remapping);
3235
} // namespace codeql

swift/extractor/main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ int main(int argc, char** argv) {
6868
codeql::rewriteOutputsInPlace(configuration, configuration.patchedFrontendOptions);
6969
codeql::ensureDirectoriesForNewPathsExist(remapping);
7070
codeql::storeRemappingForVFS(configuration, remapping);
71+
configuration.outputSwiftModules = codeql::getOutputSwiftModules(remapping);
7172

7273
std::vector<const char*> args;
7374
for (auto& arg : configuration.patchedFrontendOptions) {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
| file://:0:0:0:0 | A |
22
| file://:0:0:0:0 | B |
3+
| file://:0:0:0:0 | PackageDescription |
34
| file://:0:0:0:0 | main |
45
| file://:0:0:0:0 | partial_modules |

swift/integration-tests/runner.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ def main(opts):
6262
]
6363
if opts.check_databases:
6464
cmd.append("--check-databases")
65+
else:
66+
cmd.append("--no-check-databases")
6567
if opts.learn:
6668
cmd.append("--learn")
6769
cmd.extend(str(t.parent) for t in succesful_db_creation)

0 commit comments

Comments
 (0)