Swift: pattern visitor

This transfers the current state of `PatternVisitor` from the
proof-of-concept.
This commit is contained in:
Paolo Tranquilli
2022-05-17 14:57:03 +02:00
parent 19506dae74
commit 3f45b73d62
16 changed files with 341 additions and 22 deletions

View File

@@ -491,46 +491,46 @@ AnyPattern:
BindingPattern:
_extends: Pattern
# sub_pattern: Pattern
sub_pattern: Pattern
BoolPattern:
_extends: Pattern
# value: boolean
value: boolean
EnumElementPattern:
_extends: Pattern
# element: EnumElementDecl
# sub_pattern: Pattern?
element: EnumElementDecl
sub_pattern: Pattern?
ExprPattern:
_extends: Pattern
# sub_expr: Expr
sub_expr: Expr
IsPattern:
_extends: Pattern
# cast_type_repr: TypeRepr?
# sub_pattern: Pattern?
cast_type_repr: TypeRepr?
sub_pattern: Pattern?
NamedPattern:
_extends: Pattern
# name: string
name: string
OptionalSomePattern:
_extends: Pattern
# sub_pattern: Pattern
sub_pattern: Pattern
ParenPattern:
_extends: Pattern
# sub_pattern: Pattern
sub_pattern: Pattern
TuplePattern:
_extends: Pattern
# elements: Pattern*
elements: Pattern*
TypedPattern:
_extends: Pattern
# sub_pattern: Pattern
# type_repr: TypeRepr?
sub_pattern: Pattern
type_repr: TypeRepr?
BraceStmt:
_extends: Stmt

View File

@@ -7,6 +7,91 @@ namespace codeql {
class PatternVisitor : public AstVisitorBase<PatternVisitor> {
public:
using AstVisitorBase<PatternVisitor>::AstVisitorBase;
};
void visitNamedPattern(swift::NamedPattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
// TODO: in some (but not all) cases, this seems to introduce a duplicate entry
// for example the vars listed in a case stmt have a different pointer than then ones in
// patterns.
// assert(pattern->getDecl() && "expect NamedPattern to have Decl");
// dispatcher_.emit(NamedPatternsTrap{label, pattern->getNameStr().str(),
// dispatcher_.fetchLabel(pattern->getDecl())});
dispatcher_.emit(NamedPatternsTrap{label, pattern->getNameStr().str()});
}
void visitTypedPattern(swift::TypedPattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
assert(pattern->getSubPattern() && "expect TypedPattern to have a SubPattern");
dispatcher_.emit(TypedPatternsTrap{label, dispatcher_.fetchLabel(pattern->getSubPattern())});
if (auto typeRepr = pattern->getTypeRepr()) {
dispatcher_.emit(
TypedPatternTypeReprsTrap{label, dispatcher_.fetchLabel(pattern->getTypeRepr())});
}
}
void visitTuplePattern(swift::TuplePattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
dispatcher_.emit(TuplePatternsTrap{label});
auto i = 0u;
for (auto p : pattern->getElements()) {
dispatcher_.emit(
TuplePatternElementsTrap{label, i++, dispatcher_.fetchLabel(p.getPattern())});
}
}
void visitAnyPattern(swift::AnyPattern* pattern) {
dispatcher_.emit(AnyPatternsTrap{dispatcher_.assignNewLabel(pattern)});
}
void visitBindingPattern(swift::BindingPattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
assert(pattern->getSubPattern() && "expect BindingPattern to have a SubPattern");
dispatcher_.emit(BindingPatternsTrap{label, dispatcher_.fetchLabel(pattern->getSubPattern())});
}
void visitEnumElementPattern(swift::EnumElementPattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
dispatcher_.emit(
EnumElementPatternsTrap{label, dispatcher_.fetchLabel(pattern->getElementDecl())});
if (auto subPattern = pattern->getSubPattern()) {
dispatcher_.emit(EnumElementPatternSubPatternsTrap{
label, dispatcher_.fetchLabel(pattern->getSubPattern())});
}
}
void visitOptionalSomePattern(swift::OptionalSomePattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
assert(pattern->getSubPattern() && "expect BindingPattern to have a SubPattern");
dispatcher_.emit(
OptionalSomePatternsTrap{label, dispatcher_.fetchLabel(pattern->getSubPattern())});
}
void visitIsPattern(swift::IsPattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
dispatcher_.emit(IsPatternsTrap{label});
if (auto typeRepr = pattern->getCastTypeRepr()) {
dispatcher_.emit(IsPatternCastTypeReprsTrap{label, dispatcher_.fetchLabel(typeRepr)});
}
if (auto subPattern = pattern->getSubPattern()) {
dispatcher_.emit(IsPatternSubPatternsTrap{label, dispatcher_.fetchLabel(subPattern)});
}
}
void visitExprPattern(swift::ExprPattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
assert(pattern->getSubExpr() && "expect ExprPattern to have SubExpr");
dispatcher_.emit(ExprPatternsTrap{label, dispatcher_.fetchLabel(pattern->getSubExpr())});
}
void visitParenPattern(swift::ParenPattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
assert(pattern->getSubPattern() && "expect ParenPattern to have SubPattern");
dispatcher_.emit(ParenPatternsTrap{label, dispatcher_.fetchLabel(pattern->getSubPattern())});
}
void visitBoolPattern(swift::BoolPattern* pattern) {
auto label = dispatcher_.assignNewLabel(pattern);
dispatcher_.emit(BoolPatternsTrap{label, pattern->getValue()});
}
};
} // namespace codeql

View File

@@ -3,4 +3,11 @@ import codeql.swift.elements.pattern.Pattern
class BindingPatternBase extends @binding_pattern, Pattern {
override string getAPrimaryQlClass() { result = "BindingPattern" }
Pattern getSubPattern() {
exists(Pattern x |
binding_patterns(this, x) and
result = x.resolve()
)
}
}

View File

@@ -3,4 +3,6 @@ import codeql.swift.elements.pattern.Pattern
class BoolPatternBase extends @bool_pattern, Pattern {
override string getAPrimaryQlClass() { result = "BoolPattern" }
boolean getValue() { bool_patterns(this, result) }
}

View File

@@ -1,6 +1,23 @@
// generated by codegen/codegen.py
import codeql.swift.elements.decl.EnumElementDecl
import codeql.swift.elements.pattern.Pattern
class EnumElementPatternBase extends @enum_element_pattern, Pattern {
override string getAPrimaryQlClass() { result = "EnumElementPattern" }
EnumElementDecl getElement() {
exists(EnumElementDecl x |
enum_element_patterns(this, x) and
result = x.resolve()
)
}
Pattern getSubPattern() {
exists(Pattern x |
enum_element_pattern_sub_patterns(this, x) and
result = x.resolve()
)
}
predicate hasSubPattern() { exists(getSubPattern()) }
}

View File

@@ -1,6 +1,14 @@
// generated by codegen/codegen.py
import codeql.swift.elements.expr.Expr
import codeql.swift.elements.pattern.Pattern
class ExprPatternBase extends @expr_pattern, Pattern {
override string getAPrimaryQlClass() { result = "ExprPattern" }
Expr getSubExpr() {
exists(Expr x |
expr_patterns(this, x) and
result = x.resolve()
)
}
}

View File

@@ -1,6 +1,25 @@
// generated by codegen/codegen.py
import codeql.swift.elements.pattern.Pattern
import codeql.swift.elements.typerepr.TypeRepr
class IsPatternBase extends @is_pattern, Pattern {
override string getAPrimaryQlClass() { result = "IsPattern" }
TypeRepr getCastTypeRepr() {
exists(TypeRepr x |
is_pattern_cast_type_reprs(this, x) and
result = x.resolve()
)
}
predicate hasCastTypeRepr() { exists(getCastTypeRepr()) }
Pattern getSubPattern() {
exists(Pattern x |
is_pattern_sub_patterns(this, x) and
result = x.resolve()
)
}
predicate hasSubPattern() { exists(getSubPattern()) }
}

View File

@@ -3,4 +3,6 @@ import codeql.swift.elements.pattern.Pattern
class NamedPatternBase extends @named_pattern, Pattern {
override string getAPrimaryQlClass() { result = "NamedPattern" }
string getName() { named_patterns(this, result) }
}

View File

@@ -3,4 +3,11 @@ import codeql.swift.elements.pattern.Pattern
class OptionalSomePatternBase extends @optional_some_pattern, Pattern {
override string getAPrimaryQlClass() { result = "OptionalSomePattern" }
Pattern getSubPattern() {
exists(Pattern x |
optional_some_patterns(this, x) and
result = x.resolve()
)
}
}

View File

@@ -3,4 +3,11 @@ import codeql.swift.elements.pattern.Pattern
class ParenPatternBase extends @paren_pattern, Pattern {
override string getAPrimaryQlClass() { result = "ParenPattern" }
Pattern getSubPattern() {
exists(Pattern x |
paren_patterns(this, x) and
result = x.resolve()
)
}
}

View File

@@ -3,4 +3,15 @@ import codeql.swift.elements.pattern.Pattern
class TuplePatternBase extends @tuple_pattern, Pattern {
override string getAPrimaryQlClass() { result = "TuplePattern" }
Pattern getElement(int index) {
exists(Pattern x |
tuple_pattern_elements(this, index, x) and
result = x.resolve()
)
}
Pattern getAnElement() { result = getElement(_) }
int getNumberOfElements() { result = count(getAnElement()) }
}

View File

@@ -1,6 +1,23 @@
// generated by codegen/codegen.py
import codeql.swift.elements.pattern.Pattern
import codeql.swift.elements.typerepr.TypeRepr
class TypedPatternBase extends @typed_pattern, Pattern {
override string getAPrimaryQlClass() { result = "TypedPattern" }
Pattern getSubPattern() {
exists(Pattern x |
typed_patterns(this, x) and
result = x.resolve()
)
}
TypeRepr getTypeRepr() {
exists(TypeRepr x |
typed_pattern_type_reprs(this, x) and
result = x.resolve()
)
}
predicate hasTypeRepr() { exists(getTypeRepr()) }
}

View File

@@ -836,43 +836,82 @@ any_patterns(
);
binding_patterns(
unique int id: @binding_pattern
unique int id: @binding_pattern,
int sub_pattern: @pattern ref
);
bool_patterns(
unique int id: @bool_pattern
unique int id: @bool_pattern,
boolean value: boolean ref
);
enum_element_patterns(
unique int id: @enum_element_pattern
unique int id: @enum_element_pattern,
int element: @enum_element_decl ref
);
#keyset[id]
enum_element_pattern_sub_patterns(
int id: @enum_element_pattern ref,
int sub_pattern: @pattern ref
);
expr_patterns(
unique int id: @expr_pattern
unique int id: @expr_pattern,
int sub_expr: @expr ref
);
is_patterns(
unique int id: @is_pattern
);
#keyset[id]
is_pattern_cast_type_reprs(
int id: @is_pattern ref,
int cast_type_repr: @type_repr ref
);
#keyset[id]
is_pattern_sub_patterns(
int id: @is_pattern ref,
int sub_pattern: @pattern ref
);
named_patterns(
unique int id: @named_pattern
unique int id: @named_pattern,
string name: string ref
);
optional_some_patterns(
unique int id: @optional_some_pattern
unique int id: @optional_some_pattern,
int sub_pattern: @pattern ref
);
paren_patterns(
unique int id: @paren_pattern
unique int id: @paren_pattern,
int sub_pattern: @pattern ref
);
tuple_patterns(
unique int id: @tuple_pattern
);
#keyset[id, index]
tuple_pattern_elements(
int id: @tuple_pattern ref,
int index: int ref,
int element: @pattern ref
);
typed_patterns(
unique int id: @typed_pattern
unique int id: @typed_pattern,
int sub_pattern: @pattern ref
);
#keyset[id]
typed_pattern_type_reprs(
int id: @typed_pattern ref,
int type_repr: @type_repr ref
);
brace_stmts(

View File

@@ -0,0 +1,41 @@
| patterns.swift:2:9:2:9 | NamedPattern |
| patterns.swift:3:9:3:9 | NamedPattern |
| patterns.swift:3:9:3:20 | TypedPattern |
| patterns.swift:4:9:4:17 | TuplePattern |
| patterns.swift:4:10:4:10 | NamedPattern |
| patterns.swift:4:13:4:13 | NamedPattern |
| patterns.swift:4:16:4:16 | NamedPattern |
| patterns.swift:5:9:5:9 | AnyPattern |
| patterns.swift:6:9:6:11 | ParenPattern |
| patterns.swift:6:10:6:10 | AnyPattern |
| patterns.swift:10:9:10:9 | NamedPattern |
| patterns.swift:12:10:12:21 | BindingPattern |
| patterns.swift:12:14:12:21 | TuplePattern |
| patterns.swift:12:15:12:15 | NamedPattern |
| patterns.swift:12:19:12:19 | NamedPattern |
| patterns.swift:16:10:16:14 | ExprPattern |
| patterns.swift:17:10:17:10 | AnyPattern |
| patterns.swift:24:9:24:9 | NamedPattern |
| patterns.swift:24:9:24:13 | TypedPattern |
| patterns.swift:27:10:27:11 | EnumElementPattern |
| patterns.swift:28:10:28:23 | BindingPattern |
| patterns.swift:28:14:28:23 | EnumElementPattern |
| patterns.swift:28:18:28:23 | TuplePattern |
| patterns.swift:28:19:28:19 | NamedPattern |
| patterns.swift:28:22:28:22 | NamedPattern |
| patterns.swift:31:9:31:9 | NamedPattern |
| patterns.swift:31:9:31:16 | TypedPattern |
| patterns.swift:34:10:34:15 | BindingPattern |
| patterns.swift:34:14:34:14 | NamedPattern |
| patterns.swift:34:14:34:15 | OptionalSomePattern |
| patterns.swift:35:10:35:10 | AnyPattern |
| patterns.swift:38:9:38:9 | NamedPattern |
| patterns.swift:38:9:38:13 | TypedPattern |
| patterns.swift:41:10:41:13 | IsPattern |
| patterns.swift:42:10:42:19 | BindingPattern |
| patterns.swift:42:14:42:14 | NamedPattern |
| patterns.swift:42:14:42:19 | IsPattern |
| patterns.swift:43:10:43:10 | AnyPattern |
| patterns.swift:46:9:46:9 | NamedPattern |
| patterns.swift:49:10:49:10 | BoolPattern |
| patterns.swift:50:10:50:10 | BoolPattern |

View File

@@ -0,0 +1,5 @@
import codeql.swift.elements
from Pattern p
where exists(p.getLocation())
select p

View File

@@ -0,0 +1,52 @@
func basic_patterns() {
var an_int = 42
var a_string: String = "here"
let (x, y, z) = (1, 2, 3)
let _ = "any"
let (_) = "paren"
}
func switch_patterns() {
let point = (1, 2)
switch point {
case let (xx, yy): "binding"
}
switch 3 {
case 1 + 2: "expr"
case _: ""
}
enum Foo {
case bar, baz(Int, String)
}
let v: Foo = .bar
switch v {
case .bar: "bar"
case let .baz(i, s): i
}
let w: Int? = nil
switch w {
case let n?: n
case _: "none"
}
let a: Any = "any"
switch a {
case is Int: "is pattern"
case let x as String: "as pattern"
case _: "other"
}
let b = true
switch b {
case true: "true"
case false: "false"
}
}