Skip to content

Swift: turn extractor into a swift-frontend plugin #12713

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

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion .bazelversion
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.0.0
6.1.1
10 changes: 7 additions & 3 deletions swift/extractor/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ load("//misc/bazel/cmake:cmake.bzl", "generate_cmake")
load("//misc/bazel:pkg_runfiles.bzl", "pkg_runfiles")

swift_cc_binary(
name = "extractor.real",
name = "swiftFrontendObserver",
srcs = glob([
"*.h",
"*.cpp",
]),
linkshared = True,
deps = [
"//swift/extractor/config",
"//swift/extractor/infra",
Expand All @@ -21,14 +22,17 @@ swift_cc_binary(

generate_cmake(
name = "cmake",
targets = [":extractor.real"],
targets = [":swiftFrontendObserver"],
visibility = ["//visibility:public"],
)

sh_binary(
name = "extractor",
srcs = ["extractor.sh"],
data = [":extractor.real"],
data = [
":swiftFrontendObserver",
"//swift/third_party/swift-llvm-support:swift-frontend",
],
)

pkg_runfiles(
Expand Down
16 changes: 13 additions & 3 deletions swift/extractor/extractor.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
#!/bin/bash

EXE_DIR="$(dirname "$0")"

if [[ "$(uname)" == Darwin ]]; then
export DYLD_LIBRARY_PATH=$(dirname "$0")
export DYLD_LIBRARY_PATH="$EXE_DIR"
else
export LD_LIBRARY_PATH=$(dirname "$0")
export LD_LIBRARY_PATH="$EXE_DIR"
fi

TOOL="$CODEQL_EXTRACTOR_SWIFT_RUN_UNDER"

if [[ -n "$CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER" ]]; then
if [[ ! "$*" =~ $CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER ]]; then
TOOL=
fi
fi

exec -a "$0" "$0.real" "$@"
exec -a swift-frontend $TOOL "$EXE_DIR/swift-frontend" "$@"
85 changes: 13 additions & 72 deletions swift/extractor/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
#include <chrono>

#include <swift/Basic/LLVMInitialize.h>
#include <swift/FrontendTool/FrontendTool.h>
#include <swift/DriverTool/DriverTool.h>
#include <swift/DriverTool/FrontendObserver.h>
#include <swift/Basic/InitializeSwiftModules.h>

#include "swift/extractor/SwiftExtractor.h"
Expand Down Expand Up @@ -92,7 +93,8 @@ class Observer : public swift::FrontendObserver {
codeql::extractExtractLazyDeclarations(state, compiler);
}

void markSuccessfullyExtractedFiles() {
void finished(int status) override {
if (status != 0) return;
codeql::SwiftLocationExtractor locExtractor{invocationTrap};
for (const auto& src : state.sourceFiles) {
auto fileLabel = locExtractor.emitFile(src);
Expand All @@ -102,6 +104,8 @@ class Observer : public swift::FrontendObserver {

private:
codeql::SwiftExtractorState state;
std::shared_ptr<codeql::FileInterceptor> openInterception{
codeql::setupFileInterception(state.configuration)};
codeql::TrapDomain invocationTrap{invocationTrapDomain(state)};
codeql::SwiftDiagnosticsConsumer diagConsumer{invocationTrap};
};
Expand All @@ -113,49 +117,6 @@ static std::string getenv_or(const char* envvar, const std::string& def) {
return def;
}

static bool checkRunUnderFilter(int argc, char* const* argv) {
auto runUnderFilter = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER");
if (runUnderFilter == nullptr) {
return true;
}
std::string call = argv[0];
for (auto i = 1; i < argc; ++i) {
call += ' ';
call += argv[i];
}
std::regex filter{runUnderFilter, std::regex_constants::basic | std::regex_constants::nosubs};
return std::regex_search(call, filter);
}

// if `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` env variable is set, and either
// * `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER` is not set, or
// * it is set to a regexp matching any substring of the extractor call
// then the running process is substituted with the command (and possibly
// options) stated in `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER`, followed by `argv`.
// Before calling `exec`, `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` is unset to avoid
// unpleasant loops.
// An example usage is to run the extractor under `gdbserver :1234` when the
// arguments match a given source file.
static void checkWhetherToRunUnderTool(int argc, char* const* argv) {
assert(argc > 0);

auto runUnder = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER");
if (runUnder == nullptr || !checkRunUnderFilter(argc, argv)) {
return;
}
std::vector<char*> args;
// split RUN_UNDER value by spaces to get args vector
for (auto word = std::strtok(runUnder, " "); word != nullptr; word = std::strtok(nullptr, " ")) {
args.push_back(word);
}
// append process args, including extractor executable path
args.insert(args.end(), argv, argv + argc);
args.push_back(nullptr);
// avoid looping on this function
unsetenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER");
execvp(args[0], args.data());
}

// Creates a target file that should store per-invocation info, e.g. compilation args,
// compilations, diagnostics, etc.
codeql::TrapDomain invocationTrapDomain(codeql::SwiftExtractorState& state) {
Expand All @@ -170,39 +131,19 @@ codeql::TrapDomain invocationTrapDomain(codeql::SwiftExtractorState& state) {
return std::move(maybeDomain.value());
}

codeql::SwiftExtractorConfiguration configure(int argc, char** argv) {
codeql::SwiftExtractorConfiguration configure(llvm::ArrayRef<const char*> argv) {
codeql::SwiftExtractorConfiguration configuration{};
configuration.trapDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_TRAP_DIR", ".");
configuration.sourceArchiveDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_SOURCE_ARCHIVE_DIR", ".");
configuration.scratchDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_SCRATCH_DIR", ".");
configuration.frontendOptions.assign(argv + 1, argv + argc);
configuration.frontendOptions.assign(argv.begin() + 1, argv.end());
return configuration;
}

int main(int argc, char** argv) {
checkWhetherToRunUnderTool(argc, argv);

if (argc == 1) {
// TODO: print usage
return 1;
}

// Required by Swift/LLVM
PROGRAM_START(argc, argv);
INITIALIZE_LLVM();
initializeSwiftModules();

const auto configuration = configure(argc, argv);

auto openInterception = codeql::setupFileInterception(configuration);

Observer observer(configuration);
int frontend_rc = swift::performFrontend(configuration.frontendOptions, "swift-extractor",
(void*)main, &observer);

if (frontend_rc == 0) {
observer.markSuccessfullyExtractedFiles();
}
namespace swift {

return frontend_rc;
FrontendObserver* getFrontendObserver(llvm::ArrayRef<const char*> argv) {
static Observer observer{configure(argv)};
return &observer;
}
} // namespace swift
4 changes: 2 additions & 2 deletions swift/ql/test/extractor-tests/run_under/Strings.expected
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
| run_under: $CODEQL_EXTRACTOR_SWIFT_ROOT/tools/$CODEQL_PLATFORM/extractor -sdk $CODEQL_EXTRACTOR_SWIFT_ROOT/qltest/$CODEQL_PLATFORM/sdk -c -primary-file filtered_in.swift |
| run_under: $CODEQL_EXTRACTOR_SWIFT_ROOT/tools/$CODEQL_PLATFORM/extractor -sdk $CODEQL_EXTRACTOR_SWIFT_ROOT/qltest/$CODEQL_PLATFORM/sdk -c -primary-file unfiltered.swift |
| run_under: $CODEQL_EXTRACTOR_SWIFT_ROOT/tools/$CODEQL_PLATFORM/swift-frontend -sdk $CODEQL_EXTRACTOR_SWIFT_ROOT/qltest/$CODEQL_PLATFORM/sdk -c -primary-file filtered_in.swift |
| run_under: $CODEQL_EXTRACTOR_SWIFT_ROOT/tools/$CODEQL_PLATFORM/swift-frontend -sdk $CODEQL_EXTRACTOR_SWIFT_ROOT/qltest/$CODEQL_PLATFORM/sdk -c -primary-file unfiltered.swift |
8 changes: 4 additions & 4 deletions swift/third_party/load.bzl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

_swift_prebuilt_version = "swift-5.7.3-RELEASE.142"
_swift_prebuilt_version = "swift-5.7.3-RELEASE.150"
_swift_sha_map = {
"Linux-X64": "398d8de54c8775c939dff95ed5bb0e04a9308a1982b4c1900cd4a5d01223f63b",
"macOS-ARM64": "397dd67ea99b9c9455794c6eb0f1664b6179fe542c7c1d3010314a3e8a905ae4",
"macOS-X64": "4b9d8e4e89f16a7c1e7edc7893aa189b37d5b4412be724a86ef59c49d11a6f75",
"Linux-X64": "8465b5ad6b34c723786ae56478ece1a3a778c812c4d0a0521236a12c6544f57d",
"macOS-ARM64": "38b84b24366841fc2b7c5fe081d87310d8e62051884147e155bc74a929a770b7",
"macOS-X64": "1be86d88e8a9be530a8c48ba73cd000daaae9d0435ae1db9ff3a368444639b99",
}

_swift_arch_map = {
Expand Down
2 changes: 1 addition & 1 deletion swift/third_party/swift-llvm-support/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ _arch_override = {
for arch in ("linux", "darwin_x86_64", "darwin_arm64")
}),
)
for name in ("swift-llvm-support", "swift-test-sdk")
for name in ("swift-llvm-support", "swift-test-sdk", "swift-frontend")
]
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,16 @@ load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")

cc_library(
name = "swift-llvm-support",
srcs = [
"libCodeQLSwiftFrontendTool.a",
] + select({
"@platforms//os:linux": [
"libCodeQLSwiftFrontendTool.so",
"libswiftCore.so",
],
"@platforms//os:macos": [
"libCodeQLSwiftFrontendTool.dylib",
"libswiftCore.dylib",
"libswiftCompatibility50.a",
"libswiftCompatibility51.a",
"libswiftCompatibilityConcurrency.a",
"libswiftCompatibilityDynamicReplacements.a",
],
}),
hdrs = glob(["include/**/*", "stdlib/**/*" ]),
srcs = glob([
"lib*.a",
"lib*.so",
"lib*.dylib",
]),
hdrs = glob([
"include/**/*",
"stdlib/**/*",
]),
includes = ["include"],
linkopts = [
"-lm",
"-lz",
Expand All @@ -34,7 +27,6 @@ cc_library(
],
"//conditions:default": [],
}),
includes = [ "include" ],
visibility = ["//visibility:public"],
)

Expand All @@ -46,3 +38,5 @@ pkg_files(
strip_prefix = strip_prefix.from_pkg(),
visibility = ["//visibility:public"],
)

exports_files(["swift-frontend"])