mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Swift: extract IfConfigDecl
This also adds `UnresolvedDeclRefExpr` tests, as `IfConfigDecl` consistently introduces those.
This commit is contained in:
@@ -270,6 +270,16 @@ EnumCaseDecl:
|
||||
|
||||
IfConfigDecl:
|
||||
_extends: Decl
|
||||
_children:
|
||||
clauses: IfConfigClause*
|
||||
|
||||
IfConfigClause:
|
||||
_extends: Locatable
|
||||
_children:
|
||||
condition: Expr?
|
||||
elements: AstNode*
|
||||
is_active: predicate
|
||||
_dir: decl
|
||||
|
||||
ImportDecl:
|
||||
_extends: Decl
|
||||
@@ -545,7 +555,6 @@ TypeExpr:
|
||||
UnresolvedDeclRefExpr:
|
||||
_extends: Expr
|
||||
name: string?
|
||||
_pragma: qltest_skip # we should really never extract these
|
||||
|
||||
UnresolvedDotExpr:
|
||||
_extends: Expr
|
||||
|
||||
@@ -78,7 +78,7 @@ class SwiftDispatcher {
|
||||
waitingForNewLabel = e;
|
||||
visit(e);
|
||||
if (auto l = store.get(e)) {
|
||||
if constexpr (!std::is_base_of_v<swift::TypeBase, E>) {
|
||||
if constexpr (std::is_base_of_v<LocatableTag, TrapTagOf<E>>) {
|
||||
attachLocation(e, *l);
|
||||
}
|
||||
return *l;
|
||||
@@ -95,6 +95,10 @@ class SwiftDispatcher {
|
||||
return fetchLabelFromUnion<AstNodeTag>(node);
|
||||
}
|
||||
|
||||
TrapLabel<IfConfigClauseTag> fetchLabel(const swift::IfConfigClause& clause) {
|
||||
return fetchLabel(&clause);
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -143,6 +147,15 @@ class SwiftDispatcher {
|
||||
attachLocation(locatable->getStartLoc(), locatable->getEndLoc(), locatableLabel);
|
||||
}
|
||||
|
||||
void attachLocation(const swift::IfConfigClause* clause, TrapLabel<LocatableTag> locatableLabel) {
|
||||
attachLocation(clause->Loc, clause->Loc, locatableLabel);
|
||||
}
|
||||
|
||||
// Emits a Location TRAP entry and attaches it to a `Locatable` trap label for a given `SourceLoc`
|
||||
void attachLocation(swift::SourceLoc loc, TrapLabel<LocatableTag> locatableLabel) {
|
||||
attachLocation(loc, loc, locatableLabel);
|
||||
}
|
||||
|
||||
// Emits a Location TRAP entry for a list of swift entities and attaches it to a `Locatable` trap
|
||||
// label
|
||||
template <typename Locatable>
|
||||
@@ -217,7 +230,8 @@ class SwiftDispatcher {
|
||||
swift::Expr,
|
||||
swift::Pattern,
|
||||
swift::TypeRepr,
|
||||
swift::TypeBase>;
|
||||
swift::TypeBase,
|
||||
swift::IfConfigClause>;
|
||||
|
||||
void attachLocation(swift::SourceLoc start,
|
||||
swift::SourceLoc end,
|
||||
@@ -274,6 +288,7 @@ class SwiftDispatcher {
|
||||
// TODO: The following methods are supposed to redirect TRAP emission to correpsonding visitors,
|
||||
// which are to be introduced in follow-up PRs
|
||||
virtual void visit(swift::Decl* decl) = 0;
|
||||
virtual void visit(const swift::IfConfigClause* clause) = 0;
|
||||
virtual void visit(swift::Stmt* stmt) = 0;
|
||||
virtual void visit(swift::StmtCondition* cond) = 0;
|
||||
virtual void visit(swift::CaseLabelItem* item) = 0;
|
||||
|
||||
@@ -47,6 +47,7 @@ MAP_TAG(Expr);
|
||||
#include <swift/AST/ExprNodes.def>
|
||||
|
||||
MAP_TAG(Decl);
|
||||
MAP_TAG(IfConfigClause);
|
||||
#define ABSTRACT_DECL(CLASS, PARENT) MAP_SUBTAG(CLASS##Decl, PARENT)
|
||||
#define DECL(CLASS, PARENT) ABSTRACT_DECL(CLASS, PARENT)
|
||||
#include <swift/AST/DeclNodes.def>
|
||||
|
||||
@@ -358,4 +358,18 @@ void DeclVisitor::fillAbstractStorageDecl(const swift::AbstractStorageDecl& decl
|
||||
fillValueDecl(decl, entry);
|
||||
}
|
||||
|
||||
codeql::IfConfigDecl DeclVisitor::translateIfConfigDecl(const swift::IfConfigDecl& decl) {
|
||||
auto entry = dispatcher_.createEntry(decl);
|
||||
entry.clauses = dispatcher_.fetchRepeatedLabels(decl.getClauses());
|
||||
return entry;
|
||||
}
|
||||
|
||||
codeql::IfConfigClause DeclVisitor::translateIfConfigClause(const swift::IfConfigClause& clause) {
|
||||
auto entry = dispatcher_.createEntry(clause);
|
||||
entry.condition = dispatcher_.fetchOptionalLabel(clause.Cond);
|
||||
entry.elements = dispatcher_.fetchRepeatedLabels(clause.Elements);
|
||||
entry.is_active = clause.isActive;
|
||||
return entry;
|
||||
}
|
||||
|
||||
} // namespace codeql
|
||||
|
||||
@@ -14,6 +14,11 @@ namespace codeql {
|
||||
class DeclVisitor : public AstVisitorBase<DeclVisitor> {
|
||||
public:
|
||||
using AstVisitorBase<DeclVisitor>::AstVisitorBase;
|
||||
using AstVisitorBase<DeclVisitor>::visit;
|
||||
|
||||
void visit(const swift::IfConfigClause* clause) {
|
||||
dispatcher_.emit(translateIfConfigClause(*clause));
|
||||
}
|
||||
|
||||
std::variant<codeql::ConcreteFuncDecl, codeql::ConcreteFuncDeclsTrap> translateFuncDecl(
|
||||
const swift::FuncDecl& decl);
|
||||
@@ -52,6 +57,8 @@ class DeclVisitor : public AstVisitorBase<DeclVisitor> {
|
||||
codeql::ExtensionDecl translateExtensionDecl(const swift::ExtensionDecl& decl);
|
||||
codeql::ImportDecl translateImportDecl(const swift::ImportDecl& decl);
|
||||
std::optional<codeql::ModuleDecl> translateModuleDecl(const swift::ModuleDecl& decl);
|
||||
codeql::IfConfigDecl translateIfConfigDecl(const swift::IfConfigDecl& decl);
|
||||
codeql::IfConfigClause translateIfConfigClause(const swift::IfConfigClause& clause);
|
||||
|
||||
private:
|
||||
std::string mangledName(const swift::ValueDecl& decl);
|
||||
|
||||
@@ -21,6 +21,7 @@ class SwiftVisitor : private SwiftDispatcher {
|
||||
|
||||
private:
|
||||
void visit(swift::Decl* decl) override { declVisitor.visit(decl); }
|
||||
void visit(const swift::IfConfigClause* clause) override { declVisitor.visit(clause); }
|
||||
void visit(swift::Stmt* stmt) override { stmtVisitor.visit(stmt); }
|
||||
void visit(swift::StmtCondition* cond) override { stmtVisitor.visitStmtCondition(cond); }
|
||||
void visit(swift::CaseLabelItem* item) override { stmtVisitor.visitCaseLabelItem(item); }
|
||||
|
||||
@@ -24,6 +24,7 @@ import codeql.swift.elements.decl.FuncDecl
|
||||
import codeql.swift.elements.decl.GenericContext
|
||||
import codeql.swift.elements.decl.GenericTypeDecl
|
||||
import codeql.swift.elements.decl.GenericTypeParamDecl
|
||||
import codeql.swift.elements.decl.IfConfigClause
|
||||
import codeql.swift.elements.decl.IfConfigDecl
|
||||
import codeql.swift.elements.decl.ImportDecl
|
||||
import codeql.swift.elements.decl.InfixOperatorDecl
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
|
||||
private import codeql.swift.generated.decl.IfConfigClause
|
||||
|
||||
class IfConfigClause extends IfConfigClauseBase { }
|
||||
@@ -1,4 +1,9 @@
|
||||
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
|
||||
private import codeql.swift.generated.expr.UnresolvedDeclRefExpr
|
||||
|
||||
class UnresolvedDeclRefExpr extends UnresolvedDeclRefExprBase { }
|
||||
class UnresolvedDeclRefExpr extends UnresolvedDeclRefExprBase {
|
||||
override string toString() {
|
||||
result = getName() + " (unresolved)"
|
||||
or
|
||||
not hasName() and result = "(unresolved)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@ Element getAnImmediateChild(Element e) {
|
||||
or
|
||||
enum_element_decl_params(e, _, x)
|
||||
or
|
||||
if_config_clause_conditions(e, x)
|
||||
or
|
||||
if_config_clause_elements(e, _, x)
|
||||
or
|
||||
if_config_decl_clauses(e, _, x)
|
||||
or
|
||||
pattern_binding_decl_inits(e, _, x)
|
||||
or
|
||||
pattern_binding_decl_patterns(e, _, x)
|
||||
|
||||
30
swift/ql/lib/codeql/swift/generated/decl/IfConfigClause.qll
Normal file
30
swift/ql/lib/codeql/swift/generated/decl/IfConfigClause.qll
Normal file
@@ -0,0 +1,30 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements.AstNode
|
||||
import codeql.swift.elements.expr.Expr
|
||||
import codeql.swift.elements.Locatable
|
||||
|
||||
class IfConfigClauseBase extends @if_config_clause, Locatable {
|
||||
override string getAPrimaryQlClass() { result = "IfConfigClause" }
|
||||
|
||||
Expr getCondition() {
|
||||
exists(Expr x |
|
||||
if_config_clause_conditions(this, x) and
|
||||
result = x.resolve()
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasCondition() { exists(getCondition()) }
|
||||
|
||||
AstNode getElement(int index) {
|
||||
exists(AstNode x |
|
||||
if_config_clause_elements(this, index, x) and
|
||||
result = x.resolve()
|
||||
)
|
||||
}
|
||||
|
||||
AstNode getAnElement() { result = getElement(_) }
|
||||
|
||||
int getNumberOfElements() { result = count(getAnElement()) }
|
||||
|
||||
predicate isActive() { if_config_clause_is_active(this) }
|
||||
}
|
||||
@@ -1,6 +1,18 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements.decl.Decl
|
||||
import codeql.swift.elements.decl.IfConfigClause
|
||||
|
||||
class IfConfigDeclBase extends @if_config_decl, Decl {
|
||||
override string getAPrimaryQlClass() { result = "IfConfigDecl" }
|
||||
|
||||
IfConfigClause getClause(int index) {
|
||||
exists(IfConfigClause x |
|
||||
if_config_decl_clauses(this, index, x) and
|
||||
result = x.resolve()
|
||||
)
|
||||
}
|
||||
|
||||
IfConfigClause getAClause() { result = getClause(_) }
|
||||
|
||||
int getNumberOfClauses() { result = count(getAClause()) }
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ files(
|
||||
@locatable =
|
||||
@ast_node
|
||||
| @condition_element
|
||||
| @if_config_clause
|
||||
;
|
||||
|
||||
#keyset[id]
|
||||
@@ -643,6 +644,35 @@ if_config_decls( //dir=decl
|
||||
unique int id: @if_config_decl
|
||||
);
|
||||
|
||||
#keyset[id, index]
|
||||
if_config_decl_clauses( //dir=decl
|
||||
int id: @if_config_decl ref,
|
||||
int index: int ref,
|
||||
int clause: @if_config_clause ref
|
||||
);
|
||||
|
||||
if_config_clauses( //dir=decl
|
||||
unique int id: @if_config_clause
|
||||
);
|
||||
|
||||
#keyset[id]
|
||||
if_config_clause_conditions( //dir=decl
|
||||
int id: @if_config_clause ref,
|
||||
int condition: @expr ref
|
||||
);
|
||||
|
||||
#keyset[id, index]
|
||||
if_config_clause_elements( //dir=decl
|
||||
int id: @if_config_clause ref,
|
||||
int index: int ref,
|
||||
int element: @ast_node ref
|
||||
);
|
||||
|
||||
#keyset[id]
|
||||
if_config_clause_is_active( //dir=decl
|
||||
int id: @if_config_clause ref
|
||||
);
|
||||
|
||||
import_decls( //dir=decl
|
||||
unique int id: @import_decl,
|
||||
int module: @module_decl ref
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
| if_config.swift:1:1:1:1 | IfConfigClause | isActive: | no |
|
||||
| if_config.swift:4:1:4:1 | IfConfigClause | isActive: | no |
|
||||
| if_config.swift:7:1:7:1 | IfConfigClause | isActive: | yes |
|
||||
| if_config_active.swift:3:1:3:1 | IfConfigClause | isActive: | yes |
|
||||
| if_config_active.swift:6:1:6:1 | IfConfigClause | isActive: | no |
|
||||
| if_config_active.swift:9:1:9:1 | IfConfigClause | isActive: | no |
|
||||
@@ -0,0 +1,10 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from IfConfigClause x, string isActive
|
||||
where
|
||||
toBeTested(x) and
|
||||
not x.isUnknown() and
|
||||
if x.isActive() then isActive = "yes" else isActive = "no"
|
||||
select x, "isActive:", isActive
|
||||
@@ -0,0 +1,4 @@
|
||||
| if_config.swift:1:1:1:1 | IfConfigClause | if_config.swift:1:5:1:5 | FOO (unresolved) |
|
||||
| if_config.swift:4:1:4:1 | IfConfigClause | if_config.swift:4:9:4:19 | call to ... |
|
||||
| if_config_active.swift:3:1:3:1 | IfConfigClause | if_config_active.swift:3:5:3:5 | FOO (unresolved) |
|
||||
| if_config_active.swift:6:1:6:1 | IfConfigClause | if_config_active.swift:6:9:6:17 | call to ... |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from IfConfigClause x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, x.getCondition()
|
||||
@@ -0,0 +1,18 @@
|
||||
| if_config.swift:1:1:1:1 | IfConfigClause | 0 | if_config.swift:2:1:2:16 | { ... } |
|
||||
| if_config.swift:1:1:1:1 | IfConfigClause | 1 | if_config.swift:2:5:2:5 | foo |
|
||||
| if_config.swift:1:1:1:1 | IfConfigClause | 2 | if_config.swift:3:1:3:12 | { ... } |
|
||||
| if_config.swift:4:1:4:1 | IfConfigClause | 0 | if_config.swift:5:1:5:16 | { ... } |
|
||||
| if_config.swift:4:1:4:1 | IfConfigClause | 1 | if_config.swift:5:5:5:5 | bar |
|
||||
| if_config.swift:4:1:4:1 | IfConfigClause | 2 | if_config.swift:6:1:6:12 | { ... } |
|
||||
| if_config.swift:7:1:7:1 | IfConfigClause | 0 | if_config.swift:8:1:8:16 | { ... } |
|
||||
| if_config.swift:7:1:7:1 | IfConfigClause | 1 | if_config.swift:8:5:8:5 | baz |
|
||||
| if_config.swift:7:1:7:1 | IfConfigClause | 2 | if_config.swift:9:1:9:12 | { ... } |
|
||||
| if_config_active.swift:3:1:3:1 | IfConfigClause | 0 | if_config_active.swift:4:1:4:16 | { ... } |
|
||||
| if_config_active.swift:3:1:3:1 | IfConfigClause | 1 | if_config_active.swift:4:5:4:5 | foo |
|
||||
| if_config_active.swift:3:1:3:1 | IfConfigClause | 2 | if_config_active.swift:5:1:5:12 | { ... } |
|
||||
| if_config_active.swift:6:1:6:1 | IfConfigClause | 0 | if_config_active.swift:7:1:7:16 | { ... } |
|
||||
| if_config_active.swift:6:1:6:1 | IfConfigClause | 1 | if_config_active.swift:7:5:7:5 | bar |
|
||||
| if_config_active.swift:6:1:6:1 | IfConfigClause | 2 | if_config_active.swift:8:1:8:12 | { ... } |
|
||||
| if_config_active.swift:9:1:9:1 | IfConfigClause | 0 | if_config_active.swift:10:1:10:16 | { ... } |
|
||||
| if_config_active.swift:9:1:9:1 | IfConfigClause | 1 | if_config_active.swift:10:5:10:5 | baz |
|
||||
| if_config_active.swift:9:1:9:1 | IfConfigClause | 2 | if_config_active.swift:11:1:11:12 | { ... } |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from IfConfigClause x, int index
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, index, x.getElement(index)
|
||||
@@ -0,0 +1,10 @@
|
||||
#if FOO
|
||||
var foo: Int = 1
|
||||
print("foo")
|
||||
#elseif os(watchOS)
|
||||
var bar: Int = 2
|
||||
print("bar")
|
||||
#else
|
||||
var baz: Int = 3
|
||||
print("baz")
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
//codeql-extractor-options: -D FOO
|
||||
|
||||
#if FOO
|
||||
var foo: Int = 1
|
||||
print("foo")
|
||||
#elseif os(macOS)
|
||||
var bar: Int = 2
|
||||
print("bar")
|
||||
#else
|
||||
var baz: Int = 3
|
||||
print("baz")
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
| if_config.swift:1:1:10:1 | #if ... |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from IfConfigDecl x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x
|
||||
@@ -0,0 +1,3 @@
|
||||
| if_config.swift:1:1:10:1 | #if ... | 0 | if_config.swift:1:1:1:1 | IfConfigClause |
|
||||
| if_config.swift:1:1:10:1 | #if ... | 1 | if_config.swift:4:1:4:1 | IfConfigClause |
|
||||
| if_config.swift:1:1:10:1 | #if ... | 2 | if_config.swift:7:1:7:1 | IfConfigClause |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from IfConfigDecl x, int index
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, index, x.getClause(index)
|
||||
@@ -1,4 +0,0 @@
|
||||
// generated by codegen/codegen.py
|
||||
|
||||
After a swift source file is added in this directory and codegen/codegen.py is run again, test queries
|
||||
will appear and this file will be deleted
|
||||
@@ -0,0 +1,10 @@
|
||||
#if FOO
|
||||
var foo: Int = 1
|
||||
print("foo")
|
||||
#elseif BAR
|
||||
var bar: Int = 2
|
||||
print("bar")
|
||||
#else
|
||||
var baz: Int = 3
|
||||
print("baz")
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
| unresolved_decl_ref.swift:4:5:4:5 | FOO (unresolved) |
|
||||
| unresolved_decl_ref.swift:4:9:4:9 | && (unresolved) |
|
||||
| unresolved_decl_ref.swift:4:12:4:12 | os (unresolved) |
|
||||
| unresolved_decl_ref.swift:4:15:4:15 | Windows (unresolved) |
|
||||
| unresolved_decl_ref.swift:5:1:5:1 | print (unresolved) |
|
||||
| unresolved_decl_ref.swift:6:9:6:9 | BAR (unresolved) |
|
||||
| unresolved_decl_ref.swift:6:13:6:13 | \|\| (unresolved) |
|
||||
| unresolved_decl_ref.swift:6:16:6:16 | arch (unresolved) |
|
||||
| unresolved_decl_ref.swift:6:21:6:21 | i386 (unresolved) |
|
||||
| unresolved_decl_ref.swift:9:1:9:1 | print (unresolved) |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from UnresolvedDeclRefExpr x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x
|
||||
@@ -0,0 +1,10 @@
|
||||
| unresolved_decl_ref.swift:4:5:4:5 | FOO (unresolved) | FOO |
|
||||
| unresolved_decl_ref.swift:4:9:4:9 | && (unresolved) | && |
|
||||
| unresolved_decl_ref.swift:4:12:4:12 | os (unresolved) | os |
|
||||
| unresolved_decl_ref.swift:4:15:4:15 | Windows (unresolved) | Windows |
|
||||
| unresolved_decl_ref.swift:5:1:5:1 | print (unresolved) | print |
|
||||
| unresolved_decl_ref.swift:6:9:6:9 | BAR (unresolved) | BAR |
|
||||
| unresolved_decl_ref.swift:6:13:6:13 | \|\| (unresolved) | \|\| |
|
||||
| unresolved_decl_ref.swift:6:16:6:16 | arch (unresolved) | arch |
|
||||
| unresolved_decl_ref.swift:6:21:6:21 | i386 (unresolved) | i386 |
|
||||
| unresolved_decl_ref.swift:9:1:9:1 | print (unresolved) | print |
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from UnresolvedDeclRefExpr x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, x.getName()
|
||||
@@ -0,0 +1,7 @@
|
||||
// generated by codegen/codegen.py
|
||||
import codeql.swift.elements
|
||||
import TestUtils
|
||||
|
||||
from UnresolvedDeclRefExpr x
|
||||
where toBeTested(x) and not x.isUnknown()
|
||||
select x, x.getType()
|
||||
@@ -0,0 +1,10 @@
|
||||
//codeql-extractor-options: -D BAR
|
||||
|
||||
// conditions and inactive branches in conditional compilation blocks are not resolved
|
||||
#if FOO && os(Windows)
|
||||
print(1)
|
||||
#elseif BAR || arch(i386)
|
||||
print(2)
|
||||
#else
|
||||
print(3)
|
||||
#endif
|
||||
Reference in New Issue
Block a user