Swift: change translation signature and detection

Translation now takes const references to swift entities and return
trap entries (instead of taking apointer as an out parameter).
This commit is contained in:
Paolo Tranquilli 2022-05-31 11:07:58 +02:00
Родитель c3cb0d6ad7
Коммит 19f16678ac
4 изменённых файлов: 151 добавлений и 135 удалений

Просмотреть файл

@ -14,9 +14,9 @@ namespace {{namespace}} {
{{#classes}}
struct {{name}}{{#has_bases}} : {{#bases}}{{^first}}, {{/first}}{{ref.name}}{{/bases}}{{/has_bases}} {
{{name}}() {}
{{#final}}
explicit {{name}}({{trap_affix}}Label<{{name}}Tag> id) : id{id} {}
{{trap_affix}}Label<{{name}}Tag> id{};
{{/final}}
{{#fields}}

Просмотреть файл

@ -83,6 +83,11 @@ class SwiftDispatcher {
return label;
}
template <typename E, typename = std::enable_if_t<!std::is_pointer_v<E>>>
TrapLabelOf<E> assignNewLabel(E& e) {
return assignNewLabel(&e);
}
template <typename Tag>
TrapLabel<Tag> createLabel() {
auto ret = arena.allocateLabel<Tag>();
@ -132,10 +137,10 @@ class SwiftDispatcher {
// map `fetchLabel` on the iterable `arg`, returning a vector of all labels
template <typename Iterable>
auto fetchRepeatedLabels(Iterable&& arg) -> std::vector<decltype(fetchLabel(*arg.begin()))> {
auto fetchRepeatedLabels(Iterable&& arg) {
std::vector<decltype(fetchLabel(*arg.begin()))> ret;
ret.reserve(arg.size());
for (const auto& e : arg) {
for (const auto& e : std::forward<Iterable>(arg)) {
ret.push_back(fetchLabel(e));
}
return ret;

Просмотреть файл

@ -11,216 +11,232 @@ namespace codeql {
// `swift::Decl` visitor
class DeclVisitor : public AstVisitorBase<DeclVisitor> {
public:
void translateFuncDecl(swift::FuncDecl* decl, codeql::ConcreteFuncDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::ConcreteFuncDecl translateFuncDecl(const swift::FuncDecl& decl) {
ConcreteFuncDecl entry{dispatcher_.assignNewLabel(decl)};
fillAbstractFunctionDecl(decl, entry);
return entry;
}
void translateConstructorDecl(swift::ConstructorDecl* decl, codeql::ConstructorDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::ConstructorDecl translateConstructorDecl(const swift::ConstructorDecl& decl) {
ConstructorDecl entry{dispatcher_.assignNewLabel(decl)};
fillAbstractFunctionDecl(decl, entry);
return entry;
}
void translateDestructorDecl(swift::DestructorDecl* decl, codeql::DestructorDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::DestructorDecl translateDestructorDecl(const swift::DestructorDecl& decl) {
DestructorDecl entry{dispatcher_.assignNewLabel(decl)};
fillAbstractFunctionDecl(decl, entry);
return entry;
}
void translatePrefixOperatorDecl(swift::PrefixOperatorDecl* decl,
codeql::PrefixOperatorDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::PrefixOperatorDecl translatePrefixOperatorDecl(const swift::PrefixOperatorDecl& decl) {
PrefixOperatorDecl entry{dispatcher_.assignNewLabel(decl)};
fillOperatorDecl(decl, entry);
return entry;
}
void translatePostfixOperatorDecl(swift::PostfixOperatorDecl* decl,
codeql::PostfixOperatorDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::PostfixOperatorDecl translatePostfixOperatorDecl(const swift::PostfixOperatorDecl& decl) {
PostfixOperatorDecl entry{dispatcher_.assignNewLabel(decl)};
fillOperatorDecl(decl, entry);
return entry;
}
void translateInfixOperatorDecl(swift::InfixOperatorDecl* decl,
codeql::InfixOperatorDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
entry->precedence_group = dispatcher_.fetchOptionalLabel(decl->getPrecedenceGroup());
codeql::InfixOperatorDecl translateInfixOperatorDecl(const swift::InfixOperatorDecl& decl) {
InfixOperatorDecl entry{dispatcher_.assignNewLabel(decl)};
entry.precedence_group = dispatcher_.fetchOptionalLabel(decl.getPrecedenceGroup());
fillOperatorDecl(decl, entry);
return entry;
}
void translatePrecedenceGroupDecl(swift::PrecedenceGroupDecl* decl,
codeql::PrecedenceGroupDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::PrecedenceGroupDecl translatePrecedenceGroupDecl(const swift::PrecedenceGroupDecl& decl) {
PrecedenceGroupDecl entry{dispatcher_.assignNewLabel(decl)};
return entry;
}
void translateParamDecl(swift::ParamDecl* decl, codeql::ParamDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::ParamDecl translateParamDecl(const swift::ParamDecl& decl) {
ParamDecl entry{dispatcher_.assignNewLabel(decl)};
fillVarDecl(decl, entry);
return entry;
}
void translateTopLevelCodeDecl(swift::TopLevelCodeDecl* decl, codeql::TopLevelCodeDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
assert(decl->getBody() && "Expect top level code to have body");
entry->body = dispatcher_.fetchLabel(decl->getBody());
codeql::TopLevelCodeDecl translateTopLevelCodeDecl(const swift::TopLevelCodeDecl& decl) {
TopLevelCodeDecl entry{dispatcher_.assignNewLabel(decl)};
assert(decl.getBody() && "Expect top level code to have body");
entry.body = dispatcher_.fetchLabel(decl.getBody());
return entry;
}
void translatePatternBindingDecl(swift::PatternBindingDecl* decl,
codeql::PatternBindingDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
for (unsigned i = 0; i < decl->getNumPatternEntries(); ++i) {
auto pattern = decl->getPattern(i);
codeql::PatternBindingDecl translatePatternBindingDecl(const swift::PatternBindingDecl& decl) {
PatternBindingDecl entry{dispatcher_.assignNewLabel(decl)};
for (unsigned i = 0; i < decl.getNumPatternEntries(); ++i) {
auto pattern = decl.getPattern(i);
assert(pattern && "Expect pattern binding decl to have all patterns");
entry->patterns.push_back(dispatcher_.fetchLabel(pattern));
entry->inits.push_back(dispatcher_.fetchOptionalLabel(decl->getInit(i)));
entry.patterns.push_back(dispatcher_.fetchLabel(pattern));
entry.inits.push_back(dispatcher_.fetchOptionalLabel(decl.getInit(i)));
}
return entry;
}
void translateVarDecl(swift::VarDecl* decl, codeql::ConcreteVarDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
entry->introducer_int = static_cast<uint8_t>(decl->getIntroducer());
codeql::ConcreteVarDecl translateVarDecl(const swift::VarDecl& decl) {
ConcreteVarDecl entry{dispatcher_.assignNewLabel(decl)};
entry.introducer_int = static_cast<uint8_t>(decl.getIntroducer());
fillVarDecl(decl, entry);
return entry;
}
void translateStructDecl(swift::StructDecl* decl, codeql::StructDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::StructDecl translateStructDecl(const swift::StructDecl& decl) {
StructDecl entry{dispatcher_.assignNewLabel(decl)};
fillNominalTypeDecl(decl, entry);
return entry;
}
void translateClassDecl(swift::ClassDecl* decl, codeql::ClassDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::ClassDecl translateClassDecl(const swift::ClassDecl& decl) {
ClassDecl entry{dispatcher_.assignNewLabel(decl)};
fillNominalTypeDecl(decl, entry);
return entry;
}
void translateEnumDecl(swift::EnumDecl* decl, codeql::EnumDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::EnumDecl translateEnumDecl(const swift::EnumDecl& decl) {
EnumDecl entry{dispatcher_.assignNewLabel(decl)};
fillNominalTypeDecl(decl, entry);
return entry;
}
void translateProtocolDecl(swift::ProtocolDecl* decl, codeql::ProtocolDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::ProtocolDecl translateProtocolDecl(const swift::ProtocolDecl& decl) {
ProtocolDecl entry{dispatcher_.assignNewLabel(decl)};
fillNominalTypeDecl(decl, entry);
return entry;
}
void translateEnumCaseDecl(swift::EnumCaseDecl* decl, codeql::EnumCaseDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
entry->elements = dispatcher_.fetchRepeatedLabels(decl->getElements());
codeql::EnumCaseDecl translateEnumCaseDecl(const swift::EnumCaseDecl& decl) {
EnumCaseDecl entry{dispatcher_.assignNewLabel(decl)};
entry.elements = dispatcher_.fetchRepeatedLabels(decl.getElements());
return entry;
}
void translateEnumElementDecl(swift::EnumElementDecl* decl, codeql::EnumElementDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
entry->name = decl->getNameStr().str();
if (decl->hasParameterList()) {
entry->params = dispatcher_.fetchRepeatedLabels(*decl->getParameterList());
codeql::EnumElementDecl translateEnumElementDecl(const swift::EnumElementDecl& decl) {
EnumElementDecl entry{dispatcher_.assignNewLabel(decl)};
entry.name = decl.getNameStr().str();
if (decl.hasParameterList()) {
entry.params = dispatcher_.fetchRepeatedLabels(*decl.getParameterList());
}
fillValueDecl(decl, entry);
return entry;
}
void translateGenericTypeParamDecl(swift::GenericTypeParamDecl* decl,
GenericTypeParamDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::GenericTypeParamDecl translateGenericTypeParamDecl(
const swift::GenericTypeParamDecl& decl) {
GenericTypeParamDecl entry{dispatcher_.assignNewLabel(decl)};
fillTypeDecl(decl, entry);
return entry;
}
void translateAssociatedTypeDecl(swift::AssociatedTypeDecl* decl,
codeql::AssociatedTypeDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::AssociatedTypeDecl translateAssociatedTypeDecl(const swift::AssociatedTypeDecl& decl) {
AssociatedTypeDecl entry{dispatcher_.assignNewLabel(decl)};
fillTypeDecl(decl, entry);
return entry;
}
void translateTypeAliasDecl(swift::TypeAliasDecl* decl, codeql::TypeAliasDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
codeql::TypeAliasDecl translateTypeAliasDecl(const swift::TypeAliasDecl& decl) {
TypeAliasDecl entry{dispatcher_.assignNewLabel(decl)};
fillTypeDecl(decl, entry);
return entry;
}
void translateAccessorDecl(swift::AccessorDecl* decl, codeql::AccessorDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
switch (decl->getAccessorKind()) {
codeql::AccessorDecl translateAccessorDecl(const swift::AccessorDecl& decl) {
AccessorDecl entry{dispatcher_.assignNewLabel(decl)};
switch (decl.getAccessorKind()) {
case swift::AccessorKind::Get:
entry->is_getter = true;
entry.is_getter = true;
break;
case swift::AccessorKind::Set:
entry->is_setter = true;
entry.is_setter = true;
break;
case swift::AccessorKind::WillSet:
entry->is_will_set = true;
entry.is_will_set = true;
break;
case swift::AccessorKind::DidSet:
entry->is_did_set = true;
entry.is_did_set = true;
break;
}
fillAbstractFunctionDecl(decl, entry);
return entry;
}
void translateSubscriptDecl(swift::SubscriptDecl* decl, codeql::SubscriptDecl* entry) {
entry->id = dispatcher_.assignNewLabel(decl);
entry->element_type = dispatcher_.fetchLabel(decl->getElementInterfaceType());
if (auto indices = decl->getIndices()) {
entry->params = dispatcher_.fetchRepeatedLabels(*indices);
codeql::SubscriptDecl translateSubscriptDecl(const swift::SubscriptDecl& decl) {
SubscriptDecl entry{dispatcher_.assignNewLabel(decl)};
entry.element_type = dispatcher_.fetchLabel(decl.getElementInterfaceType());
if (auto indices = decl.getIndices()) {
entry.params = dispatcher_.fetchRepeatedLabels(*indices);
}
fillAbstractStorageDecl(decl, entry);
return entry;
}
private:
void fillAbstractFunctionDecl(swift::AbstractFunctionDecl* decl,
codeql::AbstractFunctionDecl* entry) {
assert(decl->hasParameterList() && "Expect functions to have a parameter list");
entry->name = !decl->hasName() || decl->getName().isSpecial() ? "(unnamed function decl)"
: decl->getNameStr().str();
entry->body = dispatcher_.fetchOptionalLabel(decl->getBody());
entry->params = dispatcher_.fetchRepeatedLabels(*decl->getParameters());
void fillAbstractFunctionDecl(const swift::AbstractFunctionDecl& decl,
codeql::AbstractFunctionDecl& entry) {
assert(decl.hasParameterList() && "Expect functions to have a parameter list");
entry.name = !decl.hasName() || decl.getName().isSpecial() ? "(unnamed function decl)"
: decl.getNameStr().str();
entry.body = dispatcher_.fetchOptionalLabel(decl.getBody());
entry.params = dispatcher_.fetchRepeatedLabels(*decl.getParameters());
fillValueDecl(decl, entry);
fillGenericContext(decl, entry);
}
void fillOperatorDecl(swift::OperatorDecl* decl, codeql::OperatorDecl* entry) {
entry->name = decl->getName().str().str();
void fillOperatorDecl(const swift::OperatorDecl& decl, codeql::OperatorDecl& entry) {
entry.name = decl.getName().str().str();
}
void fillTypeDecl(swift::TypeDecl* decl, codeql::TypeDecl* entry) {
entry->name = decl->getNameStr().str();
for (auto& typeLoc : decl->getInherited()) {
void fillTypeDecl(const swift::TypeDecl& decl, codeql::TypeDecl& entry) {
entry.name = decl.getNameStr().str();
for (auto& typeLoc : decl.getInherited()) {
if (auto type = typeLoc.getType()) {
entry->base_types.push_back(dispatcher_.fetchLabel(type));
entry.base_types.push_back(dispatcher_.fetchLabel(type));
}
}
fillValueDecl(decl, entry);
}
void fillIterableDeclContext(swift::IterableDeclContext* decl,
codeql::IterableDeclContext* entry) {
entry->members = dispatcher_.fetchRepeatedLabels(decl->getAllMembers());
void fillIterableDeclContext(const swift::IterableDeclContext& decl,
codeql::IterableDeclContext& entry) {
entry.members = dispatcher_.fetchRepeatedLabels(decl.getAllMembers());
}
void fillVarDecl(swift::VarDecl* decl, codeql::VarDecl* entry) {
entry->name = decl->getNameStr().str();
entry->type = dispatcher_.fetchLabel(decl->getType());
entry->parent_pattern = dispatcher_.fetchOptionalLabel(decl->getParentPattern());
entry->parent_initializer = dispatcher_.fetchOptionalLabel(decl->getParentInitializer());
if (decl->hasAttachedPropertyWrapper()) {
entry->attached_property_wrapper_type =
dispatcher_.fetchOptionalLabel(decl->getPropertyWrapperBackingPropertyType());
void fillVarDecl(const swift::VarDecl& decl, codeql::VarDecl& entry) {
entry.name = decl.getNameStr().str();
entry.type = dispatcher_.fetchLabel(decl.getType());
entry.parent_pattern = dispatcher_.fetchOptionalLabel(decl.getParentPattern());
entry.parent_initializer = dispatcher_.fetchOptionalLabel(decl.getParentInitializer());
if (decl.hasAttachedPropertyWrapper()) {
entry.attached_property_wrapper_type =
dispatcher_.fetchOptionalLabel(decl.getPropertyWrapperBackingPropertyType());
}
fillAbstractStorageDecl(decl, entry);
}
void fillNominalTypeDecl(swift::NominalTypeDecl* decl, codeql::NominalTypeDecl* entry) {
entry->type = dispatcher_.fetchLabel(decl->getDeclaredType());
void fillNominalTypeDecl(const swift::NominalTypeDecl& decl, codeql::NominalTypeDecl& entry) {
entry.type = dispatcher_.fetchLabel(decl.getDeclaredType());
fillGenericContext(decl, entry);
fillIterableDeclContext(decl, entry);
fillTypeDecl(decl, entry);
}
void fillGenericContext(swift::GenericContext* decl, codeql::GenericContext* entry) {
if (auto params = decl->getGenericParams()) {
entry->generic_type_params = dispatcher_.fetchRepeatedLabels(*params);
void fillGenericContext(const swift::GenericContext& decl, codeql::GenericContext& entry) {
if (auto params = decl.getGenericParams()) {
entry.generic_type_params = dispatcher_.fetchRepeatedLabels(*params);
}
}
void fillValueDecl(swift::ValueDecl* decl, codeql::ValueDecl* entry) {
assert(decl->getInterfaceType() && "Expect ValueDecl to have InterfaceType");
entry->interface_type = dispatcher_.fetchLabel(decl->getInterfaceType());
void fillValueDecl(const swift::ValueDecl& decl, codeql::ValueDecl& entry) {
assert(decl.getInterfaceType() && "Expect ValueDecl to have InterfaceType");
entry.interface_type = dispatcher_.fetchLabel(decl.getInterfaceType());
}
void fillAbstractStorageDecl(swift::AbstractStorageDecl* decl,
codeql::AbstractStorageDecl* entry) {
entry->accessor_decls = dispatcher_.fetchRepeatedLabels(decl->getAllAccessors());
void fillAbstractStorageDecl(const swift::AbstractStorageDecl& decl,
codeql::AbstractStorageDecl& entry) {
entry.accessor_decls = dispatcher_.fetchRepeatedLabels(decl.getAllAccessors());
fillValueDecl(decl, entry);
}
};

Просмотреть файл

@ -20,35 +20,32 @@ class VisitorBase {
} // namespace detail
// we want to override the default swift visitor behaviour of chaining calls to immediate
// superclasses by default and instead provide our own TBD default (using the exact type)
// if we the implementation class has translate##CLASS##KIND (that uses generated C++ classes), we
// want to use that. We detect that by comparing the member function pointer to the one for a
// private undefined member function of the same name and signature in {Ast,Type}VisitorBase, which
// will be shadowed (and thus different) in case the implementation class has it.
#define DEFAULT(KIND, CLASS, PARENT) \
public: \
void visit##CLASS##KIND(swift::CLASS##KIND* e) { \
constexpr bool hasTranslateImplementation = \
(&Self::translate##CLASS##KIND != &CrtpSubclass::translate##CLASS##KIND); \
if constexpr (hasTranslateImplementation) { \
TrapClassOf<swift::CLASS##KIND> entry{}; \
static_cast<CrtpSubclass*>(this)->translate##CLASS##KIND(e, &entry); \
dispatcher_.emit(entry); \
} else { \
dispatcher_.emitUnknown(e); \
} \
} \
\
private: \
void translate##CLASS##KIND(swift::CLASS##KIND*, TrapClassOf<swift::CLASS##KIND>*);
// superclasses by default and instead provide our own TBD default (using the exact type).
// Moreover if the implementation class has translate##CLASS##KIND (that uses generated C++
// classes), we want to use that. We detect that by comparing the member function pointer to the one
// for a private undefined member function of the same name and signature in {Ast,Type}VisitorBase,
// which will be shadowed (and thus different) in case the implementation class has it.
#define DEFAULT(KIND, CLASS, PARENT) \
public: \
void visit##CLASS##KIND(swift::CLASS##KIND* e) { \
using TranslateResult = std::invoke_result_t<decltype(&CrtpSubclass::translate##CLASS##KIND), \
CrtpSubclass, swift::CLASS##KIND>; \
constexpr bool hasTranslateImplementation = !std::is_same_v<TranslateResult, void>; \
if constexpr (hasTranslateImplementation) { \
dispatcher_.emit(static_cast<CrtpSubclass*>(this)->translate##CLASS##KIND(*e)); \
} else { \
dispatcher_.emitUnknown(e); \
} \
} \
\
private: \
void translate##CLASS##KIND(const swift::CLASS##KIND&);
// base class for our AST visitors, getting a SwiftDispatcher member and default emission for
// unknown/TBD entities. Like `swift::ASTVisitor`, this uses CRTP (the Curiously Recurring Template
// Pattern)
template <typename CrtpSubclass>
class AstVisitorBase : public swift::ASTVisitor<CrtpSubclass>, protected detail::VisitorBase {
using Self = AstVisitorBase;
public:
using VisitorBase::VisitorBase;
@ -73,8 +70,6 @@ class AstVisitorBase : public swift::ASTVisitor<CrtpSubclass>, protected detail:
// Pattern)
template <typename CrtpSubclass>
class TypeVisitorBase : public swift::TypeVisitor<CrtpSubclass>, protected detail::VisitorBase {
using Self = TypeVisitorBase;
public:
using VisitorBase::VisitorBase;