diff --git a/swift/extractor/SwiftExtractor.cpp b/swift/extractor/SwiftExtractor.cpp index 967b4d49364..8c3cdab590b 100644 --- a/swift/extractor/SwiftExtractor.cpp +++ b/swift/extractor/SwiftExtractor.cpp @@ -109,7 +109,7 @@ static llvm::SmallVector getTopLevelDecls(swift::ModuleDecl& modul } static std::unordered_set extractDeclarations( - const SwiftExtractorConfiguration& config, + SwiftExtractorState& state, swift::CompilerInstance& compiler, swift::ModuleDecl& module, swift::SourceFile* primaryFile = nullptr) { @@ -118,7 +118,7 @@ static std::unordered_set extractDeclarations( // The extractor can be called several times from different processes with // the same input file(s). Using `TargetFile` the first process will win, and the following // will just skip the work - auto trap = createTargetTrapDomain(config, filename); + auto trap = createTargetTrapDomain(state, filename); if (!trap) { // another process arrived first, nothing to do for us return {}; @@ -170,8 +170,7 @@ static std::vector collectLoadedModules(swift::CompilerInsta return ret; } -void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config, - swift::CompilerInstance& compiler) { +void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstance& compiler) { auto inputFiles = collectInputFilenames(compiler); std::vector todo = collectLoadedModules(compiler); std::unordered_set seen{todo.begin(), todo.end()}; @@ -190,11 +189,11 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config, if (inputFiles.count(sourceFile->getFilename().str()) == 0) { continue; } - archiveFile(config, *sourceFile); - encounteredModules = extractDeclarations(config, compiler, *module, sourceFile); + archiveFile(state.configuration, *sourceFile); + encounteredModules = extractDeclarations(state, compiler, *module, sourceFile); } if (!isFromSourceFile) { - encounteredModules = extractDeclarations(config, compiler, *module); + encounteredModules = extractDeclarations(state, compiler, *module); } for (auto encountered : encounteredModules) { if (seen.count(encountered) == 0) { diff --git a/swift/extractor/SwiftExtractor.h b/swift/extractor/SwiftExtractor.h index d59c3163390..b3cf98b6a59 100644 --- a/swift/extractor/SwiftExtractor.h +++ b/swift/extractor/SwiftExtractor.h @@ -1,11 +1,10 @@ #pragma once -#include "swift/extractor/config/SwiftExtractorConfiguration.h" +#include "swift/extractor/config/SwiftExtractorState.h" #include #include #include namespace codeql { -void extractSwiftFiles(const SwiftExtractorConfiguration& config, - swift::CompilerInstance& compiler); +void extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstance& compiler); } // namespace codeql diff --git a/swift/extractor/TargetTrapDomain.cpp b/swift/extractor/TargetTrapDomain.cpp index 7367da598c8..e5cfae8d940 100644 --- a/swift/extractor/TargetTrapDomain.cpp +++ b/swift/extractor/TargetTrapDomain.cpp @@ -1,13 +1,15 @@ #include "swift/extractor/TargetTrapDomain.h" #include namespace codeql { -std::optional createTargetTrapDomain(const SwiftExtractorConfiguration& configuration, +std::optional createTargetTrapDomain(SwiftExtractorState& state, const std::filesystem::path& target) { auto trap = target; trap += ".trap"; - if (auto ret = TargetFile::create(trap, configuration.trapDir, configuration.getTempTrapDir())) { + state.traps.push_back(trap.relative_path()); + if (auto ret = TargetFile::create(trap, state.configuration.trapDir, + state.configuration.getTempTrapDir())) { *ret << "/* extractor-args:\n"; - for (const auto& opt : configuration.frontendOptions) { + for (const auto& opt : state.configuration.frontendOptions) { *ret << " " << std::quoted(opt) << " \\\n"; } *ret << "\n*/\n"; diff --git a/swift/extractor/TargetTrapDomain.h b/swift/extractor/TargetTrapDomain.h index 6a780ca565e..e9e9cf4ef04 100644 --- a/swift/extractor/TargetTrapDomain.h +++ b/swift/extractor/TargetTrapDomain.h @@ -1,11 +1,11 @@ #pragma once #include "swift/extractor/trap/TrapDomain.h" -#include "swift/extractor/config/SwiftExtractorConfiguration.h" +#include "swift/extractor/config/SwiftExtractorState.h" namespace codeql { -std::optional createTargetTrapDomain(const SwiftExtractorConfiguration& configuration, +std::optional createTargetTrapDomain(SwiftExtractorState& state, const std::filesystem::path& target); } // namespace codeql diff --git a/swift/extractor/config/SwiftExtractorState.h b/swift/extractor/config/SwiftExtractorState.h new file mode 100644 index 00000000000..58fc7b29c49 --- /dev/null +++ b/swift/extractor/config/SwiftExtractorState.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include + +#include "swift/extractor/config/SwiftExtractorConfiguration.h" + +namespace codeql { +struct SwiftExtractorState { + const SwiftExtractorConfiguration configuration; + + // All the trap files related to this extraction. This may also include trap files generated in a + // previous run but that this run requested as well. Paths are relative to `configuration.trapDir` + std::vector traps; +}; + +} // namespace codeql diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp index 1c5236c30cd..0c89a48161e 100644 --- a/swift/extractor/main.cpp +++ b/swift/extractor/main.cpp @@ -21,12 +21,12 @@ using namespace std::string_literals; // must be called before processFrontendOptions modifies output paths -static void lockOutputSwiftModuleTraps(const codeql::SwiftExtractorConfiguration& config, +static void lockOutputSwiftModuleTraps(codeql::SwiftExtractorState& state, const swift::FrontendOptions& options) { for (const auto& input : options.InputsAndOutputs.getAllInputs()) { if (const auto& module = input.getPrimarySpecificPaths().SupplementaryOutputs.ModuleOutputPath; !module.empty()) { - if (auto target = codeql::createTargetTrapDomain(config, codeql::resolvePath(module))) { + if (auto target = codeql::createTargetTrapDomain(state, codeql::resolvePath(module))) { target->emit("// trap file deliberately empty\n" "// this swiftmodule was created during the build, so its entities must have" " been extracted directly from source files"); @@ -65,18 +65,18 @@ static void processFrontendOptions(swift::FrontendOptions& options) { } } +codeql::TrapDomain invocationTrapDomain(codeql::SwiftExtractorState& state); + // This is part of the swiftFrontendTool interface, we hook into the // compilation pipeline and extract files after the Swift frontend performed // semantic analysis class Observer : public swift::FrontendObserver { public: - explicit Observer(const codeql::SwiftExtractorConfiguration& config, - codeql::SwiftDiagnosticsConsumer& diagConsumer) - : config{config}, diagConsumer{diagConsumer} {} + explicit Observer(const codeql::SwiftExtractorConfiguration& config) : state{config} {} void parsedArgs(swift::CompilerInvocation& invocation) override { auto& options = invocation.getFrontendOptions(); - lockOutputSwiftModuleTraps(config, options); + lockOutputSwiftModuleTraps(state, options); processFrontendOptions(options); } @@ -85,12 +85,13 @@ class Observer : public swift::FrontendObserver { } void performedSemanticAnalysis(swift::CompilerInstance& compiler) override { - codeql::extractSwiftFiles(config, compiler); + codeql::extractSwiftFiles(state, compiler); } private: - const codeql::SwiftExtractorConfiguration& config; - codeql::SwiftDiagnosticsConsumer& diagConsumer; + codeql::SwiftExtractorState state; + codeql::TrapDomain invocationTrap{invocationTrapDomain(state)}; + codeql::SwiftDiagnosticsConsumer diagConsumer{invocationTrap}; }; static std::string getenv_or(const char* envvar, const std::string& def) { @@ -145,11 +146,11 @@ static void checkWhetherToRunUnderTool(int argc, char* const* argv) { // Creates a target file that should store per-invocation info, e.g. compilation args, // compilations, diagnostics, etc. -codeql::TrapDomain invocationTrapDomain(const codeql::SwiftExtractorConfiguration& configuration) { +codeql::TrapDomain invocationTrapDomain(codeql::SwiftExtractorState& state) { auto timestamp = std::chrono::system_clock::now().time_since_epoch().count(); auto filename = std::to_string(timestamp) + '-' + std::to_string(getpid()); auto target = std::filesystem::path("invocations") / std::filesystem::path(filename); - auto maybeDomain = codeql::createTargetTrapDomain(configuration, target); + auto maybeDomain = codeql::createTargetTrapDomain(state, target); if (!maybeDomain) { std::cerr << "Cannot create invocation trap file: " << target << "\n"; abort(); @@ -183,9 +184,7 @@ int main(int argc, char** argv) { auto openInterception = codeql::setupFileInterception(configuration); - auto invocationDomain = invocationTrapDomain(configuration); - codeql::SwiftDiagnosticsConsumer diagConsumer(invocationDomain); - Observer observer(configuration, diagConsumer); + Observer observer(configuration); int frontend_rc = swift::performFrontend(configuration.frontendOptions, "swift-extractor", (void*)main, &observer);