mirror of
https://github.com/github/codeql.git
synced 2025-12-17 17:23:36 +01:00
112 lines
4.1 KiB
C++
112 lines
4.1 KiB
C++
#include "SwiftExtractor.h"
|
|
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <memory>
|
|
#include <unistd.h>
|
|
|
|
#include <swift/AST/SourceFile.h>
|
|
#include <llvm/ADT/SmallString.h>
|
|
#include <llvm/Support/FileSystem.h>
|
|
#include <llvm/Support/Path.h>
|
|
|
|
#include "swift/extractor/trap/TrapEntries.h"
|
|
|
|
using namespace codeql;
|
|
|
|
static void extractFile(const SwiftExtractorConfiguration& config, swift::SourceFile& file) {
|
|
if (std::error_code ec = llvm::sys::fs::create_directories(config.trapDir)) {
|
|
std::cerr << "Cannot create TRAP directory: " << ec.message() << "\n";
|
|
return;
|
|
}
|
|
|
|
if (std::error_code ec = llvm::sys::fs::create_directories(config.sourceArchiveDir)) {
|
|
std::cerr << "Cannot create source archive directory: " << ec.message() << "\n";
|
|
return;
|
|
}
|
|
|
|
llvm::SmallString<PATH_MAX> srcFilePath(file.getFilename());
|
|
llvm::sys::fs::make_absolute(srcFilePath);
|
|
|
|
llvm::SmallString<PATH_MAX> dstFilePath(config.sourceArchiveDir);
|
|
llvm::sys::path::append(dstFilePath, srcFilePath);
|
|
|
|
llvm::StringRef parent = llvm::sys::path::parent_path(dstFilePath);
|
|
if (std::error_code ec = llvm::sys::fs::create_directories(parent)) {
|
|
std::cerr << "Cannot create source archive destination directory '" << parent.str()
|
|
<< "': " << ec.message() << "\n";
|
|
return;
|
|
}
|
|
|
|
if (std::error_code ec = llvm::sys::fs::copy_file(srcFilePath, dstFilePath)) {
|
|
std::cerr << "Cannot archive source file '" << srcFilePath.str().str() << "' -> '"
|
|
<< dstFilePath.str().str() << "': " << ec.message() << "\n";
|
|
return;
|
|
}
|
|
|
|
// The extractor can be called several times from different processes with
|
|
// the same input file(s)
|
|
// We are using PID to avoid concurrent access
|
|
// TODO: find a more robust approach to avoid collisions?
|
|
std::string tempTrapName = file.getFilename().str() + '.' + std::to_string(getpid()) + ".trap";
|
|
llvm::SmallString<PATH_MAX> tempTrapPath(config.trapDir);
|
|
llvm::sys::path::append(tempTrapPath, tempTrapName);
|
|
|
|
llvm::StringRef trapParent = llvm::sys::path::parent_path(tempTrapPath);
|
|
if (std::error_code ec = llvm::sys::fs::create_directories(trapParent)) {
|
|
std::cerr << "Cannot create trap directory '" << trapParent.str() << "': " << ec.message()
|
|
<< "\n";
|
|
return;
|
|
}
|
|
|
|
std::ofstream trap(tempTrapPath.str().str());
|
|
if (!trap) {
|
|
std::error_code ec;
|
|
ec.assign(errno, std::generic_category());
|
|
std::cerr << "Cannot create temp trap file '" << tempTrapPath.str().str()
|
|
<< "': " << ec.message() << "\n";
|
|
return;
|
|
}
|
|
trap << "// extractor-args: ";
|
|
for (auto opt : config.frontendOptions) {
|
|
trap << std::quoted(opt) << " ";
|
|
}
|
|
trap << "\n\n";
|
|
|
|
TrapLabel<FileTag> label{};
|
|
trap << label << "=*\n";
|
|
trap << FilesTrap{label, srcFilePath.str().str()} << "\n";
|
|
|
|
// TODO: Pick a better name to avoid collisions
|
|
std::string trapName = file.getFilename().str() + ".trap";
|
|
llvm::SmallString<PATH_MAX> trapPath(config.trapDir);
|
|
llvm::sys::path::append(trapPath, trapName);
|
|
|
|
// TODO: The last process wins. Should we do better than that?
|
|
if (std::error_code ec = llvm::sys::fs::rename(tempTrapPath, trapPath)) {
|
|
std::cerr << "Cannot rename temp trap file '" << tempTrapPath.str().str() << "' -> '"
|
|
<< trapPath.str().str() << "': " << ec.message() << "\n";
|
|
}
|
|
}
|
|
|
|
void codeql::extractSwiftFiles(const SwiftExtractorConfiguration& config,
|
|
swift::CompilerInstance& compiler) {
|
|
// Swift frontend can be called in several different modes, we are interested
|
|
// only in the cases when either a primary or a main source file is present
|
|
if (compiler.getPrimarySourceFiles().empty()) {
|
|
swift::ModuleDecl* module = compiler.getMainModule();
|
|
if (!module->getFiles().empty() &&
|
|
module->getFiles().front()->getKind() == swift::FileUnitKind::Source) {
|
|
// We can only call getMainSourceFile if the first file is of a Source kind
|
|
swift::SourceFile& file = module->getMainSourceFile();
|
|
extractFile(config, file);
|
|
}
|
|
} else {
|
|
for (auto s : compiler.getPrimarySourceFiles()) {
|
|
extractFile(config, *s);
|
|
}
|
|
}
|
|
}
|