mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
Swift: collect TRAP files related to an extractor run
In order to do this a mutable `SwiftExtractorState` is introduced.
This commit is contained in:
@@ -109,7 +109,7 @@ static llvm::SmallVector<swift::Decl*> getTopLevelDecls(swift::ModuleDecl& modul
|
|||||||
}
|
}
|
||||||
|
|
||||||
static std::unordered_set<swift::ModuleDecl*> extractDeclarations(
|
static std::unordered_set<swift::ModuleDecl*> extractDeclarations(
|
||||||
const SwiftExtractorConfiguration& config,
|
SwiftExtractorState& state,
|
||||||
swift::CompilerInstance& compiler,
|
swift::CompilerInstance& compiler,
|
||||||
swift::ModuleDecl& module,
|
swift::ModuleDecl& module,
|
||||||
swift::SourceFile* primaryFile = nullptr) {
|
swift::SourceFile* primaryFile = nullptr) {
|
||||||
@@ -118,7 +118,7 @@ static std::unordered_set<swift::ModuleDecl*> extractDeclarations(
|
|||||||
// The extractor can be called several times from different processes with
|
// 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
|
// the same input file(s). Using `TargetFile` the first process will win, and the following
|
||||||
// will just skip the work
|
// will just skip the work
|
||||||
auto trap = createTargetTrapDomain(config, filename);
|
auto trap = createTargetTrapDomain(state, filename);
|
||||||
if (!trap) {
|
if (!trap) {
|
||||||
// another process arrived first, nothing to do for us
|
// another process arrived first, nothing to do for us
|
||||||
return {};
|
return {};
|
||||||
@@ -170,8 +170,7 @@ static std::vector<swift::ModuleDecl*> collectLoadedModules(swift::CompilerInsta
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
|
void codeql::extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstance& compiler) {
|
||||||
swift::CompilerInstance& compiler) {
|
|
||||||
auto inputFiles = collectInputFilenames(compiler);
|
auto inputFiles = collectInputFilenames(compiler);
|
||||||
std::vector<swift::ModuleDecl*> todo = collectLoadedModules(compiler);
|
std::vector<swift::ModuleDecl*> todo = collectLoadedModules(compiler);
|
||||||
std::unordered_set<swift::ModuleDecl*> seen{todo.begin(), todo.end()};
|
std::unordered_set<swift::ModuleDecl*> seen{todo.begin(), todo.end()};
|
||||||
@@ -190,11 +189,11 @@ void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
|
|||||||
if (inputFiles.count(sourceFile->getFilename().str()) == 0) {
|
if (inputFiles.count(sourceFile->getFilename().str()) == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
archiveFile(config, *sourceFile);
|
archiveFile(state.configuration, *sourceFile);
|
||||||
encounteredModules = extractDeclarations(config, compiler, *module, sourceFile);
|
encounteredModules = extractDeclarations(state, compiler, *module, sourceFile);
|
||||||
}
|
}
|
||||||
if (!isFromSourceFile) {
|
if (!isFromSourceFile) {
|
||||||
encounteredModules = extractDeclarations(config, compiler, *module);
|
encounteredModules = extractDeclarations(state, compiler, *module);
|
||||||
}
|
}
|
||||||
for (auto encountered : encounteredModules) {
|
for (auto encountered : encounteredModules) {
|
||||||
if (seen.count(encountered) == 0) {
|
if (seen.count(encountered) == 0) {
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "swift/extractor/config/SwiftExtractorConfiguration.h"
|
#include "swift/extractor/config/SwiftExtractorState.h"
|
||||||
#include <swift/AST/SourceFile.h>
|
#include <swift/AST/SourceFile.h>
|
||||||
#include <swift/Frontend/Frontend.h>
|
#include <swift/Frontend/Frontend.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace codeql {
|
namespace codeql {
|
||||||
void extractSwiftFiles(const SwiftExtractorConfiguration& config,
|
void extractSwiftFiles(SwiftExtractorState& state, swift::CompilerInstance& compiler);
|
||||||
swift::CompilerInstance& compiler);
|
|
||||||
} // namespace codeql
|
} // namespace codeql
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
#include "swift/extractor/TargetTrapDomain.h"
|
#include "swift/extractor/TargetTrapDomain.h"
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
namespace codeql {
|
namespace codeql {
|
||||||
std::optional<TrapDomain> createTargetTrapDomain(const SwiftExtractorConfiguration& configuration,
|
std::optional<TrapDomain> createTargetTrapDomain(SwiftExtractorState& state,
|
||||||
const std::filesystem::path& target) {
|
const std::filesystem::path& target) {
|
||||||
auto trap = target;
|
auto trap = target;
|
||||||
trap += ".trap";
|
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";
|
*ret << "/* extractor-args:\n";
|
||||||
for (const auto& opt : configuration.frontendOptions) {
|
for (const auto& opt : state.configuration.frontendOptions) {
|
||||||
*ret << " " << std::quoted(opt) << " \\\n";
|
*ret << " " << std::quoted(opt) << " \\\n";
|
||||||
}
|
}
|
||||||
*ret << "\n*/\n";
|
*ret << "\n*/\n";
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "swift/extractor/trap/TrapDomain.h"
|
#include "swift/extractor/trap/TrapDomain.h"
|
||||||
#include "swift/extractor/config/SwiftExtractorConfiguration.h"
|
#include "swift/extractor/config/SwiftExtractorState.h"
|
||||||
|
|
||||||
namespace codeql {
|
namespace codeql {
|
||||||
|
|
||||||
std::optional<TrapDomain> createTargetTrapDomain(const SwiftExtractorConfiguration& configuration,
|
std::optional<TrapDomain> createTargetTrapDomain(SwiftExtractorState& state,
|
||||||
const std::filesystem::path& target);
|
const std::filesystem::path& target);
|
||||||
|
|
||||||
} // namespace codeql
|
} // namespace codeql
|
||||||
|
|||||||
19
swift/extractor/config/SwiftExtractorState.h
Normal file
19
swift/extractor/config/SwiftExtractorState.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include <swift/AST/Decl.h>
|
||||||
|
|
||||||
|
#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<std::filesystem::path> traps;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace codeql
|
||||||
@@ -21,12 +21,12 @@
|
|||||||
using namespace std::string_literals;
|
using namespace std::string_literals;
|
||||||
|
|
||||||
// must be called before processFrontendOptions modifies output paths
|
// 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) {
|
const swift::FrontendOptions& options) {
|
||||||
for (const auto& input : options.InputsAndOutputs.getAllInputs()) {
|
for (const auto& input : options.InputsAndOutputs.getAllInputs()) {
|
||||||
if (const auto& module = input.getPrimarySpecificPaths().SupplementaryOutputs.ModuleOutputPath;
|
if (const auto& module = input.getPrimarySpecificPaths().SupplementaryOutputs.ModuleOutputPath;
|
||||||
!module.empty()) {
|
!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"
|
target->emit("// trap file deliberately empty\n"
|
||||||
"// this swiftmodule was created during the build, so its entities must have"
|
"// this swiftmodule was created during the build, so its entities must have"
|
||||||
" been extracted directly from source files");
|
" 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
|
// This is part of the swiftFrontendTool interface, we hook into the
|
||||||
// compilation pipeline and extract files after the Swift frontend performed
|
// compilation pipeline and extract files after the Swift frontend performed
|
||||||
// semantic analysis
|
// semantic analysis
|
||||||
class Observer : public swift::FrontendObserver {
|
class Observer : public swift::FrontendObserver {
|
||||||
public:
|
public:
|
||||||
explicit Observer(const codeql::SwiftExtractorConfiguration& config,
|
explicit Observer(const codeql::SwiftExtractorConfiguration& config) : state{config} {}
|
||||||
codeql::SwiftDiagnosticsConsumer& diagConsumer)
|
|
||||||
: config{config}, diagConsumer{diagConsumer} {}
|
|
||||||
|
|
||||||
void parsedArgs(swift::CompilerInvocation& invocation) override {
|
void parsedArgs(swift::CompilerInvocation& invocation) override {
|
||||||
auto& options = invocation.getFrontendOptions();
|
auto& options = invocation.getFrontendOptions();
|
||||||
lockOutputSwiftModuleTraps(config, options);
|
lockOutputSwiftModuleTraps(state, options);
|
||||||
processFrontendOptions(options);
|
processFrontendOptions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,12 +85,13 @@ class Observer : public swift::FrontendObserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void performedSemanticAnalysis(swift::CompilerInstance& compiler) override {
|
void performedSemanticAnalysis(swift::CompilerInstance& compiler) override {
|
||||||
codeql::extractSwiftFiles(config, compiler);
|
codeql::extractSwiftFiles(state, compiler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const codeql::SwiftExtractorConfiguration& config;
|
codeql::SwiftExtractorState state;
|
||||||
codeql::SwiftDiagnosticsConsumer& diagConsumer;
|
codeql::TrapDomain invocationTrap{invocationTrapDomain(state)};
|
||||||
|
codeql::SwiftDiagnosticsConsumer diagConsumer{invocationTrap};
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::string getenv_or(const char* envvar, const std::string& def) {
|
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,
|
// Creates a target file that should store per-invocation info, e.g. compilation args,
|
||||||
// compilations, diagnostics, etc.
|
// 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 timestamp = std::chrono::system_clock::now().time_since_epoch().count();
|
||||||
auto filename = std::to_string(timestamp) + '-' + std::to_string(getpid());
|
auto filename = std::to_string(timestamp) + '-' + std::to_string(getpid());
|
||||||
auto target = std::filesystem::path("invocations") / std::filesystem::path(filename);
|
auto target = std::filesystem::path("invocations") / std::filesystem::path(filename);
|
||||||
auto maybeDomain = codeql::createTargetTrapDomain(configuration, target);
|
auto maybeDomain = codeql::createTargetTrapDomain(state, target);
|
||||||
if (!maybeDomain) {
|
if (!maybeDomain) {
|
||||||
std::cerr << "Cannot create invocation trap file: " << target << "\n";
|
std::cerr << "Cannot create invocation trap file: " << target << "\n";
|
||||||
abort();
|
abort();
|
||||||
@@ -183,9 +184,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
auto openInterception = codeql::setupFileInterception(configuration);
|
auto openInterception = codeql::setupFileInterception(configuration);
|
||||||
|
|
||||||
auto invocationDomain = invocationTrapDomain(configuration);
|
Observer observer(configuration);
|
||||||
codeql::SwiftDiagnosticsConsumer diagConsumer(invocationDomain);
|
|
||||||
Observer observer(configuration, diagConsumer);
|
|
||||||
int frontend_rc = swift::performFrontend(configuration.frontendOptions, "swift-extractor",
|
int frontend_rc = swift::performFrontend(configuration.frontendOptions, "swift-extractor",
|
||||||
(void*)main, &observer);
|
(void*)main, &observer);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user