6
6
7
7
private import swift
8
8
private import codeql.swift.controlflow.ControlFlowGraph
9
+ private import ControlFlowElements
9
10
private import ControlFlowGraphImpl
10
11
private import SuccessorTypes
11
12
@@ -41,8 +42,8 @@ private predicate completionIsValidForStmt(Stmt stmt, Completion c) {
41
42
42
43
/** A completion of a statement or an expression. */
43
44
abstract class Completion extends TCompletion {
44
- private predicate isValidForSpecific ( AstNode n ) {
45
- completionIsValidForStmt ( n , this )
45
+ private predicate isValidForSpecific ( ControlFlowElement n ) {
46
+ completionIsValidForStmt ( n . asAstNode ( ) , this )
46
47
or
47
48
mustHaveBooleanCompletion ( n ) and
48
49
(
@@ -52,22 +53,24 @@ abstract class Completion extends TCompletion {
52
53
this = TBooleanCompletion ( _)
53
54
)
54
55
or
55
- mustHaveMatchingCompletion ( n ) and
56
+ mustHaveMatchingCompletion ( n . asAstNode ( ) ) and
56
57
(
57
- exists ( boolean value | isMatchingConstant ( n , value ) | this = TMatchingCompletion ( value ) )
58
+ exists ( boolean value | isMatchingConstant ( n .asAstNode ( ) , value ) |
59
+ this = TMatchingCompletion ( value )
60
+ )
58
61
or
59
- not isMatchingConstant ( n , _) and
62
+ not isMatchingConstant ( n . asAstNode ( ) , _) and
60
63
this = TMatchingCompletion ( _)
61
64
)
62
65
or
63
- mustHaveThrowCompletion ( n , this )
66
+ mustHaveThrowCompletion ( n . asAstNode ( ) , this )
64
67
}
65
68
66
69
/** Holds if this completion is valid for node `n`. */
67
- predicate isValidFor ( AstNode n ) {
70
+ predicate isValidFor ( ControlFlowElement n ) {
68
71
this .isValidForSpecific ( n )
69
72
or
70
- mayHaveThrowCompletion ( n , this )
73
+ mayHaveThrowCompletion ( n . asAstNode ( ) , this )
71
74
or
72
75
not any ( Completion c ) .isValidForSpecific ( n ) and
73
76
this = TSimpleCompletion ( )
@@ -87,25 +90,35 @@ abstract class Completion extends TCompletion {
87
90
}
88
91
89
92
/** Holds if node `n` has the Boolean constant value `value`. */
90
- private predicate isBooleanConstant ( AstNode n , boolean value ) {
93
+ private predicate isBooleanConstant ( ControlFlowElement n , boolean value ) {
91
94
mustHaveBooleanCompletion ( n ) and
92
- value = n .( BooleanLiteralExpr ) .getValue ( )
95
+ value = n .asAstNode ( ) . ( BooleanLiteralExpr ) .getValue ( )
93
96
or
94
97
// Boolean consants hidden inside conversions are also
95
98
// constants that resolve to the same value.
96
- isBooleanConstant ( n .getResolveStep ( ) , value )
99
+ exists ( ControlFlowElement parent |
100
+ parent .asAstNode ( ) = n .asAstNode ( ) .getResolveStep ( ) and
101
+ isBooleanConstant ( parent , value )
102
+ )
97
103
}
98
104
99
105
/**
100
106
* Holds if a normal completion of `n` must be a Boolean completion.
101
107
*/
102
- private predicate mustHaveBooleanCompletion ( AstNode n ) { inBooleanContext ( n ) }
108
+ private predicate mustHaveBooleanCompletion ( ControlFlowElement n ) { inBooleanContext ( n ) }
103
109
104
110
/**
105
111
* Holds if `n` is used in a Boolean context. That is, the value
106
112
* that `n` evaluates to determines a true/false branch successor.
107
113
*/
108
- private predicate inBooleanContext ( AstNode n ) {
114
+ private predicate inBooleanContext ( ControlFlowElement n ) {
115
+ astInBooleanContext ( n .asAstNode ( ) ) or
116
+ astInBooleanContext ( n .( PropertyGetterElement ) .getRef ( ) ) or
117
+ astInBooleanContext ( n .( PropertySetterElement ) .getAssignExpr ( ) ) or
118
+ astInBooleanContext ( n .( PropertyObserverElement ) .getAssignExpr ( ) )
119
+ }
120
+
121
+ private predicate astInBooleanContext ( AstNode n ) {
109
122
n = any ( ConditionElement condElem ) .getFullyUnresolved ( )
110
123
or
111
124
n = any ( StmtCondition stmtCond ) .getFullyUnresolved ( )
@@ -115,30 +128,30 @@ private predicate inBooleanContext(AstNode n) {
115
128
exists ( LogicalAndExpr parent |
116
129
n = parent .getLeftOperand ( ) .getFullyConverted ( )
117
130
or
118
- inBooleanContext ( parent ) and
131
+ astInBooleanContext ( parent ) and
119
132
n = parent .getRightOperand ( ) .getFullyConverted ( )
120
133
)
121
134
or
122
135
exists ( LogicalOrExpr parent |
123
136
n = parent .getLeftOperand ( ) .getFullyConverted ( )
124
137
or
125
- inBooleanContext ( parent ) and
138
+ astInBooleanContext ( parent ) and
126
139
n = parent .getRightOperand ( ) .getFullyConverted ( )
127
140
)
128
141
or
129
- n = any ( NotExpr parent | inBooleanContext ( parent ) ) .getOperand ( ) .getFullyConverted ( )
142
+ n = any ( NotExpr parent | astInBooleanContext ( parent ) ) .getOperand ( ) .getFullyConverted ( )
130
143
or
131
144
exists ( IfExpr ifExpr |
132
145
ifExpr .getCondition ( ) .getFullyConverted ( ) = n
133
146
or
134
- inBooleanContext ( ifExpr ) and
147
+ astInBooleanContext ( ifExpr ) and
135
148
n = ifExpr .getBranch ( _) .getFullyConverted ( )
136
149
)
137
150
or
138
151
exists ( ForEachStmt foreach | n = foreach .getWhere ( ) .getFullyConverted ( ) )
139
152
or
140
153
exists ( Exprs:: Conversions:: ConversionOrIdentityTree parent |
141
- inBooleanContext ( parent ) and
154
+ astInBooleanContext ( parent . getAst ( ) ) and
142
155
parent .convertsFrom ( n )
143
156
)
144
157
}
@@ -477,3 +490,18 @@ class ThrowCompletion extends TThrowCompletion, Completion {
477
490
478
491
override string toString ( ) { result = "throw" }
479
492
}
493
+
494
+ /**
495
+ * Hold if `c` represents normal evaluation of a statement or an
496
+ * expression.
497
+ */
498
+ predicate completionIsNormal ( Completion c ) { c instanceof NormalCompletion }
499
+
500
+ /**
501
+ * Hold if `c` represents simple (normal) evaluation of a statement or an
502
+ * expression.
503
+ */
504
+ predicate completionIsSimple ( Completion c ) { c instanceof SimpleCompletion }
505
+
506
+ /** Holds if `c` is a valid completion for `e`. */
507
+ predicate completionIsValidFor ( Completion c , ControlFlowElement e ) { c .isValidFor ( e ) }
0 commit comments