@@ -177,6 +177,32 @@ predicate hasNodePath(ControlFlowReachabilityConfiguration conf, ExprNode n1, No
177
177
)
178
178
}
179
179
180
+ /**
181
+ * Gets a node that may execute last in `n`, and which, when it executes last,
182
+ * will be the value of `n`.
183
+ */
184
+ private ControlFlow:: Nodes:: ExprNode getALastEvalNode ( ControlFlow:: Nodes:: ExprNode cfn ) {
185
+ exists ( ConditionalExpr e | cfn .getExpr ( ) = e | result .getExpr ( ) = [ e .getThen ( ) , e .getElse ( ) ] )
186
+ }
187
+
188
+ private predicate relevantArgumentType ( ControlFlow:: Nodes:: ExprNode cfn ) {
189
+ exists ( Expr e | cfn .getExpr ( ) = e |
190
+ exists ( Type t | t = e .stripCasts ( ) .getType ( ) |
191
+ t instanceof RefType and
192
+ not t instanceof NullType
193
+ or
194
+ t = any ( TypeParameter tp | not tp .isValueType ( ) )
195
+ )
196
+ )
197
+ }
198
+
199
+ /** Gets a node for which to construct a post-update node for argument `arg`. */
200
+ private ControlFlow:: Nodes:: ExprNode getAPostUpdateNodeForArg ( Argument arg ) {
201
+ result = getALastEvalNode * ( arg .getAControlFlowNode ( ) ) and
202
+ relevantArgumentType ( result ) and
203
+ not exists ( getALastEvalNode ( result ) )
204
+ }
205
+
180
206
/** Provides predicates related to local data flow. */
181
207
module LocalFlow {
182
208
private class LocalExprStepConfiguration extends ControlFlowReachabilityConfiguration {
@@ -719,14 +745,9 @@ private module Cached {
719
745
cfn .getElement ( ) .( ObjectCreation ) .hasInitializer ( )
720
746
} or
721
747
TExprPostUpdateNode ( ControlFlow:: Nodes:: ExprNode cfn ) {
748
+ cfn = getAPostUpdateNodeForArg ( _)
749
+ or
722
750
exists ( Expr e | e = cfn .getExpr ( ) |
723
- exists ( Type t | t = e .( Argument ) .stripCasts ( ) .getType ( ) |
724
- t instanceof RefType and
725
- not t instanceof NullType
726
- or
727
- t = any ( TypeParameter tp | not tp .isValueType ( ) )
728
- )
729
- or
730
751
fieldOrPropertyStore ( _, _, _, e , true )
731
752
or
732
753
arrayStore ( _, _, e , true )
@@ -1921,7 +1942,18 @@ private module PostUpdateNodes {
1921
1942
1922
1943
ExprPostUpdateNode ( ) { this = TExprPostUpdateNode ( cfn ) }
1923
1944
1924
- override ExprNode getPreUpdateNode ( ) { cfn = result .getControlFlowNode ( ) }
1945
+ override ExprNode getPreUpdateNode ( ) {
1946
+ // For compund arguments, such as `m(if b then x else y)`, we want the leaf nodes
1947
+ // `[post] x` and `[post] y` to have two pre-update nodes: (1) the compund argument,
1948
+ // `if b then x else y`; and the (2) the underlying expressions; `x` and `y`,
1949
+ // respectively.
1950
+ //
1951
+ // This ensures that we get flow out of the call into both leafs (1), while still
1952
+ // maintaining the invariant that the underlying expression is a pre-update node (2).
1953
+ cfn = getAPostUpdateNodeForArg ( result .asExpr ( ) )
1954
+ or
1955
+ cfn = result .getControlFlowNode ( )
1956
+ }
1925
1957
1926
1958
override DataFlowCallable getEnclosingCallableImpl ( ) {
1927
1959
result .asCallable ( ) = cfn .getEnclosingCallable ( )
0 commit comments