@@ -410,6 +410,34 @@ module LocalFlow {
410410 n instanceof SummaryNode or
411411 n instanceof ImplicitCapturedArgumentNode
412412 }
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+ }
413441}
414442
415443/**
@@ -719,14 +747,9 @@ private module Cached {
719747 cfn .getElement ( ) .( ObjectCreation ) .hasInitializer ( )
720748 } or
721749 TExprPostUpdateNode ( ControlFlow:: Nodes:: ExprNode cfn ) {
750+ cfn = LocalFlow:: getAPostUpdateNodeForArg ( _)
751+ or
722752 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
730753 fieldOrPropertyStore ( _, _, _, e , true )
731754 or
732755 arrayStore ( _, _, e , true )
@@ -1921,7 +1944,18 @@ private module PostUpdateNodes {
19211944
19221945 ExprPostUpdateNode ( ) { this = TExprPostUpdateNode ( cfn ) }
19231946
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+ }
19251959
19261960 override DataFlowCallable getEnclosingCallableImpl ( ) {
19271961 result .asCallable ( ) = cfn .getEnclosingCallable ( )
0 commit comments