Skip to content

Swift: use std::filesystem and picoSHA2 #10987

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions misc/bazel/workspace.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ def codeql_workspace(repository_name = "codeql"):
sha256 = "9f2cdee6dcc2039d4c47d25ab5141fe0678ce6ed27ef482cab17fe9fa38a30ce",
)

http_archive(
name = "picosha2",
url = "https://github.com/okdshin/PicoSHA2/archive/27fcf6979298949e8a462e16d09a0351c18fcaf2.zip",
strip_prefix = "PicoSHA2-27fcf6979298949e8a462e16d09a0351c18fcaf2",
build_file = "@%s//swift/third_party/picosha2:BUILD.picosha2.bazel" % repository_name,
sha256 = "d6647ca45a8b7bdaf027ecb68d041b22a899a0218b7206dee755c558a2725abb",
)

maybe(
repo_rule = http_archive,
name = "rules_pkg",
Expand Down
54 changes: 29 additions & 25 deletions swift/extractor/SwiftExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,42 @@

using namespace codeql;
using namespace std::string_literals;
namespace fs = std::filesystem;

static void archiveFile(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;
}
static fs::path toPath(llvm::StringRef s) {
return {static_cast<std::string_view>(s)};
}

if (std::error_code ec = llvm::sys::fs::create_directories(config.sourceArchiveDir)) {
std::cerr << "Cannot create source archive directory: " << ec.message() << "\n";
return;
static void ensureDirectory(const char* label, const fs::path& dir) {
std::error_code ec;
fs::create_directories(dir, ec);
if (ec) {
std::cerr << "Cannot create " << label << " directory: " << ec.message() << "\n";
std::abort();
}
}

llvm::SmallString<PATH_MAX> srcFilePath(file.getFilename());
llvm::sys::fs::make_absolute(srcFilePath);
static void archiveFile(const SwiftExtractorConfiguration& config, swift::SourceFile& file) {
ensureDirectory("TRAP", config.trapDir);
ensureDirectory("source archive", config.sourceArchiveDir);

llvm::SmallString<PATH_MAX> dstFilePath(config.sourceArchiveDir);
llvm::sys::path::append(dstFilePath, srcFilePath);
fs::path srcFilePath = fs::absolute(toPath(file.getFilename()));
auto dstFilePath = config.sourceArchiveDir;
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;
}
ensureDirectory("source archive destination", dstFilePath.parent_path());

std::error_code ec;
fs::copy(srcFilePath, dstFilePath, fs::copy_options::overwrite_existing, ec);

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;
if (ec) {
std::cerr << "Cannot archive source file " << srcFilePath << " -> " << dstFilePath << ": "
<< ec.message() << "\n";
std::abort();
}
}

static std::string getFilename(swift::ModuleDecl& module, swift::SourceFile* primaryFile) {
static fs::path getFilename(swift::ModuleDecl& module, swift::SourceFile* primaryFile) {
if (primaryFile) {
return primaryFile->getFilename().str();
}
Expand All @@ -57,7 +60,8 @@ static std::string getFilename(swift::ModuleDecl& module, swift::SourceFile* pri
// In this case we want to differentiate them
// Moreover, pcm files may come from caches located in different directories, but are
// unambiguously identified by the base file name, so we can discard the absolute directory
std::string filename = "/pcms/"s + llvm::sys::path::filename(module.getModuleFilename()).str();
fs::path filename = "/pcms";
filename /= toPath(module.getModuleFilename()).filename();
filename += "-";
filename += module.getName().str();
return filename;
Expand All @@ -66,7 +70,7 @@ static std::string getFilename(swift::ModuleDecl& module, swift::SourceFile* pri
// The Builtin module has an empty filename, let's fix that
return "/__Builtin__";
}
auto filename = module.getModuleFilename().str();
auto filename = toPath(module.getModuleFilename());
// there is a special case of a module without an actual filename reporting `<imports>`: in this
// case we want to avoid the `<>` characters, in case a dirty DB is imported on Windows
if (filename == "<imports>") {
Expand Down
19 changes: 11 additions & 8 deletions swift/extractor/SwiftExtractorConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@

#include <string>
#include <vector>
#include <filesystem>

#include "swift/extractor/infra/TargetFile.h"
#include "swift/extractor/infra/file/TargetFile.h"

namespace codeql {
struct SwiftExtractorConfiguration {
// The location for storing TRAP files to be imported by CodeQL engine.
std::string trapDir;
std::filesystem::path trapDir;
// The location for storing extracted source files.
std::string sourceArchiveDir;
std::filesystem::path sourceArchiveDir;
// A temporary directory that exists during database creation, but is deleted once the DB is
// finalized.
std::string scratchDir;
std::filesystem::path scratchDir;

// The original arguments passed to the extractor. Used for debugging.
std::vector<std::string> frontendOptions;
Expand All @@ -22,18 +23,20 @@ struct SwiftExtractorConfiguration {

// A temporary directory that contains TRAP files before they are moved into their final
// destination.
std::string getTempTrapDir() const { return scratchDir + "/swift-trap-temp"; }
std::filesystem::path getTempTrapDir() const { return scratchDir / "swift-trap-temp"; }

// VFS (virtual file system) support.
// A temporary directory that contains VFS files used during extraction.
std::string getVFSDir() const { return scratchDir + "/swift-vfs"; }
std::filesystem::path getVFSDir() const { return scratchDir / "swift-vfs"; }

// A temporary directory that contains temp VFS files before they moved into VFSDir.
std::string getTempVFSDir() const { return scratchDir + "/swift-vfs-temp"; }
std::filesystem::path getTempVFSDir() const { return scratchDir / "swift-vfs-temp"; }

// A temporary directory that contains build artifacts generated by the extractor during the
// overall extraction process.
std::string getTempArtifactDir() const { return scratchDir + "/swift-extraction-artifacts"; }
std::filesystem::path getTempArtifactDir() const {
return scratchDir / "swift-extraction-artifacts";
}
};

} // namespace codeql
4 changes: 2 additions & 2 deletions swift/extractor/TargetTrapFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
#include <iomanip>
namespace codeql {
std::optional<TargetFile> createTargetTrapFile(const SwiftExtractorConfiguration& configuration,
std::string_view target) {
std::string trap{target};
const std::filesystem::path& target) {
auto trap = target;
trap += ".trap";
auto ret = TargetFile::create(trap, configuration.trapDir, configuration.getTempTrapDir());
if (ret) {
Expand Down
4 changes: 2 additions & 2 deletions swift/extractor/TargetTrapFile.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#pragma once

#include "swift/extractor/infra/TargetFile.h"
#include "swift/extractor/infra/file/TargetFile.h"
#include "swift/extractor/SwiftExtractorConfiguration.h"

namespace codeql {

std::optional<TargetFile> createTargetTrapFile(const SwiftExtractorConfiguration& configuration,
std::string_view target);
const std::filesystem::path& target);

} // namespace codeql
1 change: 1 addition & 0 deletions swift/extractor/infra/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ swift_cc_library(
hdrs = glob(["*.h"]),
visibility = ["//swift:__subpackages__"],
deps = [
"//swift/extractor/infra/file",
"//swift/extractor/trap",
"//swift/third_party/swift-llvm-support",
],
Expand Down
24 changes: 0 additions & 24 deletions swift/extractor/infra/FilePath.h

This file was deleted.

24 changes: 13 additions & 11 deletions swift/extractor/infra/SwiftDispatcher.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
#pragma once

#include <filesystem>

#include <swift/AST/SourceFile.h>
#include <swift/Basic/SourceManager.h>
#include <llvm/Support/FileSystem.h>
#include <swift/Parse/Token.h>

#include "swift/extractor/trap/TrapLabelStore.h"
#include "swift/extractor/trap/TrapDomain.h"
#include "swift/extractor/infra/SwiftTagTraits.h"
#include "swift/extractor/trap/generated/TrapClasses.h"
#include "swift/extractor/infra/FilePath.h"
#include "swift/extractor/infra/file/PathHash.h"

namespace codeql {

Expand All @@ -29,7 +30,7 @@ class SwiftDispatcher {
const swift::Pattern*,
const swift::TypeRepr*,
const swift::TypeBase*,
FilePath>;
std::filesystem::path>;

template <typename E>
static constexpr bool IsStorable = std::is_constructible_v<Store::Handle, const E&>;
Expand Down Expand Up @@ -306,16 +307,17 @@ class SwiftDispatcher {
return false;
}

static FilePath getFilePath(llvm::StringRef path) {
static std::filesystem::path getFilePath(std::string_view path) {
// TODO: this needs more testing
// TODO: check canonicalization of names on a case insensitive filesystems
// TODO: make symlink resolution conditional on CODEQL_PRESERVE_SYMLINKS=true
llvm::SmallString<PATH_MAX> realPath;
if (std::error_code ec = llvm::sys::fs::real_path(path, realPath)) {
std::cerr << "Cannot get real path: '" << path.str() << "': " << ec.message() << "\n";
std::error_code ec;
auto ret = std::filesystem::canonical(path, ec);
if (ec) {
std::cerr << "Cannot get real path: " << std::quoted(path) << ": " << ec.message() << "\n";
return {};
}
return realPath.str().str();
return ret;
}

// TODO: for const correctness these should consistently be `const` (and maybe const references
Expand All @@ -331,9 +333,9 @@ class SwiftDispatcher {
virtual void visit(swift::TypeRepr* typeRepr, swift::Type type) = 0;
virtual void visit(swift::TypeBase* type) = 0;

void visit(const FilePath& file) {
auto entry = createEntry(file, file.path);
entry.name = file.path;
void visit(const std::filesystem::path& file) {
auto entry = createEntry(file, file.string());
entry.name = file.string();
emit(entry);
}

Expand Down
4 changes: 2 additions & 2 deletions swift/extractor/infra/SwiftTagTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

// This file implements the mapping needed by the API defined in the TrapTagTraits.h, so that
// TrapTagOf/TrapLabelOf provide the tags/labels for specific swift entity types.
#include <filesystem>
#include <swift/AST/ASTVisitor.h>
#include "swift/extractor/trap/TrapTagTraits.h"
#include "swift/extractor/trap/generated/TrapTags.h"
#include "swift/extractor/infra/FilePath.h"

namespace codeql {

Expand Down Expand Up @@ -68,7 +68,7 @@ MAP_TYPE_TO_TAG(swift::TypeBase, TypeTag);
OVERRIDE_TAG(FuncDecl, ConcreteFuncDeclTag);
OVERRIDE_TAG(VarDecl, ConcreteVarDeclTag);

MAP_TYPE_TO_TAG(FilePath, DbFileTag);
MAP_TYPE_TO_TAG(std::filesystem::path, DbFileTag);

#undef MAP_TAG
#undef MAP_SUBTAG
Expand Down
85 changes: 0 additions & 85 deletions swift/extractor/infra/TargetFile.cpp

This file was deleted.

9 changes: 9 additions & 0 deletions swift/extractor/infra/file/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
load("//swift:rules.bzl", "swift_cc_library")

swift_cc_library(
name = "file",
srcs = glob(["*.cpp"]),
hdrs = glob(["*.h"]),
visibility = ["//swift:__subpackages__"],
deps = ["@picosha2"],
)
Loading