@@ -410,6 +410,34 @@ module LocalFlow {
410
410
n instanceof SummaryNode or
411
411
n instanceof ImplicitCapturedArgumentNode
412
412
}
413
+
414
+ /**
415
+ * Gets a node that may execute last in `n`, and which, when it executes last,
416
+ * will be the value of `n`.
417
+ */
418
+ private ControlFlow:: Nodes:: ExprNode getALastEvalNode ( ControlFlow:: Nodes:: ExprNode cfn ) {
419
+ exists ( Expr e | any ( LocalExprStepConfiguration x ) .hasExprPath ( _, result , e , cfn ) |
420
+ e instanceof ConditionalExpr or
421
+ e instanceof Cast or
422
+ e instanceof NullCoalescingExpr or
423
+ e instanceof SwitchExpr or
424
+ e instanceof SuppressNullableWarningExpr or
425
+ e instanceof AssignExpr
426
+ )
427
+ }
428
+
429
+ /** Gets a node for which to construct a post-update node for argument `arg`. */
430
+ ControlFlow:: Nodes:: ExprNode getAPostUpdateNodeForArg ( ControlFlow:: Nodes:: ExprNode arg ) {
431
+ arg .getExpr ( ) instanceof Argument and
432
+ result = getALastEvalNode * ( arg ) and
433
+ exists ( Expr e , Type t | result .getExpr ( ) = e and t = e .stripCasts ( ) .getType ( ) |
434
+ t instanceof RefType and
435
+ not t instanceof NullType
436
+ or
437
+ t = any ( TypeParameter tp | not tp .isValueType ( ) )
438
+ ) and
439
+ not exists ( getALastEvalNode ( result ) )
440
+ }
413
441
}
414
442
415
443
/**
@@ -719,14 +747,9 @@ private module Cached {
719
747
cfn .getElement ( ) .( ObjectCreation ) .hasInitializer ( )
720
748
} or
721
749
TExprPostUpdateNode ( ControlFlow:: Nodes:: ExprNode cfn ) {
750
+ cfn = LocalFlow:: getAPostUpdateNodeForArg ( _)
751
+ or
722
752
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
753
fieldOrPropertyStore ( _, _, _, e , true )
731
754
or
732
755
arrayStore ( _, _, e , true )
@@ -1921,7 +1944,18 @@ private module PostUpdateNodes {
1921
1944
1922
1945
ExprPostUpdateNode ( ) { this = TExprPostUpdateNode ( cfn ) }
1923
1946
1924
- override ExprNode getPreUpdateNode ( ) { cfn = result .getControlFlowNode ( ) }
1947
+ override ExprNode getPreUpdateNode ( ) {
1948
+ // For compund arguments, such as `m(b ? x : y)`, we want the leaf nodes
1949
+ // `[post] x` and `[post] y` to have two pre-update nodes: (1) the compund argument,
1950
+ // `if b then x else y`; and the (2) the underlying expressions; `x` and `y`,
1951
+ // respectively.
1952
+ //
1953
+ // This ensures that we get flow out of the call into both leafs (1), while still
1954
+ // maintaining the invariant that the underlying expression is a pre-update node (2).
1955
+ cfn = LocalFlow:: getAPostUpdateNodeForArg ( result .getControlFlowNode ( ) )
1956
+ or
1957
+ cfn = result .getControlFlowNode ( )
1958
+ }
1925
1959
1926
1960
override DataFlowCallable getEnclosingCallableImpl ( ) {
1927
1961
result .asCallable ( ) = cfn .getEnclosingCallable ( )
0 commit comments