@@ -691,19 +691,22 @@ module LocalFlow {
691
691
)
692
692
}
693
693
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 )
707
710
}
708
711
709
712
/**
@@ -763,6 +766,13 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
763
766
VariableCapture:: valueStep ( nodeFrom , nodeTo )
764
767
or
765
768
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 ( ) )
766
776
) and
767
777
model = ""
768
778
or
@@ -1061,6 +1071,20 @@ private class FieldOrPropertyUsedInSource extends FieldOrProperty {
1061
1071
}
1062
1072
}
1063
1073
1074
+ /**
1075
+ * Hold if `e` has a type that allows for it to have a post-update node.
1076
+ */
1077
+ predicate exprMayHavePostUpdateNode ( Expr e ) {
1078
+ exists ( Type t | t = e .stripCasts ( ) .getType ( ) |
1079
+ t instanceof RefType and
1080
+ not t instanceof NullType
1081
+ or
1082
+ t = any ( TypeParameter tp | not tp .isValueType ( ) )
1083
+ or
1084
+ t .isRefLikeType ( )
1085
+ )
1086
+ }
1087
+
1064
1088
/** A collection of cached types and predicates to be evaluated in the same stage. */
1065
1089
cached
1066
1090
private module Cached {
@@ -1106,7 +1130,15 @@ private module Cached {
1106
1130
cfn .getAstNode ( ) .( ObjectCreation ) .hasInitializer ( )
1107
1131
} or
1108
1132
TExprPostUpdateNode ( ControlFlow:: Nodes:: ExprNode cfn ) {
1109
- cfn = LocalFlow:: getAPostUpdateNodeForArg ( _)
1133
+ (
1134
+ cfn .getExpr ( ) instanceof Argument
1135
+ or
1136
+ cfn =
1137
+ LocalFlow:: getPostUpdateReverseStep ( any ( ControlFlow:: Nodes:: ExprNode e |
1138
+ exists ( any ( SourcePostUpdateNode p ) .getPreUpdateNode ( ) .asExprAtNode ( e ) )
1139
+ ) )
1140
+ ) and
1141
+ exprMayHavePostUpdateNode ( cfn .getExpr ( ) )
1110
1142
or
1111
1143
exists ( Expr e | e = cfn .getExpr ( ) |
1112
1144
fieldOrPropertyStore ( _, _, _, e , true )
@@ -2722,17 +2754,23 @@ abstract class PostUpdateNode extends Node {
2722
2754
}
2723
2755
2724
2756
module PostUpdateNodes {
2725
- class ObjectCreationNode extends PostUpdateNode , ExprNode , TExprNode {
2757
+ abstract class SourcePostUpdateNode extends PostUpdateNode {
2758
+ abstract Node getPreUpdateSourceNode ( ) ;
2759
+
2760
+ final override Node getPreUpdateNode ( ) { result = this .getPreUpdateSourceNode ( ) }
2761
+ }
2762
+
2763
+ class ObjectCreationNode extends SourcePostUpdateNode , ExprNode , TExprNode {
2726
2764
private ObjectCreation oc ;
2727
2765
2728
2766
ObjectCreationNode ( ) { this = TExprNode ( oc .getAControlFlowNode ( ) ) }
2729
2767
2730
- override Node getPreUpdateNode ( ) {
2768
+ override Node getPreUpdateSourceNode ( ) {
2731
2769
exists ( ControlFlow:: Nodes:: ElementNode cfn | this = TExprNode ( cfn ) |
2732
- result . ( ObjectInitializerNode ) . getControlFlowNode ( ) = cfn
2770
+ result = TObjectInitializerNode ( cfn )
2733
2771
or
2734
2772
not oc .hasInitializer ( ) and
2735
- result . ( MallocNode ) . getControlFlowNode ( ) = cfn
2773
+ result = TMallocNode ( cfn )
2736
2774
)
2737
2775
}
2738
2776
}
@@ -2744,7 +2782,7 @@ module PostUpdateNodes {
2744
2782
* Such a node acts as both a post-update node for the `MallocNode`, as well as
2745
2783
* a pre-update node for the `ObjectCreationNode`.
2746
2784
*/
2747
- class ObjectInitializerNode extends PostUpdateNode , NodeImpl , ArgumentNodeImpl ,
2785
+ class ObjectInitializerNode extends SourcePostUpdateNode , NodeImpl , ArgumentNodeImpl ,
2748
2786
TObjectInitializerNode
2749
2787
{
2750
2788
private ObjectCreation oc ;
@@ -2758,7 +2796,7 @@ module PostUpdateNodes {
2758
2796
/** Gets the initializer to which this initializer node belongs. */
2759
2797
ObjectOrCollectionInitializer getInitializer ( ) { result = oc .getInitializer ( ) }
2760
2798
2761
- override MallocNode getPreUpdateNode ( ) { result . getControlFlowNode ( ) = cfn }
2799
+ override MallocNode getPreUpdateSourceNode ( ) { result = TMallocNode ( cfn ) }
2762
2800
2763
2801
override predicate argumentOf ( DataFlowCall call , ArgumentPosition pos ) {
2764
2802
pos .isQualifier ( ) and
@@ -2781,23 +2819,12 @@ module PostUpdateNodes {
2781
2819
override string toStringImpl ( ) { result = "[pre-initializer] " + cfn }
2782
2820
}
2783
2821
2784
- class ExprPostUpdateNode extends PostUpdateNode , NodeImpl , TExprPostUpdateNode {
2822
+ class ExprPostUpdateNode extends SourcePostUpdateNode , NodeImpl , TExprPostUpdateNode {
2785
2823
private ControlFlow:: Nodes:: ElementNode cfn ;
2786
2824
2787
2825
ExprPostUpdateNode ( ) { this = TExprPostUpdateNode ( cfn ) }
2788
2826
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
- }
2827
+ override ExprNode getPreUpdateSourceNode ( ) { result = TExprNode ( cfn ) }
2801
2828
2802
2829
override DataFlowCallable getEnclosingCallableImpl ( ) {
2803
2830
result .getAControlFlowNode ( ) = cfn
@@ -2825,49 +2852,49 @@ module PostUpdateNodes {
2825
2852
override Node getPreUpdateNode ( ) { result .( FlowSummaryNode ) .getSummaryNode ( ) = preUpdateNode }
2826
2853
}
2827
2854
2828
- private class InstanceParameterAccessPostUpdateNode extends PostUpdateNode ,
2855
+ private class InstanceParameterAccessPostUpdateNode extends SourcePostUpdateNode ,
2829
2856
InstanceParameterAccessNode
2830
2857
{
2831
2858
InstanceParameterAccessPostUpdateNode ( ) { isPostUpdate = true }
2832
2859
2833
- override InstanceParameterAccessPreNode getPreUpdateNode ( ) {
2860
+ override InstanceParameterAccessPreNode getPreUpdateSourceNode ( ) {
2834
2861
result = TInstanceParameterAccessNode ( cfn , false )
2835
2862
}
2836
2863
2837
2864
override string toStringImpl ( ) { result = "[post] this" }
2838
2865
}
2839
2866
2840
- private class PrimaryConstructorThisAccessPostUpdateNode extends PostUpdateNode ,
2867
+ private class PrimaryConstructorThisAccessPostUpdateNode extends SourcePostUpdateNode ,
2841
2868
PrimaryConstructorThisAccessNode
2842
2869
{
2843
2870
PrimaryConstructorThisAccessPostUpdateNode ( ) { isPostUpdate = true }
2844
2871
2845
- override PrimaryConstructorThisAccessPreNode getPreUpdateNode ( ) {
2872
+ override PrimaryConstructorThisAccessPreNode getPreUpdateSourceNode ( ) {
2846
2873
result = TPrimaryConstructorThisAccessNode ( p , false , callable )
2847
2874
}
2848
2875
2849
2876
override string toStringImpl ( ) { result = "[post] this" }
2850
2877
}
2851
2878
2852
- class LocalFunctionCreationPostUpdateNode extends LocalFunctionCreationNode , PostUpdateNode {
2879
+ class LocalFunctionCreationPostUpdateNode extends LocalFunctionCreationNode , SourcePostUpdateNode {
2853
2880
LocalFunctionCreationPostUpdateNode ( ) { isPostUpdate = true }
2854
2881
2855
- override LocalFunctionCreationPreNode getPreUpdateNode ( ) {
2882
+ override LocalFunctionCreationPreNode getPreUpdateSourceNode ( ) {
2856
2883
result = TLocalFunctionCreationNode ( cfn , false )
2857
2884
}
2858
2885
2859
2886
override string toStringImpl ( ) { result = "[post] " + cfn }
2860
2887
}
2861
2888
2862
- private class CapturePostUpdateNode extends PostUpdateNode , CaptureNode {
2889
+ private class CapturePostUpdateNode extends SourcePostUpdateNode , CaptureNode {
2863
2890
private CaptureNode pre ;
2864
2891
2865
2892
CapturePostUpdateNode ( ) {
2866
2893
VariableCapture:: Flow:: capturePostUpdateNode ( this .getSynthesizedCaptureNode ( ) ,
2867
2894
pre .getSynthesizedCaptureNode ( ) )
2868
2895
}
2869
2896
2870
- override CaptureNode getPreUpdateNode ( ) { result = pre }
2897
+ override CaptureNode getPreUpdateSourceNode ( ) { result = pre }
2871
2898
2872
2899
override string toStringImpl ( ) { result = "[post] " + cn }
2873
2900
}
0 commit comments