@@ -691,19 +691,22 @@ module LocalFlow {
691691 )
692692 }
693693
694- /** Gets a node for which to construct a post-update node for argument `arg`. */
695- ControlFlow:: Nodes:: ExprNode getAPostUpdateNodeForArg ( ControlFlow:: Nodes:: ExprNode arg ) {
696- arg .getExpr ( ) instanceof Argument and
697- result = getALastEvalNode * ( arg ) and
698- exists ( Expr e , Type t | result .getExpr ( ) = e and t = e .stripCasts ( ) .getType ( ) |
699- t instanceof RefType and
700- not t instanceof NullType
701- or
702- t = any ( TypeParameter tp | not tp .isValueType ( ) )
703- or
704- t .isRefLikeType ( )
705- ) and
706- not exists ( getALastEvalNode ( result ) )
694+ /**
695+ * Holds if a reverse local flow step should be added from the post-update node
696+ * for `e` to the post-update node for the result.
697+ *
698+ * This is needed to allow for side-effects on compound expressions to propagate
699+ * to sub components. For example, in
700+ *
701+ * ```csharp
702+ * m(b ? x : y)
703+ * ```
704+ *
705+ * we add a reverse flow step from `[post] b ? x : y` to `[post] x` and to
706+ * `[post] y`, in order for the side-effect of `m` to reach both `x` and `y`.
707+ */
708+ ControlFlow:: Nodes:: ExprNode getPostUpdateReverseStep ( ControlFlow:: Nodes:: ExprNode e ) {
709+ result = getALastEvalNode ( e )
707710 }
708711
709712 /**
@@ -763,6 +766,13 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
763766 VariableCapture:: valueStep ( nodeFrom , nodeTo )
764767 or
765768 nodeTo = nodeFrom .( LocalFunctionCreationNode ) .getAnAccess ( true )
769+ or
770+ nodeTo .( PostUpdateNode ) .getPreUpdateNode ( ) .( ExprNode ) .getControlFlowNode ( ) =
771+ LocalFlow:: getPostUpdateReverseStep ( nodeFrom
772+ .( PostUpdateNode )
773+ .getPreUpdateNode ( )
774+ .( ExprNode )
775+ .getControlFlowNode ( ) )
766776 ) and
767777 model = ""
768778 or
@@ -1106,7 +1116,22 @@ private module Cached {
11061116 cfn .getAstNode ( ) .( ObjectCreation ) .hasInitializer ( )
11071117 } or
11081118 TExprPostUpdateNode ( ControlFlow:: Nodes:: ExprNode cfn ) {
1109- cfn = LocalFlow:: getAPostUpdateNodeForArg ( _)
1119+ (
1120+ cfn .getExpr ( ) instanceof Argument
1121+ or
1122+ cfn =
1123+ LocalFlow:: getPostUpdateReverseStep ( any ( ControlFlow:: Nodes:: ExprNode e |
1124+ exists ( any ( SourcePostUpdateNode p ) .getPreUpdateNode ( ) .asExprAtNode ( e ) )
1125+ ) )
1126+ ) and
1127+ exists ( Expr e , Type t | cfn .getExpr ( ) = e and t = e .stripCasts ( ) .getType ( ) |
1128+ t instanceof RefType and
1129+ not t instanceof NullType
1130+ or
1131+ t = any ( TypeParameter tp | not tp .isValueType ( ) )
1132+ or
1133+ t .isRefLikeType ( )
1134+ )
11101135 or
11111136 exists ( Expr e | e = cfn .getExpr ( ) |
11121137 fieldOrPropertyStore ( _, _, _, e , true )
@@ -2722,17 +2747,23 @@ abstract class PostUpdateNode extends Node {
27222747}
27232748
27242749module PostUpdateNodes {
2725- class ObjectCreationNode extends PostUpdateNode , ExprNode , TExprNode {
2750+ abstract class SourcePostUpdateNode extends PostUpdateNode {
2751+ abstract Node getPreUpdateSourceNode ( ) ;
2752+
2753+ final override Node getPreUpdateNode ( ) { result = this .getPreUpdateSourceNode ( ) }
2754+ }
2755+
2756+ class ObjectCreationNode extends SourcePostUpdateNode , ExprNode , TExprNode {
27262757 private ObjectCreation oc ;
27272758
27282759 ObjectCreationNode ( ) { this = TExprNode ( oc .getAControlFlowNode ( ) ) }
27292760
2730- override Node getPreUpdateNode ( ) {
2761+ override Node getPreUpdateSourceNode ( ) {
27312762 exists ( ControlFlow:: Nodes:: ElementNode cfn | this = TExprNode ( cfn ) |
2732- result . ( ObjectInitializerNode ) . getControlFlowNode ( ) = cfn
2763+ result = TObjectInitializerNode ( cfn )
27332764 or
27342765 not oc .hasInitializer ( ) and
2735- result . ( MallocNode ) . getControlFlowNode ( ) = cfn
2766+ result = TMallocNode ( cfn )
27362767 )
27372768 }
27382769 }
@@ -2744,7 +2775,7 @@ module PostUpdateNodes {
27442775 * Such a node acts as both a post-update node for the `MallocNode`, as well as
27452776 * a pre-update node for the `ObjectCreationNode`.
27462777 */
2747- class ObjectInitializerNode extends PostUpdateNode , NodeImpl , ArgumentNodeImpl ,
2778+ class ObjectInitializerNode extends SourcePostUpdateNode , NodeImpl , ArgumentNodeImpl ,
27482779 TObjectInitializerNode
27492780 {
27502781 private ObjectCreation oc ;
@@ -2758,7 +2789,7 @@ module PostUpdateNodes {
27582789 /** Gets the initializer to which this initializer node belongs. */
27592790 ObjectOrCollectionInitializer getInitializer ( ) { result = oc .getInitializer ( ) }
27602791
2761- override MallocNode getPreUpdateNode ( ) { result . getControlFlowNode ( ) = cfn }
2792+ override MallocNode getPreUpdateSourceNode ( ) { result = TMallocNode ( cfn ) }
27622793
27632794 override predicate argumentOf ( DataFlowCall call , ArgumentPosition pos ) {
27642795 pos .isQualifier ( ) and
@@ -2781,23 +2812,12 @@ module PostUpdateNodes {
27812812 override string toStringImpl ( ) { result = "[pre-initializer] " + cfn }
27822813 }
27832814
2784- class ExprPostUpdateNode extends PostUpdateNode , NodeImpl , TExprPostUpdateNode {
2815+ class ExprPostUpdateNode extends SourcePostUpdateNode , NodeImpl , TExprPostUpdateNode {
27852816 private ControlFlow:: Nodes:: ElementNode cfn ;
27862817
27872818 ExprPostUpdateNode ( ) { this = TExprPostUpdateNode ( cfn ) }
27882819
2789- override ExprNode getPreUpdateNode ( ) {
2790- // For compound arguments, such as `m(b ? x : y)`, we want the leaf nodes
2791- // `[post] x` and `[post] y` to have two pre-update nodes: (1) the compound argument,
2792- // `if b then x else y`; and the (2) the underlying expressions; `x` and `y`,
2793- // respectively.
2794- //
2795- // This ensures that we get flow out of the call into both leafs (1), while still
2796- // maintaining the invariant that the underlying expression is a pre-update node (2).
2797- cfn = LocalFlow:: getAPostUpdateNodeForArg ( result .getControlFlowNode ( ) )
2798- or
2799- cfn = result .getControlFlowNode ( )
2800- }
2820+ override ExprNode getPreUpdateSourceNode ( ) { result = TExprNode ( cfn ) }
28012821
28022822 override DataFlowCallable getEnclosingCallableImpl ( ) {
28032823 result .getAControlFlowNode ( ) = cfn
@@ -2825,49 +2845,49 @@ module PostUpdateNodes {
28252845 override Node getPreUpdateNode ( ) { result .( FlowSummaryNode ) .getSummaryNode ( ) = preUpdateNode }
28262846 }
28272847
2828- private class InstanceParameterAccessPostUpdateNode extends PostUpdateNode ,
2848+ private class InstanceParameterAccessPostUpdateNode extends SourcePostUpdateNode ,
28292849 InstanceParameterAccessNode
28302850 {
28312851 InstanceParameterAccessPostUpdateNode ( ) { isPostUpdate = true }
28322852
2833- override InstanceParameterAccessPreNode getPreUpdateNode ( ) {
2853+ override InstanceParameterAccessPreNode getPreUpdateSourceNode ( ) {
28342854 result = TInstanceParameterAccessNode ( cfn , false )
28352855 }
28362856
28372857 override string toStringImpl ( ) { result = "[post] this" }
28382858 }
28392859
2840- private class PrimaryConstructorThisAccessPostUpdateNode extends PostUpdateNode ,
2860+ private class PrimaryConstructorThisAccessPostUpdateNode extends SourcePostUpdateNode ,
28412861 PrimaryConstructorThisAccessNode
28422862 {
28432863 PrimaryConstructorThisAccessPostUpdateNode ( ) { isPostUpdate = true }
28442864
2845- override PrimaryConstructorThisAccessPreNode getPreUpdateNode ( ) {
2865+ override PrimaryConstructorThisAccessPreNode getPreUpdateSourceNode ( ) {
28462866 result = TPrimaryConstructorThisAccessNode ( p , false , callable )
28472867 }
28482868
28492869 override string toStringImpl ( ) { result = "[post] this" }
28502870 }
28512871
2852- class LocalFunctionCreationPostUpdateNode extends LocalFunctionCreationNode , PostUpdateNode {
2872+ class LocalFunctionCreationPostUpdateNode extends LocalFunctionCreationNode , SourcePostUpdateNode {
28532873 LocalFunctionCreationPostUpdateNode ( ) { isPostUpdate = true }
28542874
2855- override LocalFunctionCreationPreNode getPreUpdateNode ( ) {
2875+ override LocalFunctionCreationPreNode getPreUpdateSourceNode ( ) {
28562876 result = TLocalFunctionCreationNode ( cfn , false )
28572877 }
28582878
28592879 override string toStringImpl ( ) { result = "[post] " + cfn }
28602880 }
28612881
2862- private class CapturePostUpdateNode extends PostUpdateNode , CaptureNode {
2882+ private class CapturePostUpdateNode extends SourcePostUpdateNode , CaptureNode {
28632883 private CaptureNode pre ;
28642884
28652885 CapturePostUpdateNode ( ) {
28662886 VariableCapture:: Flow:: capturePostUpdateNode ( this .getSynthesizedCaptureNode ( ) ,
28672887 pre .getSynthesizedCaptureNode ( ) )
28682888 }
28692889
2870- override CaptureNode getPreUpdateNode ( ) { result = pre }
2890+ override CaptureNode getPreUpdateSourceNode ( ) { result = pre }
28712891
28722892 override string toStringImpl ( ) { result = "[post] " + cn }
28732893 }
0 commit comments