mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Swift: pattern visitor
This transfers the current state of `PatternVisitor` from the proof-of-concept.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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()) }
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) }
|
||||
}
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) }
|
||||
}
|
||||
|
||||
@@ -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()) }
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
41
swift/ql/test/extractor-tests/patterns/all.expected
Normal file
41
swift/ql/test/extractor-tests/patterns/all.expected
Normal 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 |
|
||||
5
swift/ql/test/extractor-tests/patterns/all.ql
Normal file
5
swift/ql/test/extractor-tests/patterns/all.ql
Normal file
@@ -0,0 +1,5 @@
|
||||
import codeql.swift.elements
|
||||
|
||||
from Pattern p
|
||||
where exists(p.getLocation())
|
||||
select p
|
||||
52
swift/ql/test/extractor-tests/patterns/patterns.swift
Normal file
52
swift/ql/test/extractor-tests/patterns/patterns.swift
Normal 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"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user