Swift: add NamedPattern.getVarDecl()

This commit is contained in:
Nora Dimitrijević
2023-02-09 00:35:14 +01:00
parent feb8243d5f
commit 5419e65e01
8 changed files with 215 additions and 7 deletions

View File

@@ -222,19 +222,19 @@ predicate catchMatchingPattern(DoCatchStmt s, CaseStmt c, Pattern pattern) {
/** Holds if `sub` is a subpattern of `p`. */
private predicate isSubPattern(Pattern p, Pattern sub) {
sub = p.(BindingPattern).getResolveStep()
sub = p.(BindingPattern).getImmediateSubPattern()
or
sub = p.(EnumElementPattern).getSubPattern().getFullyUnresolved()
sub = p.(EnumElementPattern).getImmediateSubPattern()
or
sub = p.(IsPattern).getSubPattern().getFullyUnresolved()
sub = p.(IsPattern).getImmediateSubPattern()
or
sub = p.(OptionalSomePattern).getFullyUnresolved()
sub = p.(OptionalSomePattern).getImmediateSubPattern()
or
sub = p.(ParenPattern).getResolveStep()
sub = p.(ParenPattern).getImmediateSubPattern()
or
sub = p.(TuplePattern).getAnElement().getFullyUnresolved()
sub = p.(TuplePattern).getImmediateElement(_)
or
sub = p.(TypedPattern).getSubPattern().getFullyUnresolved()
sub = p.(TypedPattern).getImmediateSubPattern()
}
/** Gets the value of `e` if it is a constant value, disregarding conversions. */

View File

@@ -1,5 +1,40 @@
private import codeql.swift.generated.pattern.NamedPattern
private import codeql.swift.elements.pattern.BindingPattern
private import codeql.swift.elements.pattern.EnumElementPattern
private import codeql.swift.elements.pattern.IsPattern
private import codeql.swift.elements.pattern.OptionalSomePattern
private import codeql.swift.elements.pattern.ParenPattern
private import codeql.swift.elements.pattern.TuplePattern
private import codeql.swift.elements.pattern.TypedPattern
private import codeql.swift.elements.decl.VarDecl
private import codeql.swift.elements.stmt.LabeledConditionalStmt
private import codeql.swift.elements.stmt.ConditionElement
class NamedPattern extends Generated::NamedPattern {
/** Holds if this named pattern has a corresponding `VarDecl` */
predicate hasVarDecl() { exists(this.getVarDecl()) }
/** Gets the `VarDecl` bound by this named pattern, if any. */
VarDecl getVarDecl() {
isSubPattern*(result.getParentPattern().getFullyUnresolved(), this) and
result.getName() = this.getName()
}
override string toString() { result = this.getName() }
}
private predicate isSubPattern(Pattern p, Pattern sub) {
sub = p.(BindingPattern).getImmediateSubPattern()
or
sub = p.(EnumElementPattern).getImmediateSubPattern()
or
sub = p.(IsPattern).getImmediateSubPattern()
or
sub = p.(OptionalSomePattern).getImmediateSubPattern()
or
sub = p.(ParenPattern).getImmediateSubPattern()
or
sub = p.(TuplePattern).getImmediateElement(_)
or
sub = p.(TypedPattern).getImmediateSubPattern()
}

View File

@@ -39,3 +39,23 @@
| patterns.swift:46:9:46:9 | b |
| patterns.swift:49:10:49:10 | true |
| patterns.swift:50:10:50:10 | false |
| patterns.swift:55:9:55:9 | a |
| patterns.swift:55:16:55:16 | b |
| patterns.swift:55:23:55:23 | c |
| patterns.swift:55:23:55:26 | ... as ... |
| patterns.swift:57:8:57:20 | let ... |
| patterns.swift:57:8:57:20 | let ...? |
| patterns.swift:57:12:57:20 | (...) |
| patterns.swift:57:13:57:13 | a |
| patterns.swift:57:16:57:16 | b |
| patterns.swift:57:19:57:19 | c |
| patterns.swift:58:13:58:29 | (...) |
| patterns.swift:58:14:58:14 | =~ ... |
| patterns.swift:58:17:58:21 | let ... |
| patterns.swift:58:21:58:21 | b |
| patterns.swift:58:24:58:28 | let ... |
| patterns.swift:58:28:58:28 | c |
| patterns.swift:61:14:61:14 | =~ ... |
| patterns.swift:62:14:62:18 | let ... |
| patterns.swift:62:18:62:18 | c |
| patterns.swift:63:9:63:9 | _ |

View File

@@ -0,0 +1,27 @@
bound
| patterns.swift:2:9:2:9 | an_int |
| patterns.swift:3:9:3:9 | a_string |
| patterns.swift:4:10:4:10 | x |
| patterns.swift:4:13:4:13 | y |
| patterns.swift:4:16:4:16 | z |
| patterns.swift:10:9:10:9 | point |
| patterns.swift:12:15:12:15 | xx |
| patterns.swift:12:19:12:19 | yy |
| patterns.swift:24:9:24:9 | v |
| patterns.swift:28:19:28:19 | i |
| patterns.swift:28:22:28:22 | s |
| patterns.swift:31:9:31:9 | w |
| patterns.swift:34:14:34:14 | n |
| patterns.swift:38:9:38:9 | a |
| patterns.swift:42:14:42:14 | x |
| patterns.swift:46:9:46:9 | b |
| patterns.swift:55:9:55:9 | a |
| patterns.swift:55:16:55:16 | b |
| patterns.swift:55:23:55:23 | c |
| patterns.swift:57:13:57:13 | a |
| patterns.swift:57:19:57:19 | c |
| patterns.swift:58:21:58:21 | b |
| patterns.swift:62:18:62:18 | c |
unbound
| patterns.swift:57:16:57:16 | b |
| patterns.swift:58:28:58:28 | c |

View File

@@ -0,0 +1,11 @@
import swift
query predicate bound(NamedPattern p) {
p.getFile().getBaseName() = "patterns.swift" and
p.hasVarDecl()
}
query predicate unbound(NamedPattern p) {
p.getFile().getBaseName() = "patterns.swift" and
not p.hasVarDecl()
}

View File

@@ -50,3 +50,16 @@ func switch_patterns() {
case false: "false"
}
}
func bound_and_unbound() {
let a = 1, b = 2, c: Int = 3
if let (a, b, c) = Optional.some((a, b, c)) { _ = (a, c) }
if case (a, let b, let c) = (a, b, c) { _ = (b) }
switch a {
case c: "equals c"
case let c: "binds c"
default: "default"
}
}

View File

@@ -5509,6 +5509,95 @@ patterns.swift:
# 34| Type = Int
# 42| [ConcreteVarDecl] x
# 42| Type = String
# 54| [ConcreteFuncDecl] bound_and_unbound()
# 54| InterfaceType = () -> ()
# 54| getBody(): [BraceStmt] { ... }
# 55| getElement(0): [PatternBindingDecl] var ... = ...
# 55| getInit(0): [IntegerLiteralExpr] 1
# 55| getInit(1): [IntegerLiteralExpr] 2
# 55| getInit(2): [IntegerLiteralExpr] 3
# 55| getPattern(0): [NamedPattern] a
# 55| getPattern(1): [NamedPattern] b
# 55| getPattern(2): [TypedPattern] ... as ...
# 55| getSubPattern(): [NamedPattern] c
# 55| getTypeRepr(): [TypeRepr] Int
# 55| getElement(1): [ConcreteVarDecl] a
# 55| Type = Int
# 55| getElement(2): [ConcreteVarDecl] b
# 55| Type = Int
# 55| getElement(3): [ConcreteVarDecl] c
# 55| Type = Int
# 57| getElement(4): [IfStmt] if ... then { ... }
# 57| getCondition(): [StmtCondition] StmtCondition
# 57| getElement(0): [ConditionElement] let ...? = ...
# 57| getPattern(): [OptionalSomePattern] let ...?
# 57| getSubPattern(): [TuplePattern] (...)
# 57| getElement(0): [NamedPattern] a
# 57| getElement(1): [NamedPattern] b
# 57| getElement(2): [NamedPattern] c
# 57| getSubPattern().getFullyUnresolved(): [BindingPattern] let ...
# 57| getInitializer(): [CallExpr] call to ...
# 57| getFunction(): [MethodLookupExpr] .some
# 57| getBase(): [TypeExpr] Optional<(Int, Int, Int)>.Type
# 57| getTypeRepr(): [TypeRepr] Optional<(Int, Int, Int)>
# 57| getMethodRef(): [DeclRefExpr] some
# 57| getArgument(0): [Argument] : (...)
# 57| getExpr(): [TupleExpr] (...)
# 57| getElement(0): [DeclRefExpr] a
# 57| getElement(1): [DeclRefExpr] b
# 57| getElement(2): [DeclRefExpr] c
# 57| getThen(): [BraceStmt] { ... }
# 57| getElement(0): [AssignExpr] ... = ...
# 57| getDest(): [DiscardAssignmentExpr] _
# 57| getSource(): [TupleExpr] (...)
# 57| getElement(0): [DeclRefExpr] a
# 57| getElement(1): [DeclRefExpr] c
# 58| getElement(5): [IfStmt] if ... then { ... }
# 58| getCondition(): [StmtCondition] StmtCondition
# 58| getElement(0): [ConditionElement] (...) = ...
# 58| getPattern(): [TuplePattern] (...)
# 58| getElement(0): [ExprPattern] =~ ...
# 58| getSubExpr(): [DeclRefExpr] a
# 58| getElement(1): [NamedPattern] b
# 58| getElement(1).getFullyUnresolved(): [BindingPattern] let ...
# 58| getElement(2): [NamedPattern] c
# 58| getElement(2).getFullyUnresolved(): [BindingPattern] let ...
# 58| getInitializer(): [TupleExpr] (...)
# 58| getElement(0): [DeclRefExpr] a
# 58| getElement(1): [DeclRefExpr] b
# 58| getElement(2): [DeclRefExpr] c
# 58| getThen(): [BraceStmt] { ... }
# 58| getElement(0): [AssignExpr] ... = ...
# 58| getDest(): [DiscardAssignmentExpr] _
# 58| getSource(): [DeclRefExpr] b
# 58| getSource().getFullyConverted(): [ParenExpr] (...)
# 60| getElement(6): [SwitchStmt] switch a { ... }
# 60| getExpr(): [DeclRefExpr] a
# 61| getCase(0): [CaseStmt] case ...
# 61| getBody(): [BraceStmt] { ... }
# 61| getElement(0): [StringLiteralExpr] equals c
# 61| getLabel(0): [CaseLabelItem] =~ ...
# 61| getPattern(): [ExprPattern] =~ ...
# 61| getSubExpr(): [DeclRefExpr] c
# 62| getCase(1): [CaseStmt] case ...
# 62| getBody(): [BraceStmt] { ... }
# 62| getElement(0): [StringLiteralExpr] binds c
# 62| getLabel(0): [CaseLabelItem] c
# 62| getPattern(): [NamedPattern] c
# 62| getPattern().getFullyUnresolved(): [BindingPattern] let ...
# 63| getCase(2): [CaseStmt] case ...
# 63| getBody(): [BraceStmt] { ... }
# 63| getElement(0): [StringLiteralExpr] default
# 63| getLabel(0): [CaseLabelItem] _
# 63| getPattern(): [AnyPattern] _
# 57| [ConcreteVarDecl] a
# 57| Type = Int
# 57| [ConcreteVarDecl] c
# 57| Type = Int
# 58| [ConcreteVarDecl] b
# 58| Type = Int
# 62| [ConcreteVarDecl] c
# 62| Type = Int
statements.swift:
# 1| [ConcreteFuncDecl] loop()
# 1| InterfaceType = () -> ()

View File

@@ -50,3 +50,16 @@ func switch_patterns() {
case false: "false"
}
}
func bound_and_unbound() {
let a = 1, b = 2, c: Int = 3
if let (a, b, c) = Optional.some((a, b, c)) { _ = (a, c) }
if case (a, let b, let c) = (a, b, c) { _ = (b) }
switch a {
case c: "equals c"
case let c: "binds c"
default: "default"
}
}