@@ -41,7 +41,9 @@ module ConstCondInput implements ConstCond::InputSig<ControlFlow::BasicBlock> {
4141module ConstCondImpl = ConstCond:: Make< Location , Cfg , ConstCondInput > ;
4242
4343predicate nullCheck ( Expr e , boolean direct ) {
44- exists ( QualifiableExpr qe | qe .isConditional ( ) and qe .getQualifier ( ) = e and direct = true )
44+ exists ( QualifiableExpr qe | qe .isConditional ( ) and direct = true |
45+ qe .getQualifier ( ) = e or qe .( ExtensionMethodCall ) .getArgument ( 0 ) = e
46+ )
4547 or
4648 exists ( NullCoalescingOperation nce | nce .getLeftOperand ( ) = e and direct = true )
4749 or
@@ -108,72 +110,38 @@ class ConstantGuard extends ConstantCondition {
108110class ConstantBooleanCondition extends ConstantCondition {
109111 boolean b ;
110112
111- ConstantBooleanCondition ( ) { isConstantCondition ( this , b ) }
113+ ConstantBooleanCondition ( ) { isConstantComparison ( this , b ) }
112114
113115 override string getMessage ( ) { result = "Condition always evaluates to '" + b + "'." }
114-
115- override predicate isWhiteListed ( ) {
116- // E.g. `x ?? false`
117- this .( BoolLiteral ) = any ( NullCoalescingOperation nce ) .getRightOperand ( ) or
118- // No need to flag logical operations when the operands are constant
119- isConstantCondition ( this .( LogicalNotExpr ) .getOperand ( ) , _) or
120- this =
121- any ( LogicalAndExpr lae |
122- isConstantCondition ( lae .getAnOperand ( ) , false )
123- or
124- isConstantCondition ( lae .getLeftOperand ( ) , true ) and
125- isConstantCondition ( lae .getRightOperand ( ) , true )
126- ) or
127- this =
128- any ( LogicalOrExpr loe |
129- isConstantCondition ( loe .getAnOperand ( ) , true )
130- or
131- isConstantCondition ( loe .getLeftOperand ( ) , false ) and
132- isConstantCondition ( loe .getRightOperand ( ) , false )
133- )
134- }
135116}
136117
137- /** A constant condition in an `if` statement or a conditional expression. */
138- class ConstantIfCondition extends ConstantBooleanCondition {
139- ConstantIfCondition ( ) {
140- this = any ( IfStmt is ) .getCondition ( ) .getAChildExpr * ( ) or
141- this = any ( ConditionalExpr ce ) .getCondition ( ) .getAChildExpr * ( )
142- }
143-
144- override predicate isWhiteListed ( ) {
145- ConstantBooleanCondition .super .isWhiteListed ( )
146- or
147- // It is a common pattern to use a local constant/constant field to control
148- // whether code parts must be executed or not
149- this instanceof AssignableRead and
150- not this instanceof ParameterRead
151- }
152- }
153-
154- /** A constant loop condition. */
155- class ConstantLoopCondition extends ConstantBooleanCondition {
156- ConstantLoopCondition ( ) { this = any ( LoopStmt ls ) .getCondition ( ) }
157-
158- override predicate isWhiteListed ( ) {
159- // Clearly intentional infinite loops are allowed
160- this .( BoolLiteral ) .getBoolValue ( ) = true
161- }
118+ private Expr getQualifier ( QualifiableExpr e ) {
119+ // `e.getQualifier()` does not work for calls to extension methods
120+ result = e .getChildExpr ( - 1 )
162121}
163122
164123/** A constant nullness condition. */
165124class ConstantNullnessCondition extends ConstantCondition {
166125 boolean b ;
167126
168127 ConstantNullnessCondition ( ) {
169- forex ( ControlFlow:: Node cfn | cfn = this .getAControlFlowNode ( ) |
170- exists ( ControlFlow:: NullnessSuccessor t , ControlFlow:: Node s |
171- s = cfn .getASuccessorByType ( t )
172- |
173- b = t .getValue ( ) and
174- not s .isJoin ( )
175- ) and
176- strictcount ( ControlFlow:: SuccessorType t | exists ( cfn .getASuccessorByType ( t ) ) ) = 1
128+ nullCheck ( this , true ) and
129+ exists ( Expr stripped | stripped = this .( Expr ) .stripCasts ( ) |
130+ stripped .getType ( ) =
131+ any ( ValueType t |
132+ not t instanceof NullableType and
133+ // Extractor bug: the type of `x?.Length` is reported as `int`, but it should
134+ // be `int?`
135+ not getQualifier * ( stripped ) .( QualifiableExpr ) .isConditional ( )
136+ ) and
137+ b = false
138+ or
139+ stripped instanceof NullLiteral and
140+ b = true
141+ or
142+ stripped .hasValue ( ) and
143+ not stripped instanceof NullLiteral and
144+ b = false
177145 )
178146 }
179147
@@ -184,39 +152,6 @@ class ConstantNullnessCondition extends ConstantCondition {
184152 }
185153}
186154
187- /** A constant matching condition. */
188- class ConstantMatchingCondition extends ConstantCondition {
189- boolean b ;
190-
191- ConstantMatchingCondition ( ) {
192- this instanceof Expr and
193- forex ( ControlFlow:: Node cfn | cfn = this .getAControlFlowNode ( ) |
194- exists ( ControlFlow:: MatchingSuccessor t | exists ( cfn .getASuccessorByType ( t ) ) |
195- b = t .getValue ( )
196- ) and
197- strictcount ( ControlFlow:: SuccessorType t | exists ( cfn .getASuccessorByType ( t ) ) ) = 1
198- )
199- }
200-
201- override predicate isWhiteListed ( ) {
202- exists ( Switch se , Case c , int i |
203- c = se .getCase ( i ) and
204- c .getPattern ( ) = this .( DiscardExpr )
205- |
206- i > 0
207- or
208- i = 0 and
209- exists ( Expr cond | c .getCondition ( ) = cond and not isConstantCondition ( cond , true ) )
210- )
211- or
212- this = any ( PositionalPatternExpr ppe ) .getPattern ( _)
213- }
214-
215- override string getMessage ( ) {
216- if b = true then result = "Pattern always matches." else result = "Pattern never matches."
217- }
218- }
219-
220155from ConstantCondition c , string msg , Guards:: Guards:: Guard reason , string reasonMsg
221156where
222157 msg = c .getMessage ( ) and
0 commit comments