Merge pull request #12500 from github/redsun82/swift-dispatcher-rework

Swift: rework fetching and dispatching
This commit is contained in:
Paolo Tranquilli
2023-04-26 09:58:19 +02:00
committed by GitHub
23 changed files with 585 additions and 483 deletions

View File

@@ -12,7 +12,6 @@ swift_cc_binary(
"//swift/extractor/config",
"//swift/extractor/infra",
"//swift/extractor/invocation",
"//swift/extractor/mangler",
"//swift/extractor/remapping",
"//swift/extractor/translators",
"//swift/third_party/swift-llvm-support",

View File

@@ -44,6 +44,26 @@ static void archiveFile(const SwiftExtractorConfiguration& config, swift::Source
}
}
// TODO: This should be factored out/replaced with simplified version of custom mangling
static std::string mangledDeclName(const swift::ValueDecl& decl) {
std::string_view moduleName = decl.getModuleContext()->getRealName().str();
// ASTMangler::mangleAnyDecl crashes when called on `ModuleDecl`
if (decl.getKind() == swift::DeclKind::Module) {
return std::string{moduleName};
}
swift::Mangle::ASTMangler mangler;
if (decl.getKind() == swift::DeclKind::TypeAlias) {
// In cases like this (when coming from PCM)
// typealias CFXMLTree = CFTree
// typealias CFXMLTreeRef = CFXMLTree
// mangleAnyDecl mangles both CFXMLTree and CFXMLTreeRef into 'So12CFXMLTreeRefa'
// which is not correct and causes inconsistencies. mangleEntity makes these two distinct
// prefix adds a couple of special symbols, we don't necessary need them
return mangler.mangleEntity(&decl);
}
return mangler.mangleAnyDecl(&decl, /* prefix = */ false);
}
static fs::path getFilename(swift::ModuleDecl& module,
swift::SourceFile* primaryFile,
const swift::Decl* lazyDeclaration) {
@@ -52,15 +72,15 @@ static fs::path getFilename(swift::ModuleDecl& module,
}
if (lazyDeclaration) {
// this code will be thrown away in the near future
SwiftMangler mangler;
auto mangled = mangler.mangledName(*lazyDeclaration);
auto decl = llvm::dyn_cast<swift::ValueDecl>(lazyDeclaration);
assert(decl);
auto mangled = mangledDeclName(*decl);
// mangled name can be too long to use as a file name, so we can't use it directly
mangled = picosha2::hash256_hex_string(mangled);
std::string ret;
ret += module.getRealName().str();
ret += '_';
// lazyDeclaration must be a ValueDecl, as already asserted in SwiftMangler::mangledName
ret += llvm::cast<swift::ValueDecl>(lazyDeclaration)->getBaseName().userFacingName();
ret += decl->getBaseName().userFacingName();
ret += '_';
// half a SHA2 is enough
ret += std::string_view(mangled).substr(0, mangled.size() / 2);

View File

@@ -6,12 +6,12 @@
#include <swift/Basic/SourceManager.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/SwiftLocationExtractor.h"
#include "swift/extractor/infra/SwiftBodyEmissionStrategy.h"
#include "swift/extractor/infra/SwiftMangledName.h"
#include "swift/extractor/config/SwiftExtractorState.h"
#include "swift/extractor/infra/log/SwiftLogging.h"
@@ -24,24 +24,31 @@ namespace codeql {
// node (AST nodes that are not types: declarations, statements, expressions, etc.).
class SwiftDispatcher {
// types to be supported by assignNewLabel/fetchLabel need to be listed here
using Store = TrapLabelStore<const swift::Decl*,
const swift::Stmt*,
const swift::StmtCondition*,
const swift::StmtConditionElement*,
const swift::CaseLabelItem*,
const swift::Expr*,
const swift::Pattern*,
const swift::TypeRepr*,
const swift::TypeBase*,
const swift::CapturedValue*,
const swift::PoundAvailableInfo*,
const swift::AvailabilitySpec*>;
using Handle = std::variant<const swift::Decl*,
const swift::Stmt*,
const swift::StmtCondition*,
const swift::StmtConditionElement*,
const swift::CaseLabelItem*,
const swift::Expr*,
const swift::Pattern*,
const swift::TypeRepr*,
const swift::TypeBase*,
const swift::CapturedValue*,
const swift::PoundAvailableInfo*,
const swift::AvailabilitySpec*>;
template <typename E>
static constexpr bool IsStorable = std::is_constructible_v<Store::Handle, const E&>;
static constexpr bool IsFetchable = std::is_constructible_v<Handle, const E&>;
template <typename E>
static constexpr bool IsLocatable = std::is_base_of_v<LocatableTag, TrapTagOf<E>>;
static constexpr bool IsLocatable =
std::is_base_of_v<LocatableTag, TrapTagOf<E>> && !std::is_base_of_v<TypeTag, TrapTagOf<E>>;
template <typename E>
static constexpr bool IsDeclPointer = std::is_convertible_v<E, const swift::Decl*>;
template <typename E>
static constexpr bool IsTypePointer = std::is_convertible_v<E, const swift::TypeBase*>;
public:
// all references and pointers passed as parameters to this constructor are supposed to outlive
@@ -112,7 +119,7 @@ class SwiftDispatcher {
TrapLabel<UnspecifiedElementTag> emitUnspecified(std::optional<TrapLabel<ElementTag>>&& parent,
const char* property,
int index) {
UnspecifiedElement entry{trap.createLabel<UnspecifiedElementTag>()};
UnspecifiedElement entry{trap.createTypedLabel<UnspecifiedElementTag>()};
entry.error = "element was unspecified by the extractor";
entry.parent = std::move(parent);
entry.property = property;
@@ -135,35 +142,22 @@ class SwiftDispatcher {
// This method gives a TRAP label for already emitted AST node.
// If the AST node was not emitted yet, then the emission is dispatched to a corresponding
// visitor (see `visit(T *)` methods below).
template <typename E, typename... Args, std::enable_if_t<IsStorable<E>>* = nullptr>
TrapLabelOf<E> fetchLabel(const E& e, Args&&... args) {
template <typename E, std::enable_if_t<IsFetchable<E>>* = nullptr>
TrapLabelOf<E> fetchLabel(const E& e, swift::Type type = {}) {
if constexpr (std::is_constructible_v<bool, const E&>) {
if (!e) {
// this will be treated on emission
return undefined_label;
}
}
// this is required so we avoid any recursive loop: a `fetchLabel` during the visit of `e` might
// end up calling `fetchLabel` on `e` itself, so we want the visit of `e` to call `fetchLabel`
// only after having called `assignNewLabel` on `e`.
assert(std::holds_alternative<std::monostate>(waitingForNewLabel) &&
"fetchLabel called before assignNewLabel");
if (auto l = store.get(e)) {
return *l;
auto& stored = store[e];
if (!stored.valid()) {
auto inserted = fetching.insert(e);
assert(inserted.second && "detected infinite fetchLabel recursion");
stored = createLabel(e, type);
fetching.erase(e);
}
waitingForNewLabel = e;
// TODO: add tracing logs for visited stuff, maybe within the translators?
visit(e, std::forward<Args>(args)...);
Log::flush();
// TODO when everything is moved to structured C++ classes, this should be moved to createEntry
if (auto l = store.get(e)) {
if constexpr (IsLocatable<E>) {
locationExtractor.attachLocation(sourceManager, e, *l);
}
return *l;
}
assert(!"assignNewLabel not called during visit");
return {};
return TrapLabelOf<E>::unsafeCreateFromUntyped(stored);
}
// convenience `fetchLabel` overload for `swift::Type` (which is just a wrapper for
@@ -174,39 +168,28 @@ class SwiftDispatcher {
return fetchLabelFromUnion<AstNodeTag>(node);
}
template <typename E, std::enable_if_t<IsStorable<E*>>* = nullptr>
template <typename E, std::enable_if_t<IsFetchable<E*>>* = nullptr>
TrapLabelOf<E> fetchLabel(const E& e) {
return fetchLabel(&e);
}
// Due to the lazy emission approach, we must assign a label to a corresponding AST node before
// it actually gets emitted to handle recursive cases such as recursive calls, or recursive type
// declarations
template <typename E, typename... Args, std::enable_if_t<IsStorable<E>>* = nullptr>
TrapLabel<ConcreteTrapTagOf<E>> assignNewLabel(const E& e, Args&&... args) {
assert(waitingForNewLabel == Store::Handle{e} && "assignNewLabel called on wrong entity");
auto label = trap.createLabel<ConcreteTrapTagOf<E>>(std::forward<Args>(args)...);
store.insert(e, label);
waitingForNewLabel = std::monostate{};
return label;
}
template <typename E, typename... Args, std::enable_if_t<IsStorable<E*>>* = nullptr>
TrapLabel<ConcreteTrapTagOf<E>> assignNewLabel(const E& e, Args&&... args) {
return assignNewLabel(&e, std::forward<Args>(args)...);
}
// convenience methods for structured C++ creation
template <typename E, typename... Args>
auto createEntry(const E& e, Args&&... args) {
return TrapClassOf<E>{assignNewLabel(e, std::forward<Args>(args)...)};
template <typename E>
auto createEntry(const E& e) {
auto found = store.find(&e);
assert(found != store.end() && "createEntry called on non-fetched label");
auto label = TrapLabel<ConcreteTrapTagOf<E>>::unsafeCreateFromUntyped(found->second);
if constexpr (IsLocatable<E>) {
locationExtractor.attachLocation(sourceManager, e, label);
}
return TrapClassOf<E>{label};
}
// used to create a new entry for entities that should not be cached
// an example is swift::Argument, that are created on the fly and thus have no stable pointer
template <typename E, typename... Args>
auto createUncachedEntry(const E& e, Args&&... args) {
auto label = trap.createLabel<TrapTagOf<E>>(std::forward<Args>(args)...);
template <typename E>
auto createUncachedEntry(const E& e) {
auto label = trap.createTypedLabel<TrapTagOf<E>>();
locationExtractor.attachLocation(sourceManager, &e, label);
return TrapClassOf<E>{label};
}
@@ -243,31 +226,65 @@ class SwiftDispatcher {
trap.debug(args...);
}
bool shouldEmitDeclBody(const swift::Decl& decl) {
encounteredModules.insert(decl.getModuleContext());
return bodyEmissionStrategy.shouldEmitDeclBody(decl);
}
void emitComment(swift::Token& comment) {
CommentsTrap entry{trap.createLabel<CommentTag>(), comment.getRawText().str()};
CommentsTrap entry{trap.createTypedLabel<CommentTag>(), comment.getRawText().str()};
trap.emit(entry);
locationExtractor.attachLocation(sourceManager, comment, entry.id);
}
void extractedDeclaration(const swift::Decl& decl) {
if (isLazyDeclaration(decl)) {
state.emittedDeclarations.insert(&decl);
}
}
void skippedDeclaration(const swift::Decl& decl) {
if (isLazyDeclaration(decl)) {
state.pendingDeclarations.insert(&decl);
protected:
void visitPending() {
while (!toBeVisited.empty()) {
auto [next, type] = toBeVisited.back();
toBeVisited.pop_back();
// TODO: add tracing logs for visited stuff, maybe within the translators?
std::visit([this, type = type](const auto* e) { visit(e, type); }, next);
}
}
private:
bool isLazyDeclaration(const swift::Decl& decl) {
swift::ModuleDecl* module = decl.getModuleContext();
template <typename E>
UntypedTrapLabel createLabel(const E& e, swift::Type type) {
if constexpr (IsDeclPointer<E> || IsTypePointer<E>) {
if (auto mangledName = name(e)) {
if (shouldVisit(e)) {
toBeVisited.emplace_back(e, type);
}
return trap.createLabel(mangledName);
}
}
// we always need to visit unnamed things
toBeVisited.emplace_back(e, type);
return trap.createLabel();
}
template <typename E>
bool shouldVisit(const E& e) {
if constexpr (IsDeclPointer<E>) {
encounteredModules.insert(e->getModuleContext());
if (bodyEmissionStrategy.shouldEmitDeclBody(*e)) {
extractedDeclaration(e);
return true;
}
skippedDeclaration(e);
return false;
}
return true;
}
void extractedDeclaration(const swift::Decl* decl) {
if (isLazyDeclaration(decl)) {
state.emittedDeclarations.insert(decl);
}
}
void skippedDeclaration(const swift::Decl* decl) {
if (isLazyDeclaration(decl)) {
state.pendingDeclarations.insert(decl);
}
}
static bool isLazyDeclaration(const swift::Decl* decl) {
swift::ModuleDecl* module = decl->getModuleContext();
return module->isBuiltinModule() || module->getName().str() == "__ObjC" ||
module->isNonSwiftModule();
}
@@ -311,6 +328,8 @@ class SwiftDispatcher {
return false;
}
virtual SwiftMangledName name(const swift::Decl* decl) = 0;
virtual SwiftMangledName name(const swift::TypeBase* type) = 0;
virtual void visit(const swift::Decl* decl) = 0;
virtual void visit(const swift::Stmt* stmt) = 0;
virtual void visit(const swift::StmtCondition* cond) = 0;
@@ -324,13 +343,19 @@ class SwiftDispatcher {
virtual void visit(const swift::TypeBase* type) = 0;
virtual void visit(const swift::CapturedValue* capture) = 0;
template <typename T, std::enable_if<!std::is_base_of_v<swift::TypeRepr, T>>* = nullptr>
void visit(const T* e, swift::Type) {
visit(e);
}
const swift::SourceManager& sourceManager;
SwiftExtractorState& state;
TrapDomain& trap;
Store store;
std::unordered_map<Handle, UntypedTrapLabel> store;
std::unordered_set<Handle> fetching;
std::vector<std::pair<Handle, swift::Type>> toBeVisited;
SwiftLocationExtractor& locationExtractor;
SwiftBodyEmissionStrategy& bodyEmissionStrategy;
Store::Handle waitingForNewLabel{std::monostate{}};
std::unordered_set<swift::ModuleDecl*> encounteredModules;
Logger logger{"dispatcher"};
};

View File

@@ -8,13 +8,14 @@
#include "swift/extractor/trap/generated/TrapClasses.h"
#include "swift/extractor/infra/SwiftLocationExtractor.h"
#include "swift/extractor/infra/file/Path.h"
#include "swift/extractor/infra/SwiftMangledName.h"
using namespace codeql;
void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceManager,
swift::SourceLoc start,
swift::SourceLoc end,
TrapLabel<LocatableTag> locatableLabel) {
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
swift::SourceLoc start,
swift::SourceLoc end,
TrapLabel<LocatableTag> locatableLabel) {
if (!start.isValid() || !end.isValid()) {
// invalid locations seem to come from entities synthesized by the compiler
return;
@@ -24,9 +25,9 @@ void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceMa
entry.file = fetchFileLabel(file);
std::tie(entry.start_line, entry.start_column) = sourceManager.getLineAndColumnInBuffer(start);
std::tie(entry.end_line, entry.end_column) = sourceManager.getLineAndColumnInBuffer(end);
entry.id = trap.createLabel<DbLocationTag>('{', entry.file, "}:", entry.start_line, ':',
entry.start_column, ':', entry.end_line, ':',
entry.end_column);
SwiftMangledName locName{{"loc", entry.file, ":", entry.start_line, ":", entry.start_column, ":",
entry.end_line, ":", entry.end_column}};
entry.id = trap.createTypedLabel<DbLocationTag>(locName);
trap.emit(entry);
trap.emit(LocatableLocationsTrap{locatableLabel, entry.id});
}
@@ -42,43 +43,54 @@ TrapLabel<FileTag> SwiftLocationExtractor::emitFile(const std::filesystem::path&
return fetchFileLabel(resolvePath(file));
}
void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceManager,
const swift::CapturedValue* capture,
TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, capture->getLoc(), locatableLabel);
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::SourceRange& range,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, range.Start, range.End, locatableLabel);
}
void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceManager,
const swift::IfConfigClause* clause,
TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, clause->Loc, clause->Loc, locatableLabel);
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::CapturedValue* capture,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, capture->getLoc(), locatableLabel);
}
void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceManager,
swift::AvailabilitySpec* spec,
TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, spec->getSourceRange().Start, spec->getSourceRange().End,
locatableLabel);
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::IfConfigClause* clause,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, clause->Loc, locatableLabel);
}
void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceManager,
swift::Token& token,
TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, token.getRange().getStart(), token.getRange().getEnd(),
locatableLabel);
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::AvailabilitySpec* spec,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, spec->getSourceRange(), locatableLabel);
}
void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceManager,
const swift::KeyPathExpr::Component* component,
TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, component->getSourceRange().Start, component->getSourceRange().End,
locatableLabel);
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::KeyPathExpr::Component* component,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, component->getSourceRange().Start,
component->getSourceRange().End, locatableLabel);
}
void SwiftLocationExtractor::attachLocation(const swift::SourceManager& sourceManager,
swift::SourceLoc loc,
TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, loc, loc, locatableLabel);
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::Token* token,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, token->getRange().getStart(), token->getRange().getEnd(),
locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
swift::SourceLoc loc,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, loc, loc, locatableLabel);
}
void SwiftLocationExtractor::attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::DiagnosticInfo* diagInfo,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, diagInfo->Loc, locatableLabel);
}
TrapLabel<FileTag> SwiftLocationExtractor::fetchFileLabel(const std::filesystem::path& file) {
@@ -87,7 +99,7 @@ TrapLabel<FileTag> SwiftLocationExtractor::fetchFileLabel(const std::filesystem:
}
DbFile entry({});
entry.id = trap.createLabel<DbFileTag>(file.string());
entry.id = trap.createTypedLabel<DbFileTag>({{"file_", file.string()}});
entry.name = file.string();
trap.emit(entry);
store[file] = entry.id;

View File

@@ -16,6 +16,9 @@ namespace codeql {
class TrapDomain;
class SwiftLocationExtractor {
template <typename Locatable, typename = void>
struct HasSpecializedImplementation : std::false_type {};
public:
explicit SwiftLocationExtractor(TrapDomain& trap) : trap(trap) {}
@@ -24,60 +27,79 @@ class SwiftLocationExtractor {
template <typename Locatable>
void attachLocation(const swift::SourceManager& sourceManager,
Locatable locatable,
const Locatable& locatable,
TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, &locatable, locatableLabel);
}
// Emits a Location TRAP entry and attaches it to a `Locatable` trap label
template <typename Locatable>
template <typename Locatable,
std::enable_if_t<!HasSpecializedImplementation<Locatable>::value>* = nullptr>
void attachLocation(const swift::SourceManager& sourceManager,
Locatable* locatable,
const Locatable* locatable,
TrapLabel<LocatableTag> locatableLabel) {
attachLocation(sourceManager, locatable->getStartLoc(), locatable->getEndLoc(), locatableLabel);
attachLocationImpl(sourceManager, locatable->getStartLoc(), locatable->getEndLoc(),
locatableLabel);
}
template <typename Locatable,
std::enable_if_t<HasSpecializedImplementation<Locatable>::value>* = nullptr>
void attachLocation(const swift::SourceManager& sourceManager,
const Locatable* locatable,
TrapLabel<LocatableTag> locatableLabel) {
attachLocationImpl(sourceManager, locatable, locatableLabel);
}
private:
// Emits a Location TRAP entry for a list of swift entities and attaches it to a `Locatable` trap
// label
template <typename Locatable>
void attachLocation(const swift::SourceManager& sourceManager,
llvm::MutableArrayRef<Locatable>* locatables,
TrapLabel<LocatableTag> locatableLabel) {
void attachLocationImpl(const swift::SourceManager& sourceManager,
const llvm::MutableArrayRef<Locatable>* locatables,
TrapLabel<LocatableTag> locatableLabel) {
if (locatables->empty()) {
return;
}
attachLocation(sourceManager, locatables->front().getStartLoc(), locatables->back().getEndLoc(),
locatableLabel);
attachLocationImpl(sourceManager, locatables->front().getStartLoc(),
locatables->back().getEndLoc(), locatableLabel);
}
void attachLocation(const swift::SourceManager& sourceManager,
swift::SourceLoc start,
swift::SourceLoc end,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
swift::SourceLoc start,
swift::SourceLoc end,
TrapLabel<LocatableTag> locatableLabel);
void attachLocation(const swift::SourceManager& sourceManager,
swift::SourceLoc loc,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
swift::SourceLoc loc,
TrapLabel<LocatableTag> locatableLabel);
void attachLocation(const swift::SourceManager& sourceManager,
const swift::CapturedValue* capture,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::SourceRange& range,
TrapLabel<LocatableTag> locatableLabel);
void attachLocation(const swift::SourceManager& sourceManager,
const swift::IfConfigClause* clause,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::CapturedValue* capture,
TrapLabel<LocatableTag> locatableLabel);
void attachLocation(const swift::SourceManager& sourceManager,
swift::AvailabilitySpec* spec,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::IfConfigClause* clause,
TrapLabel<LocatableTag> locatableLabel);
void attachLocation(const swift::SourceManager& sourceManager,
swift::Token& token,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::AvailabilitySpec* spec,
TrapLabel<LocatableTag> locatableLabel);
void attachLocation(const swift::SourceManager& sourceManager,
const swift::KeyPathExpr::Component* component,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::Token* token,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::DiagnosticInfo* token,
TrapLabel<LocatableTag> locatableLabel);
void attachLocationImpl(const swift::SourceManager& sourceManager,
const swift::KeyPathExpr::Component* component,
TrapLabel<LocatableTag> locatableLabel);
private:
TrapLabel<FileTag> fetchFileLabel(const std::filesystem::path& file);
@@ -85,4 +107,12 @@ class SwiftLocationExtractor {
std::unordered_map<std::filesystem::path, TrapLabel<FileTag>> store;
};
template <typename Locatable>
struct SwiftLocationExtractor::HasSpecializedImplementation<
Locatable,
decltype(std::declval<SwiftLocationExtractor>().attachLocationImpl(
std::declval<const swift::SourceManager&>(),
std::declval<const Locatable*>(),
std::declval<TrapLabel<LocatableTag>>()))> : std::true_type {};
} // namespace codeql

View File

@@ -0,0 +1,30 @@
#include "swift/extractor/infra/SwiftMangledName.h"
namespace codeql {
namespace {
void appendPart(std::string& out, const std::string& prefix) {
out += prefix;
}
void appendPart(std::string& out, UntypedTrapLabel label) {
out += '{';
out += label.str();
out += '}';
}
void appendPart(std::string& out, unsigned index) {
out += std::to_string(index);
}
} // namespace
std::string SwiftMangledName::str() const {
std::string out;
for (const auto& part : parts) {
std::visit([&](const auto& contents) { appendPart(out, contents); }, part);
}
return out;
}
} // namespace codeql

View File

@@ -0,0 +1,45 @@
#pragma once
#include <iostream>
#include <vector>
#include <variant>
#include <string>
#include "swift/extractor/trap/TrapLabel.h"
namespace codeql {
struct SwiftMangledName {
using Part = std::variant<UntypedTrapLabel, std::string, unsigned>;
std::vector<Part> parts;
explicit operator bool() const { return !parts.empty(); }
std::string str() const;
// streaming labels or ints into a SwiftMangledName just appends them
template <typename Tag>
SwiftMangledName& operator<<(TrapLabel<Tag> label) {
parts.emplace_back(label);
return *this;
}
SwiftMangledName& operator<<(unsigned i) {
parts.emplace_back(i);
return *this;
}
// streaming string-like stuff will add a new part it only if strictly required, otherwise it will
// append to the last part if it is a string
template <typename T>
SwiftMangledName& operator<<(T&& arg) {
if (parts.empty() || !std::holds_alternative<std::string>(parts.back())) {
parts.emplace_back("");
}
std::get<std::string>(parts.back()) += std::forward<T>(arg);
return *this;
}
};
} // namespace codeql

View File

@@ -8,6 +8,7 @@ swift_cc_library(
deps = [
"//swift/extractor/config",
"//swift/extractor/infra",
"//swift/extractor/mangler",
"//swift/extractor/remapping",
],
)

View File

@@ -15,11 +15,11 @@ void SwiftDiagnosticsConsumer::handleDiagnostic(swift::SourceManager& sourceMana
const swift::DiagnosticInfo& diagInfo) {
auto message = getDiagMessage(sourceManager, diagInfo);
DiagnosticsTrap diag{};
diag.id = trap.createLabel<DiagnosticsTag>();
diag.id = trap.createTypedLabel<DiagnosticsTag>();
diag.kind = translateDiagnosticsKind(diagInfo.Kind);
diag.text = message;
trap.emit(diag);
locationExtractor.attachLocation(sourceManager, diagInfo.Loc, diagInfo.Loc, diag.id);
locationExtractor.attachLocation(sourceManager, diagInfo, diag.id);
}
std::string SwiftDiagnosticsConsumer::getDiagMessage(swift::SourceManager& sourceManager,

View File

@@ -4,7 +4,7 @@
#include "swift/extractor/trap/generated/TrapTags.h"
#include "swift/extractor/infra/file/TargetFile.h"
#include "swift/extractor/infra/file/Path.h"
#include "swift/extractor/trap/LinkDomain.h"
#include "swift/extractor/mangler/SwiftMangler.h"
namespace fs = std::filesystem;
using namespace std::string_literals;
@@ -65,7 +65,8 @@ std::vector<ModuleInfo> emitModuleImplementations(SwiftExtractorState& state,
if (auto hash = getModuleHash(modulePath)) {
auto target = getModuleTarget(moduleName, *hash);
if (auto moduleTrap = createTargetTrapDomain(state, target, TrapType::linkage)) {
moduleTrap->createLabelWithImplementationId<ModuleDeclTag>(*hash, moduleName);
moduleTrap->createTypedLabelWithImplementationId<ModuleDeclTag>(
SwiftMangler::mangleModuleName(moduleName), *hash);
ret.push_back({target, getModuleId(moduleName, *hash)});
}
}

View File

@@ -6,6 +6,7 @@ swift_cc_library(
hdrs = glob(["*.h"]),
visibility = ["//swift:__subpackages__"],
deps = [
"//swift/extractor/infra",
"//swift/extractor/trap",
"//swift/third_party/swift-llvm-support",
],

View File

@@ -1,21 +1,62 @@
#include "swift/extractor/mangler/SwiftMangler.h"
#include "swift/extractor/infra/SwiftDispatcher.h"
#include "swift/extractor/trap/generated/decl/TrapClasses.h"
#include <swift/AST/Module.h>
#include <sstream>
using namespace codeql;
std::string SwiftMangler::mangledName(const swift::Decl& decl) {
assert(llvm::isa<swift::ValueDecl>(decl));
auto& valueDecl = llvm::cast<swift::ValueDecl>(decl);
std::string_view moduleName = decl.getModuleContext()->getRealName().str();
// ASTMangler::mangleAnyDecl crashes when called on `ModuleDecl`
if (decl.getKind() == swift::DeclKind::Module) {
return std::string{moduleName};
namespace {
SwiftMangledName initMangled(const swift::TypeBase* type) {
switch (type->getKind()) {
#define TYPE(ID, PARENT) \
case swift::TypeKind::ID: \
return {{#ID "Type_"}};
#include <swift/AST/TypeNodes.def>
default:
return {};
}
std::ostringstream ret;
}
SwiftMangledName initMangled(const swift::Decl* decl) {
SwiftMangledName ret;
ret << swift::Decl::getKindName(decl->getKind()) << "Decl_";
return ret;
}
} // namespace
SwiftMangledName SwiftMangler::mangleModuleName(std::string_view name) {
SwiftMangledName ret = {{"ModuleDecl_"}};
ret << name;
return ret;
}
SwiftMangledName SwiftMangler::mangleDecl(const swift::Decl& decl) {
if (!llvm::isa<swift::ValueDecl>(decl)) {
return {};
}
// We do not deduplicate local variables, but for the moment also non-local vars from non-swift
// (PCM, clang modules) modules as the mangler crashes sometimes
if (decl.getKind() == swift::DeclKind::Var &&
(decl.getDeclContext()->isLocalContext() || decl.getModuleContext()->isNonSwiftModule())) {
return {};
}
// we do not deduplicate GenericTypeParamDecl, as their mangling is ambiguous in the presence of
// extensions
if (decl.getKind() == swift::DeclKind::GenericTypeParam) {
return {};
}
if (decl.getKind() == swift::DeclKind::Module) {
return mangleModuleName(llvm::cast<swift::ModuleDecl>(decl).getRealName().str());
}
auto ret = initMangled(&decl);
const auto& valueDecl = llvm::cast<swift::ValueDecl>(decl);
// stamp all declarations with an id-ref of the containing module
ret << '{' << ModuleDeclTag::prefix << '_' << moduleName << '}';
auto moduleLabel = dispatcher.fetchLabel(decl.getModuleContext());
ret << moduleLabel;
if (decl.getKind() == swift::DeclKind::TypeAlias) {
// In cases like this (when coming from PCM)
// typealias CFXMLTree = CFTree
@@ -28,22 +69,21 @@ std::string SwiftMangler::mangledName(const swift::Decl& decl) {
// prefix adds a couple of special symbols, we don't necessary need them
ret << mangler.mangleAnyDecl(&valueDecl, /* prefix = */ false);
}
return ret.str();
return ret;
}
std::optional<std::string> SwiftMangler::mangleType(const swift::ModuleType& type) {
auto key = type.getModule()->getRealName().str().str();
if (type.getModule()->isNonSwiftModule()) {
key += "|clang";
SwiftMangledName SwiftMangler::visitModuleType(const swift::ModuleType* type) {
auto ret = initMangled(type);
ret << type->getModule()->getRealName().str();
if (type->getModule()->isNonSwiftModule()) {
ret << "|clang";
}
return key;
return ret;
}
#define TYPE(TYPE_ID, PARENT_TYPE)
#define BUILTIN_TYPE(TYPE_ID, PARENT_TYPE) \
std::optional<std::string> SwiftMangler::mangleType(const swift::TYPE_ID##Type& type) { \
llvm::SmallString<32> buffer; \
type.getTypeName(buffer); \
return buffer.str().str(); \
}
#include <swift/AST/TypeNodes.def>
SwiftMangledName SwiftMangler::visitBuiltinType(const swift::BuiltinType* type) {
auto ret = initMangled(type);
llvm::SmallString<32> buffer;
ret << type->getTypeName(buffer, /* prependBuiltinNamespace= */ false);
return ret;
}

View File

@@ -2,28 +2,48 @@
#include <swift/AST/ASTMangler.h>
#include <swift/AST/Types.h>
#include <swift/AST/ASTVisitor.h>
#include <swift/AST/TypeVisitor.h>
#include <variant>
#include "swift/extractor/trap/TrapLabel.h"
#include "swift/extractor/infra/SwiftMangledName.h"
#include <optional>
namespace codeql {
class SwiftMangler {
public:
std::string mangledName(const swift::Decl& decl);
template <typename T>
std::optional<std::string> mangleType(const T& type) {
return std::nullopt;
class SwiftDispatcher;
class SwiftMangler : private swift::TypeVisitor<SwiftMangler, SwiftMangledName> {
public:
explicit SwiftMangler(SwiftDispatcher& dispatcher) : dispatcher(dispatcher) {}
static SwiftMangledName mangleModuleName(std::string_view name);
// TODO actual visit
SwiftMangledName mangleDecl(const swift::Decl& decl);
SwiftMangledName mangleType(const swift::TypeBase& type) {
return visit(const_cast<swift::TypeBase*>(&type));
}
std::optional<std::string> mangleType(const swift::ModuleType& type);
private:
friend class swift::TypeVisitor<SwiftMangler, SwiftMangledName>;
#define TYPE(TYPE_ID, PARENT_TYPE)
#define BUILTIN_TYPE(TYPE_ID, PARENT_TYPE) \
std::optional<std::string> mangleType(const swift::TYPE_ID##Type& type);
#include <swift/AST/TypeNodes.def>
// default fallback for not yet mangled types. This should never be called in normal situations
// will just spawn a random name
// TODO: make it assert once we mangle all types
static SwiftMangledName visitType(const swift::TypeBase* type) { return {}; }
SwiftMangledName visitModuleType(const swift::ModuleType* type);
SwiftMangledName visitBuiltinType(const swift::BuiltinType* type);
private:
swift::Mangle::ASTMangler mangler;
SwiftDispatcher& dispatcher;
};
} // namespace codeql

View File

@@ -24,31 +24,23 @@ std::string constructName(const swift::DeclName& declName) {
}
} // namespace
std::optional<codeql::ConcreteFuncDecl> DeclTranslator::translateFuncDecl(
const swift::FuncDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillAbstractFunctionDecl(decl, *entry);
return entry;
}
return std::nullopt;
codeql::ConcreteFuncDecl DeclTranslator::translateFuncDecl(const swift::FuncDecl& decl) {
auto entry = createEntry(decl);
fillAbstractFunctionDecl(decl, entry);
return entry;
}
std::optional<codeql::ConstructorDecl> DeclTranslator::translateConstructorDecl(
codeql::ConstructorDecl DeclTranslator::translateConstructorDecl(
const swift::ConstructorDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillAbstractFunctionDecl(decl, *entry);
return entry;
}
return std::nullopt;
auto entry = createEntry(decl);
fillAbstractFunctionDecl(decl, entry);
return entry;
}
std::optional<codeql::DestructorDecl> DeclTranslator::translateDestructorDecl(
const swift::DestructorDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillAbstractFunctionDecl(decl, *entry);
return entry;
}
return std::nullopt;
codeql::DestructorDecl DeclTranslator::translateDestructorDecl(const swift::DestructorDecl& decl) {
auto entry = createEntry(decl);
fillAbstractFunctionDecl(decl, entry);
return entry;
}
codeql::PrefixOperatorDecl DeclTranslator::translatePrefixOperatorDecl(
@@ -79,16 +71,13 @@ codeql::PrecedenceGroupDecl DeclTranslator::translatePrecedenceGroupDecl(
return entry;
}
std::optional<codeql::ParamDecl> DeclTranslator::translateParamDecl(const swift::ParamDecl& decl) {
auto entry = createNamedEntry(decl);
if (!entry) {
return std::nullopt;
}
fillVarDecl(decl, *entry);
entry->is_inout = decl.isInOut();
codeql::ParamDecl DeclTranslator::translateParamDecl(const swift::ParamDecl& decl) {
auto entry = createEntry(decl);
fillVarDecl(decl, entry);
entry.is_inout = decl.isInOut();
if (auto wrapped = decl.getPropertyWrapperWrappedValueVar()) {
entry->property_wrapper_local_wrapped_var = dispatcher.fetchLabel(wrapped);
entry->property_wrapper_local_wrapped_var_binding =
entry.property_wrapper_local_wrapped_var = dispatcher.fetchLabel(wrapped);
entry.property_wrapper_local_wrapped_var_binding =
dispatcher.fetchLabel(wrapped->getParentPatternBinding());
}
return entry;
@@ -114,56 +103,35 @@ codeql::PatternBindingDecl DeclTranslator::translatePatternBindingDecl(
return entry;
}
std::optional<codeql::ConcreteVarDecl> DeclTranslator::translateVarDecl(
const swift::VarDecl& decl) {
std::optional<codeql::ConcreteVarDecl> entry;
// We do not deduplicate variables from non-swift (PCM, clang modules) modules as the mangler
// crashes sometimes
if (decl.getDeclContext()->isLocalContext() || decl.getModuleContext()->isNonSwiftModule()) {
entry = createEntry(decl);
} else {
entry = createNamedEntry(decl);
if (!entry) {
return std::nullopt;
}
}
entry->introducer_int = static_cast<uint8_t>(decl.getIntroducer());
fillVarDecl(decl, *entry);
codeql::ConcreteVarDecl DeclTranslator::translateVarDecl(const swift::VarDecl& decl) {
auto entry = createEntry(decl);
entry.introducer_int = static_cast<uint8_t>(decl.getIntroducer());
fillVarDecl(decl, entry);
return entry;
}
std::optional<codeql::StructDecl> DeclTranslator::translateStructDecl(
const swift::StructDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillNominalTypeDecl(decl, *entry);
return entry;
}
return std::nullopt;
codeql::StructDecl DeclTranslator::translateStructDecl(const swift::StructDecl& decl) {
auto entry = createEntry(decl);
fillNominalTypeDecl(decl, entry);
return entry;
}
std::optional<codeql::ClassDecl> DeclTranslator::translateClassDecl(const swift::ClassDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillNominalTypeDecl(decl, *entry);
return entry;
}
return std::nullopt;
codeql::ClassDecl DeclTranslator::translateClassDecl(const swift::ClassDecl& decl) {
auto entry = createEntry(decl);
fillNominalTypeDecl(decl, entry);
return entry;
}
std::optional<codeql::EnumDecl> DeclTranslator::translateEnumDecl(const swift::EnumDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillNominalTypeDecl(decl, *entry);
return entry;
}
return std::nullopt;
codeql::EnumDecl DeclTranslator::translateEnumDecl(const swift::EnumDecl& decl) {
auto entry = createEntry(decl);
fillNominalTypeDecl(decl, entry);
return entry;
}
std::optional<codeql::ProtocolDecl> DeclTranslator::translateProtocolDecl(
const swift::ProtocolDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillNominalTypeDecl(decl, *entry);
return entry;
}
return std::nullopt;
codeql::ProtocolDecl DeclTranslator::translateProtocolDecl(const swift::ProtocolDecl& decl) {
auto entry = createEntry(decl);
fillNominalTypeDecl(decl, entry);
return entry;
}
codeql::EnumCaseDecl DeclTranslator::translateEnumCaseDecl(const swift::EnumCaseDecl& decl) {
@@ -172,17 +140,14 @@ codeql::EnumCaseDecl DeclTranslator::translateEnumCaseDecl(const swift::EnumCase
return entry;
}
std::optional<codeql::EnumElementDecl> DeclTranslator::translateEnumElementDecl(
codeql::EnumElementDecl DeclTranslator::translateEnumElementDecl(
const swift::EnumElementDecl& decl) {
auto entry = createNamedEntry(decl);
if (!entry) {
return std::nullopt;
}
entry->name = decl.getNameStr().str();
auto entry = createEntry(decl);
entry.name = decl.getNameStr().str();
if (decl.hasParameterList()) {
entry->params = dispatcher.fetchRepeatedLabels(*decl.getParameterList());
entry.params = dispatcher.fetchRepeatedLabels(*decl.getParameterList());
}
fillValueDecl(decl, *entry);
fillValueDecl(decl, entry);
return entry;
}
@@ -194,72 +159,59 @@ codeql::GenericTypeParamDecl DeclTranslator::translateGenericTypeParamDecl(
return entry;
}
std::optional<codeql::AssociatedTypeDecl> DeclTranslator::translateAssociatedTypeDecl(
codeql::AssociatedTypeDecl DeclTranslator::translateAssociatedTypeDecl(
const swift::AssociatedTypeDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillTypeDecl(decl, *entry);
return entry;
}
return std::nullopt;
}
std::optional<codeql::TypeAliasDecl> DeclTranslator::translateTypeAliasDecl(
const swift::TypeAliasDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
entry->aliased_type = dispatcher.fetchLabel(decl.getUnderlyingType());
fillTypeDecl(decl, *entry);
return entry;
}
return std::nullopt;
}
std::optional<codeql::AccessorDecl> DeclTranslator::translateAccessorDecl(
const swift::AccessorDecl& decl) {
auto entry = createNamedEntry(decl);
if (!entry) {
return std::nullopt;
}
switch (decl.getAccessorKind()) {
case swift::AccessorKind::Get:
entry->is_getter = true;
break;
case swift::AccessorKind::Set:
entry->is_setter = true;
break;
case swift::AccessorKind::WillSet:
entry->is_will_set = true;
break;
case swift::AccessorKind::DidSet:
entry->is_did_set = true;
break;
case swift::AccessorKind::Read:
entry->is_read = true;
break;
case swift::AccessorKind::Modify:
entry->is_modify = true;
break;
case swift::AccessorKind::Address:
entry->is_unsafe_address = true;
break;
case swift::AccessorKind::MutableAddress:
entry->is_unsafe_mutable_address = true;
break;
}
fillAbstractFunctionDecl(decl, *entry);
auto entry = createEntry(decl);
fillTypeDecl(decl, entry);
return entry;
}
std::optional<codeql::SubscriptDecl> DeclTranslator::translateSubscriptDecl(
const swift::SubscriptDecl& decl) {
auto entry = createNamedEntry(decl);
if (!entry) {
return std::nullopt;
codeql::TypeAliasDecl DeclTranslator::translateTypeAliasDecl(const swift::TypeAliasDecl& decl) {
auto entry = createEntry(decl);
entry.aliased_type = dispatcher.fetchLabel(decl.getUnderlyingType());
fillTypeDecl(decl, entry);
return entry;
}
codeql::AccessorDecl DeclTranslator::translateAccessorDecl(const swift::AccessorDecl& decl) {
auto entry = createEntry(decl);
switch (decl.getAccessorKind()) {
case swift::AccessorKind::Get:
entry.is_getter = true;
break;
case swift::AccessorKind::Set:
entry.is_setter = true;
break;
case swift::AccessorKind::WillSet:
entry.is_will_set = true;
break;
case swift::AccessorKind::DidSet:
entry.is_did_set = true;
break;
case swift::AccessorKind::Read:
entry.is_read = true;
break;
case swift::AccessorKind::Modify:
entry.is_modify = true;
break;
case swift::AccessorKind::Address:
entry.is_unsafe_address = true;
break;
case swift::AccessorKind::MutableAddress:
entry.is_unsafe_mutable_address = true;
break;
}
entry->element_type = dispatcher.fetchLabel(decl.getElementInterfaceType());
fillAbstractFunctionDecl(decl, entry);
return entry;
}
codeql::SubscriptDecl DeclTranslator::translateSubscriptDecl(const swift::SubscriptDecl& decl) {
auto entry = createEntry(decl);
entry.element_type = dispatcher.fetchLabel(decl.getElementInterfaceType());
if (auto indices = decl.getIndices()) {
entry->params = dispatcher.fetchRepeatedLabels(*indices);
entry.params = dispatcher.fetchRepeatedLabels(*indices);
}
fillAbstractStorageDecl(decl, *entry);
fillAbstractStorageDecl(decl, entry);
return entry;
}
@@ -280,33 +232,25 @@ codeql::ImportDecl DeclTranslator::translateImportDecl(const swift::ImportDecl&
return entry;
}
std::optional<codeql::ModuleDecl> DeclTranslator::translateModuleDecl(
const swift::ModuleDecl& decl) {
auto entry = createNamedEntry(decl);
if (!entry) {
return std::nullopt;
}
entry->is_builtin_module = decl.isBuiltinModule();
entry->is_system_module = decl.isSystemModule();
codeql::ModuleDecl DeclTranslator::translateModuleDecl(const swift::ModuleDecl& decl) {
auto entry = createEntry(decl);
entry.is_builtin_module = decl.isBuiltinModule();
entry.is_system_module = decl.isSystemModule();
using K = swift::ModuleDecl::ImportFilterKind;
llvm::SmallVector<swift::ImportedModule> imports;
decl.getImportedModules(imports, K::Default);
for (const auto& import : imports) {
entry->imported_modules.push_back(dispatcher.fetchLabel(import.importedModule));
entry.imported_modules.push_back(dispatcher.fetchLabel(import.importedModule));
}
imports.clear();
decl.getImportedModules(imports, K::Exported);
for (const auto& import : imports) {
entry->exported_modules.push_back(dispatcher.fetchLabel(import.importedModule));
entry.exported_modules.push_back(dispatcher.fetchLabel(import.importedModule));
}
fillTypeDecl(decl, *entry);
fillTypeDecl(decl, entry);
return entry;
}
std::string DeclTranslator::mangledName(const swift::ValueDecl& decl) {
return mangler.mangledName(decl);
}
void DeclTranslator::fillAbstractFunctionDecl(const swift::AbstractFunctionDecl& decl,
codeql::AbstractFunctionDecl& entry) {
assert(decl.hasParameterList() && "Expect functions to have a parameter list");
@@ -396,15 +340,12 @@ codeql::IfConfigDecl DeclTranslator::translateIfConfigDecl(const swift::IfConfig
return entry;
}
std::optional<codeql::OpaqueTypeDecl> DeclTranslator::translateOpaqueTypeDecl(
const swift::OpaqueTypeDecl& decl) {
if (auto entry = createNamedEntry(decl)) {
fillTypeDecl(decl, *entry);
entry->naming_declaration = dispatcher.fetchLabel(decl.getNamingDecl());
entry->opaque_generic_params = dispatcher.fetchRepeatedLabels(decl.getOpaqueGenericParams());
return entry;
}
return std::nullopt;
codeql::OpaqueTypeDecl DeclTranslator::translateOpaqueTypeDecl(const swift::OpaqueTypeDecl& decl) {
auto entry = createEntry(decl);
fillTypeDecl(decl, entry);
entry.naming_declaration = dispatcher.fetchLabel(decl.getNamingDecl());
entry.opaque_generic_params = dispatcher.fetchRepeatedLabels(decl.getOpaqueGenericParams());
return entry;
}
codeql::PoundDiagnosticDecl DeclTranslator::translatePoundDiagnosticDecl(
@@ -423,7 +364,7 @@ codeql::MissingMemberDecl DeclTranslator::translateMissingMemberDecl(
}
codeql::CapturedDecl DeclTranslator::translateCapturedValue(const swift::CapturedValue& capture) {
codeql::CapturedDecl entry{dispatcher.template assignNewLabel(capture)};
auto entry = dispatcher.createEntry(capture);
auto decl = capture.getDecl();
entry.decl = dispatcher.fetchLabel(decl);
entry.module = dispatcher.fetchLabel(decl->getModuleContext());

View File

@@ -6,7 +6,6 @@
#include "swift/extractor/translators/TranslatorBase.h"
#include "swift/extractor/trap/generated/decl/TrapClasses.h"
#include "swift/extractor/mangler/SwiftMangler.h"
namespace codeql {
@@ -17,43 +16,39 @@ class DeclTranslator : public AstTranslatorBase<DeclTranslator> {
public:
using AstTranslatorBase<DeclTranslator>::AstTranslatorBase;
std::optional<codeql::ConcreteFuncDecl> translateFuncDecl(const swift::FuncDecl& decl);
std::optional<codeql::ConstructorDecl> translateConstructorDecl(
const swift::ConstructorDecl& decl);
std::optional<codeql::DestructorDecl> translateDestructorDecl(const swift::DestructorDecl& decl);
codeql::ConcreteFuncDecl translateFuncDecl(const swift::FuncDecl& decl);
codeql::ConstructorDecl translateConstructorDecl(const swift::ConstructorDecl& decl);
codeql::DestructorDecl translateDestructorDecl(const swift::DestructorDecl& decl);
codeql::PrefixOperatorDecl translatePrefixOperatorDecl(const swift::PrefixOperatorDecl& decl);
codeql::PostfixOperatorDecl translatePostfixOperatorDecl(const swift::PostfixOperatorDecl& decl);
codeql::InfixOperatorDecl translateInfixOperatorDecl(const swift::InfixOperatorDecl& decl);
codeql::PrecedenceGroupDecl translatePrecedenceGroupDecl(const swift::PrecedenceGroupDecl& decl);
std::optional<codeql::ParamDecl> translateParamDecl(const swift::ParamDecl& decl);
codeql::ParamDecl translateParamDecl(const swift::ParamDecl& decl);
codeql::TopLevelCodeDecl translateTopLevelCodeDecl(const swift::TopLevelCodeDecl& decl);
codeql::PatternBindingDecl translatePatternBindingDecl(const swift::PatternBindingDecl& decl);
std::optional<codeql::ConcreteVarDecl> translateVarDecl(const swift::VarDecl& decl);
std::optional<codeql::StructDecl> translateStructDecl(const swift::StructDecl& decl);
std::optional<codeql::ClassDecl> translateClassDecl(const swift::ClassDecl& decl);
std::optional<codeql::EnumDecl> translateEnumDecl(const swift::EnumDecl& decl);
std::optional<codeql::ProtocolDecl> translateProtocolDecl(const swift::ProtocolDecl& decl);
codeql::ConcreteVarDecl translateVarDecl(const swift::VarDecl& decl);
codeql::StructDecl translateStructDecl(const swift::StructDecl& decl);
codeql::ClassDecl translateClassDecl(const swift::ClassDecl& decl);
codeql::EnumDecl translateEnumDecl(const swift::EnumDecl& decl);
codeql::ProtocolDecl translateProtocolDecl(const swift::ProtocolDecl& decl);
codeql::EnumCaseDecl translateEnumCaseDecl(const swift::EnumCaseDecl& decl);
std::optional<codeql::EnumElementDecl> translateEnumElementDecl(
const swift::EnumElementDecl& decl);
codeql::EnumElementDecl translateEnumElementDecl(const swift::EnumElementDecl& decl);
codeql::GenericTypeParamDecl translateGenericTypeParamDecl(
const swift::GenericTypeParamDecl& decl);
std::optional<codeql::AssociatedTypeDecl> translateAssociatedTypeDecl(
const swift::AssociatedTypeDecl& decl);
std::optional<codeql::TypeAliasDecl> translateTypeAliasDecl(const swift::TypeAliasDecl& decl);
std::optional<codeql::AccessorDecl> translateAccessorDecl(const swift::AccessorDecl& decl);
std::optional<codeql::SubscriptDecl> translateSubscriptDecl(const swift::SubscriptDecl& decl);
codeql::AssociatedTypeDecl translateAssociatedTypeDecl(const swift::AssociatedTypeDecl& decl);
codeql::TypeAliasDecl translateTypeAliasDecl(const swift::TypeAliasDecl& decl);
codeql::AccessorDecl translateAccessorDecl(const swift::AccessorDecl& decl);
codeql::SubscriptDecl translateSubscriptDecl(const swift::SubscriptDecl& decl);
codeql::ExtensionDecl translateExtensionDecl(const swift::ExtensionDecl& decl);
codeql::ImportDecl translateImportDecl(const swift::ImportDecl& decl);
std::optional<codeql::ModuleDecl> translateModuleDecl(const swift::ModuleDecl& decl);
codeql::ModuleDecl translateModuleDecl(const swift::ModuleDecl& decl);
codeql::IfConfigDecl translateIfConfigDecl(const swift::IfConfigDecl& decl);
std::optional<codeql::OpaqueTypeDecl> translateOpaqueTypeDecl(const swift::OpaqueTypeDecl& decl);
codeql::OpaqueTypeDecl translateOpaqueTypeDecl(const swift::OpaqueTypeDecl& decl);
codeql::PoundDiagnosticDecl translatePoundDiagnosticDecl(const swift::PoundDiagnosticDecl& decl);
codeql::MissingMemberDecl translateMissingMemberDecl(const swift::MissingMemberDecl& decl);
codeql::CapturedDecl translateCapturedValue(const swift::CapturedValue& capture);
private:
std::string mangledName(const swift::ValueDecl& decl);
void fillAbstractFunctionDecl(const swift::AbstractFunctionDecl& decl,
codeql::AbstractFunctionDecl& entry);
void fillOperatorDecl(const swift::OperatorDecl& decl, codeql::OperatorDecl& entry);
@@ -66,23 +61,9 @@ class DeclTranslator : public AstTranslatorBase<DeclTranslator> {
void fillAbstractStorageDecl(const swift::AbstractStorageDecl& decl,
codeql::AbstractStorageDecl& entry);
template <typename D>
auto createNamedEntry(const D& decl) {
std::optional<TrapClassOf<D>> entry;
auto id = dispatcher.assignNewLabel(decl, mangledName(decl));
if (dispatcher.shouldEmitDeclBody(decl)) {
dispatcher.extractedDeclaration(decl);
entry.emplace(id);
fillDecl(decl, *entry);
} else {
dispatcher.skippedDeclaration(decl);
}
return entry;
}
template <typename D>
auto createEntry(const D& decl) {
TrapClassOf<D> entry{dispatcher.template assignNewLabel(decl)};
auto entry = dispatcher.createEntry(decl);
fillDecl(decl, entry);
return entry;
}
@@ -90,8 +71,6 @@ class DeclTranslator : public AstTranslatorBase<DeclTranslator> {
void fillDecl(const swift::Decl& decl, codeql::Decl& entry) {
entry.module = dispatcher.fetchLabel(decl.getModuleContext());
}
SwiftMangler mangler;
};
} // namespace codeql

View File

@@ -6,6 +6,7 @@
#include "swift/extractor/translators/StmtTranslator.h"
#include "swift/extractor/translators/TypeTranslator.h"
#include "swift/extractor/translators/PatternTranslator.h"
#include "swift/extractor/mangler/SwiftMangler.h"
namespace codeql {
@@ -17,10 +18,13 @@ class SwiftVisitor : private SwiftDispatcher {
template <typename T>
void extract(const T& entity) {
fetchLabel(entity);
visitPending();
}
void extract(swift::Token& comment) { emitComment(comment); }
private:
SwiftMangledName name(const swift::Decl* decl) override { return mangler.mangleDecl(*decl); }
SwiftMangledName name(const swift::TypeBase* type) override { return mangler.mangleType(*type); }
void visit(const swift::Decl* decl) override { declTranslator.translateAndEmit(*decl); }
void visit(const swift::Stmt* stmt) override { stmtTranslator.translateAndEmit(*stmt); }
void visit(const swift::StmtCondition* cond) override { stmtTranslator.translateAndEmit(*cond); }
@@ -54,6 +58,7 @@ class SwiftVisitor : private SwiftDispatcher {
StmtTranslator stmtTranslator{*this};
TypeTranslator typeTranslator{*this};
PatternTranslator patternTranslator{*this};
SwiftMangler mangler{*this};
};
} // namespace codeql

View File

@@ -2,7 +2,6 @@
#include "swift/extractor/translators/TranslatorBase.h"
#include "swift/extractor/trap/generated/type/TrapClasses.h"
#include "swift/extractor/mangler/SwiftMangler.h"
namespace codeql {
class TypeTranslator : public TypeTranslatorBase<TypeTranslator> {
@@ -88,23 +87,12 @@ class TypeTranslator : public TypeTranslatorBase<TypeTranslator> {
void fillBoundGenericType(const swift::BoundGenericType& type, codeql::BoundGenericType& entry);
void fillAnyGenericType(const swift::AnyGenericType& type, codeql::AnyGenericType& entry);
template <typename T>
auto createMangledTypeEntry(const T& type) {
auto mangledName = mangler.mangleType(type);
if (mangledName) {
return dispatcher.createEntry(type, mangledName.value());
}
return dispatcher.createEntry(type);
}
template <typename T>
auto createTypeEntry(const T& type) {
auto entry = createMangledTypeEntry(type);
auto entry = dispatcher.createEntry(type);
fillType(type, entry);
return entry;
}
SwiftMangler mangler;
};
} // namespace codeql

View File

@@ -6,6 +6,7 @@
#include "swift/extractor/trap/TrapLabel.h"
#include "swift/extractor/infra/file/TargetFile.h"
#include "swift/extractor/infra/log/SwiftLogging.h"
#include "swift/extractor/infra/SwiftMangledName.h"
namespace codeql {
@@ -32,59 +33,56 @@ class TrapDomain {
out << "\n*/\n";
}
template <typename Tag>
TrapLabel<Tag> createLabel() {
auto ret = allocateLabel<Tag>();
UntypedTrapLabel createLabel() {
auto ret = allocateLabel();
assignStar(ret);
out << '\n';
return ret;
}
template <typename Tag, typename... Args>
TrapLabel<Tag> createLabel(Args&&... args) {
auto ret = allocateLabel<Tag>();
assignKey(ret, std::forward<Args>(args)...);
template <typename Tag>
TrapLabel<Tag> createTypedLabel() {
auto untyped = createLabel();
return TrapLabel<Tag>::unsafeCreateFromUntyped(untyped);
}
UntypedTrapLabel createLabel(const SwiftMangledName& name) {
auto ret = allocateLabel();
assignKey(ret, name);
out << '\n';
return ret;
}
template <typename Tag, typename... Args>
TrapLabel<Tag> createLabelWithImplementationId(const std::string_view& implementationId,
Args&&... args) {
auto ret = allocateLabel<Tag>();
assignKey(ret, std::forward<Args>(args)...);
template <typename Tag>
TrapLabel<Tag> createTypedLabel(const SwiftMangledName& name) {
auto untyped = createLabel(name);
return TrapLabel<Tag>::unsafeCreateFromUntyped(untyped);
}
template <typename Tag>
TrapLabel<Tag> createTypedLabelWithImplementationId(const SwiftMangledName& name,
const std::string_view& implementationId) {
auto untyped = allocateLabel();
assignKey(untyped, name);
LOG_TRACE("^^^ .implementation {}", implementationId);
out << " .implementation " << trapQuoted(implementationId) << '\n';
return ret;
return TrapLabel<Tag>::unsafeCreateFromUntyped(untyped);
}
private:
uint64_t id_{0};
template <typename Tag>
TrapLabel<Tag> allocateLabel() {
return TrapLabel<Tag>::unsafeCreateFromExplicitId(id_++);
}
UntypedTrapLabel allocateLabel() { return UntypedTrapLabel{id_++}; }
template <typename Tag>
void assignStar(TrapLabel<Tag> label) {
void assignStar(UntypedTrapLabel label) {
LOG_TRACE("{}=*", label);
out << label << "=*";
}
template <typename Tag>
void assignKey(TrapLabel<Tag> label, const std::string& key) {
// prefix the key with the id to guarantee the same key is not used wrongly with different tags
auto prefixed = std::string(Tag::prefix) + '_' + key;
LOG_TRACE("{}=@{}", label, prefixed);
out << label << "=@" << trapQuoted(prefixed);
}
template <typename Tag, typename... Args>
void assignKey(TrapLabel<Tag> label, const Args&... keyParts) {
std::ostringstream oss;
(oss << ... << keyParts);
assignKey(label, oss.str());
void assignKey(UntypedTrapLabel label, const SwiftMangledName& name) {
auto key = name.str();
LOG_TRACE("{}=@{}", label, key);
out << label << "=@" << trapQuoted(key);
}
std::string getLoggerName() {

View File

@@ -26,11 +26,11 @@ class UntypedTrapLabel {
static constexpr uint64_t undefined = 0xffffffffffffffff;
protected:
UntypedTrapLabel() : id_{undefined} {}
UntypedTrapLabel(uint64_t id) : id_{id} { assert(id != undefined); }
public:
UntypedTrapLabel() : id_{undefined} {}
explicit UntypedTrapLabel(uint64_t id) : id_{id} { assert(id != undefined); }
UntypedTrapLabel(UndefinedTrapLabel) : UntypedTrapLabel() {}
bool valid() const { return id_ != undefined; }
explicit operator bool() const { return valid(); }
@@ -58,6 +58,8 @@ class UntypedTrapLabel {
// Number of hex digits is ceil(bit_width(id) / 4), but C++ integer division can only do floor.
return /* # */ 1 + /* hex digits */ 1 + (absl::bit_width(id_) - 1) / 4;
}
friend bool operator!=(UntypedTrapLabel lhs, UntypedTrapLabel rhs) { return lhs.id_ != rhs.id_; }
};
template <typename TagParam>
@@ -79,8 +81,8 @@ class TrapLabel : public UntypedTrapLabel {
}
// The caller is responsible for ensuring ID uniqueness.
static TrapLabel unsafeCreateFromExplicitId(uint64_t id) { return {id}; }
static TrapLabel unsafeCreateFromUntyped(UntypedTrapLabel label) { return {label.id_}; }
static TrapLabel unsafeCreateFromExplicitId(uint64_t id) { return TrapLabel{id}; }
static TrapLabel unsafeCreateFromUntyped(UntypedTrapLabel label) { return TrapLabel{label.id_}; }
template <typename SourceTag>
TrapLabel(const TrapLabel<SourceTag>& other) : UntypedTrapLabel(other) {

View File

@@ -1,43 +0,0 @@
#pragma once
#include <variant>
#include <cassert>
#include <optional>
#include <unordered_map>
#include <swift/AST/ASTVisitor.h>
#include "swift/extractor/trap/TrapLabel.h"
#include "swift/extractor/trap/TrapTagTraits.h"
#include "swift/extractor/trap/generated/TrapTags.h"
namespace codeql {
// The extraction is done in a lazy/on-demand fashion:
// Each emitted TRAP entry for an AST node gets a TRAP label assigned to it.
// To avoid re-emission, we store the "AST node <> label" entry in the TrapLabelStore.
// The template parameters `Ts...` indicate to what entity types we restrict the storage
template <typename... Ts>
class TrapLabelStore {
public:
using Handle = std::variant<std::monostate, Ts...>;
template <typename T>
std::optional<TrapLabelOf<T>> get(const T& e) {
if (auto found = store_.find(e); found != store_.end()) {
return TrapLabelOf<T>::unsafeCreateFromUntyped(found->second);
}
return std::nullopt;
}
template <typename T>
void insert(const T& e, TrapLabelOf<T> l) {
auto [_, inserted] = store_.emplace(e, l);
assert(inserted && "already inserted");
}
private:
std::unordered_map<Handle, UntypedTrapLabel> store_;
};
} // namespace codeql

View File

@@ -1,3 +1,5 @@
| (Builtin.IntLiteral, Builtin.IntLiteral) | getName: | (Builtin.IntLiteral, Builtin.IntLiteral) | getCanonicalType: | (Builtin.IntLiteral, Builtin.IntLiteral) | getNumberOfTypes: | 2 |
| (Builtin.IntLiteral, Builtin.IntLiteral) | getName: | (Builtin.IntLiteral, Builtin.IntLiteral) | getCanonicalType: | (Builtin.IntLiteral, Builtin.IntLiteral) | getNumberOfTypes: | 2 |
| (Int, Int, Int, Int, Int) | getName: | (Int, Int, Int, Int, Int) | getCanonicalType: | (Int, Int, Int, Int, Int) | getNumberOfTypes: | 5 |
| (Int, String, Double) | getName: | (Int, String, Double) | getCanonicalType: | (Int, String, Double) | getNumberOfTypes: | 3 |
| (Int, s: String, Double) | getName: | (Int, s: String, Double) | getCanonicalType: | (Int, s: String, Double) | getNumberOfTypes: | 3 |

View File

@@ -1,3 +1,7 @@
| (Builtin.IntLiteral, Builtin.IntLiteral) | 0 | Builtin.IntLiteral |
| (Builtin.IntLiteral, Builtin.IntLiteral) | 0 | Builtin.IntLiteral |
| (Builtin.IntLiteral, Builtin.IntLiteral) | 1 | Builtin.IntLiteral |
| (Builtin.IntLiteral, Builtin.IntLiteral) | 1 | Builtin.IntLiteral |
| (Int, Int, Int, Int, Int) | 0 | Int |
| (Int, Int, Int, Int, Int) | 1 | Int |
| (Int, Int, Int, Int, Int) | 2 | Int |

View File

@@ -0,0 +1,2 @@
//codeql-extractor-options: -parse-stdlib
func f(x : (Builtin.IntLiteral, Builtin.IntLiteral)) {}