66
77private import swift
88private import codeql.swift.controlflow.ControlFlowGraph
9+ private import ControlFlowElements
910private import ControlFlowGraphImpl
1011private import SuccessorTypes
1112
@@ -41,8 +42,8 @@ private predicate completionIsValidForStmt(Stmt stmt, Completion c) {
4142
4243/** A completion of a statement or an expression. */
4344abstract 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 )
4647 or
4748 mustHaveBooleanCompletion ( n ) and
4849 (
@@ -52,22 +53,24 @@ abstract class Completion extends TCompletion {
5253 this = TBooleanCompletion ( _)
5354 )
5455 or
55- mustHaveMatchingCompletion ( n ) and
56+ mustHaveMatchingCompletion ( n . asAstNode ( ) ) and
5657 (
57- exists ( boolean value | isMatchingConstant ( n , value ) | this = TMatchingCompletion ( value ) )
58+ exists ( boolean value | isMatchingConstant ( n .asAstNode ( ) , value ) |
59+ this = TMatchingCompletion ( value )
60+ )
5861 or
59- not isMatchingConstant ( n , _) and
62+ not isMatchingConstant ( n . asAstNode ( ) , _) and
6063 this = TMatchingCompletion ( _)
6164 )
6265 or
63- mustHaveThrowCompletion ( n , this )
66+ mustHaveThrowCompletion ( n . asAstNode ( ) , this )
6467 }
6568
6669 /** Holds if this completion is valid for node `n`. */
67- predicate isValidFor ( AstNode n ) {
70+ predicate isValidFor ( ControlFlowElement n ) {
6871 this .isValidForSpecific ( n )
6972 or
70- mayHaveThrowCompletion ( n , this )
73+ mayHaveThrowCompletion ( n . asAstNode ( ) , this )
7174 or
7275 not any ( Completion c ) .isValidForSpecific ( n ) and
7376 this = TSimpleCompletion ( )
@@ -87,25 +90,35 @@ abstract class Completion extends TCompletion {
8790}
8891
8992/** 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 ) {
9194 mustHaveBooleanCompletion ( n ) and
92- value = n .( BooleanLiteralExpr ) .getValue ( )
95+ value = n .asAstNode ( ) . ( BooleanLiteralExpr ) .getValue ( )
9396 or
9497 // Boolean consants hidden inside conversions are also
9598 // 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+ )
97103}
98104
99105/**
100106 * Holds if a normal completion of `n` must be a Boolean completion.
101107 */
102- private predicate mustHaveBooleanCompletion ( AstNode n ) { inBooleanContext ( n ) }
108+ private predicate mustHaveBooleanCompletion ( ControlFlowElement n ) { inBooleanContext ( n ) }
103109
104110/**
105111 * Holds if `n` is used in a Boolean context. That is, the value
106112 * that `n` evaluates to determines a true/false branch successor.
107113 */
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 ) {
109122 n = any ( ConditionElement condElem ) .getFullyUnresolved ( )
110123 or
111124 n = any ( StmtCondition stmtCond ) .getFullyUnresolved ( )
@@ -115,30 +128,30 @@ private predicate inBooleanContext(AstNode n) {
115128 exists ( LogicalAndExpr parent |
116129 n = parent .getLeftOperand ( ) .getFullyConverted ( )
117130 or
118- inBooleanContext ( parent ) and
131+ astInBooleanContext ( parent ) and
119132 n = parent .getRightOperand ( ) .getFullyConverted ( )
120133 )
121134 or
122135 exists ( LogicalOrExpr parent |
123136 n = parent .getLeftOperand ( ) .getFullyConverted ( )
124137 or
125- inBooleanContext ( parent ) and
138+ astInBooleanContext ( parent ) and
126139 n = parent .getRightOperand ( ) .getFullyConverted ( )
127140 )
128141 or
129- n = any ( NotExpr parent | inBooleanContext ( parent ) ) .getOperand ( ) .getFullyConverted ( )
142+ n = any ( NotExpr parent | astInBooleanContext ( parent ) ) .getOperand ( ) .getFullyConverted ( )
130143 or
131144 exists ( IfExpr ifExpr |
132145 ifExpr .getCondition ( ) .getFullyConverted ( ) = n
133146 or
134- inBooleanContext ( ifExpr ) and
147+ astInBooleanContext ( ifExpr ) and
135148 n = ifExpr .getBranch ( _) .getFullyConverted ( )
136149 )
137150 or
138151 exists ( ForEachStmt foreach | n = foreach .getWhere ( ) .getFullyConverted ( ) )
139152 or
140153 exists ( Exprs:: Conversions:: ConversionOrIdentityTree parent |
141- inBooleanContext ( parent ) and
154+ astInBooleanContext ( parent . getAst ( ) ) and
142155 parent .convertsFrom ( n )
143156 )
144157}
@@ -477,3 +490,18 @@ class ThrowCompletion extends TThrowCompletion, Completion {
477490
478491 override string toString ( ) { result = "throw" }
479492}
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