@@ -16,18 +16,42 @@ class DataFlowCfgNode extends ControlFlowNode {
1616 DataFlowCfgNode ( ) { isExpressionNode ( this ) }
1717}
1818
19- /** A data flow node which should have an associated post-update node. */
20- abstract class PreUpdateNode extends Node {
19+ /** A data flow node for which we should synthesise an associated pre-update node. */
20+ abstract class NeedsSyntheticPreUpdateNode extends Node {
21+ abstract string label ( ) ;
22+ }
23+
24+ class SyntheticPreUpdateNode extends Node , TSyntheticPreUpdateNode {
25+ NeedsSyntheticPreUpdateNode post ;
26+
27+ SyntheticPreUpdateNode ( ) { this = TSyntheticPreUpdateNode ( post ) }
28+
29+ /** Gets the node for which this is a synthetic pre-update node. */
30+ Node getPostUpdateNode ( ) { result = post }
31+
32+ override string toString ( ) { result = "[pre " + post .label ( ) + "] " + post .toString ( ) }
33+
34+ override Scope getScope ( ) { result = post .getScope ( ) }
35+
36+ override Location getLocation ( ) { result = post .getLocation ( ) }
37+ }
38+
39+ /** A data flow node for which we should synthesise an associated post-update node. */
40+ abstract class NeedsSyntheticPostUpdateNode extends Node {
2141 abstract string label ( ) ;
2242}
2343
2444/** An argument might have its value changed as a result of a call. */
25- class ArgumentPreUpdateNode extends PreUpdateNode , ExplicitArgumentNode {
45+ class ArgumentPreUpdateNode extends NeedsSyntheticPostUpdateNode , ArgumentNode {
46+ // Certain arguments, such as implicit self arguments are already post-update nodes
47+ // and should not have an extra node synthesised.
48+ ArgumentPreUpdateNode ( ) { this .isNotPostUpdate ( ) }
49+
2650 override string label ( ) { result = "arg" }
2751}
2852
2953/** An object might have its value changed after a store. */
30- class StorePreUpdateNode extends PreUpdateNode , CfgNode {
54+ class StorePreUpdateNode extends NeedsSyntheticPostUpdateNode , CfgNode {
3155 StorePreUpdateNode ( ) {
3256 exists ( Attribute a |
3357 node = a .getObject ( ) .getAFlowNode ( ) and
@@ -39,7 +63,7 @@ class StorePreUpdateNode extends PreUpdateNode, CfgNode {
3963}
4064
4165/** A node marking the state change of an object after a read. */
42- class ReadPreUpdateNode extends PreUpdateNode , CfgNode {
66+ class ReadPreUpdateNode extends NeedsSyntheticPostUpdateNode , CfgNode {
4367 ReadPreUpdateNode ( ) {
4468 exists ( Attribute a |
4569 node = a .getObject ( ) .getAFlowNode ( ) and
@@ -58,16 +82,21 @@ class ReadPreUpdateNode extends PreUpdateNode, CfgNode {
5882 * (which might have mutated the argument), or the qualifier of a field after
5983 * an update to the field.
6084 *
61- * Nodes corresponding to AST elements, for example `ExprNode`, usually refer
62- * to the value before the update.
85+ * Nodes corresponding to AST elements, for example `ExprNode`s, usually refer
86+ * to the value before the update with the exception of `ObjectCreationNode`s,
87+ * which represents the value after the constructor has run.
6388 */
64- class PostUpdateNode extends Node , TPostUpdateNode {
65- PreUpdateNode pre ;
89+ abstract class PostUpdateNode extends Node {
90+ /** Gets the node before the state update. */
91+ abstract Node getPreUpdateNode ( ) ;
92+ }
6693
67- PostUpdateNode ( ) { this = TPostUpdateNode ( pre ) }
94+ class SyntheticPostUpdateNode extends PostUpdateNode , TSyntheticPostUpdateNode {
95+ NeedsSyntheticPostUpdateNode pre ;
6896
69- /** Gets the node before the state update. */
70- Node getPreUpdateNode ( ) { result = pre }
97+ SyntheticPostUpdateNode ( ) { this = TSyntheticPostUpdateNode ( pre ) }
98+
99+ override Node getPreUpdateNode ( ) { result = pre }
71100
72101 override string toString ( ) { result = "[post " + pre .label ( ) + "] " + pre .toString ( ) }
73102
@@ -76,6 +105,14 @@ class PostUpdateNode extends Node, TPostUpdateNode {
76105 override Location getLocation ( ) { result = pre .getLocation ( ) }
77106}
78107
108+ class ObjectCreationNode extends PostUpdateNode , NeedsSyntheticPreUpdateNode , CfgNode {
109+ ObjectCreationNode ( ) { node .( CallNode ) = any ( ClassValue c ) .getACall ( ) }
110+
111+ override Node getPreUpdateNode ( ) { result .( SyntheticPreUpdateNode ) .getPostUpdateNode ( ) = this }
112+
113+ override string label ( ) { result = "objCreate" }
114+ }
115+
79116class DataFlowExpr = Expr ;
80117
81118/**
@@ -199,7 +236,7 @@ abstract class DataFlowCall extends TDataFlowCall {
199236 abstract DataFlowCallable getCallable ( ) ;
200237
201238 /** Get the specified argument to this call. */
202- abstract ControlFlowNode getArg ( int n ) ;
239+ abstract Node getArg ( int n ) ;
203240
204241 /** Get the control flow node representing this call. */
205242 abstract ControlFlowNode getNode ( ) ;
@@ -220,7 +257,7 @@ class CallNodeCall extends DataFlowCall, TCallNode {
220257
221258 override string toString ( ) { result = call .toString ( ) }
222259
223- override ControlFlowNode getArg ( int n ) { result = call .getArg ( n ) }
260+ override Node getArg ( int n ) { result = TCfgNode ( call .getArg ( n ) ) }
224261
225262 override ControlFlowNode getNode ( ) { result = call }
226263
@@ -241,10 +278,10 @@ class ClassCall extends DataFlowCall, TClassCall {
241278
242279 override string toString ( ) { result = call .toString ( ) }
243280
244- override ControlFlowNode getArg ( int n ) {
245- result = call .getArg ( n - 1 )
281+ override Node getArg ( int n ) {
282+ n > 0 and result = TCfgNode ( call .getArg ( n - 1 ) )
246283 or
247- n = 0 and result = call
284+ n = 0 and result = TSyntheticPreUpdateNode ( TCfgNode ( call ) )
248285 }
249286
250287 override ControlFlowNode getNode ( ) { result = call }
@@ -267,7 +304,7 @@ class SpecialCall extends DataFlowCall, TSpecialCall {
267304
268305 override string toString ( ) { result = special .toString ( ) }
269306
270- override ControlFlowNode getArg ( int n ) { result = special .( SpecialMethod:: Potential ) .getArg ( n ) }
307+ override Node getArg ( int n ) { result = TCfgNode ( special .( SpecialMethod:: Potential ) .getArg ( n ) ) }
271308
272309 override ControlFlowNode getNode ( ) { result = special }
273310
@@ -279,23 +316,23 @@ class SpecialCall extends DataFlowCall, TSpecialCall {
279316}
280317
281318/** A data flow node that represents a call argument. */
282- abstract class ArgumentNode extends CfgNode {
283- /** Holds if this argument occurs at the given position in the given call. */
284- abstract predicate argumentOf ( DataFlowCall call , int pos ) ;
285-
286- /** Gets the call in which this node is an argument. */
287- abstract DataFlowCall getCall ( ) ;
288- }
289-
290- /** A data flow node that represents a call argument. */
291- class ExplicitArgumentNode extends ArgumentNode {
292- ExplicitArgumentNode ( ) { exists ( DataFlowCall call , int pos | node = call .getArg ( pos ) ) }
319+ class ArgumentNode extends Node {
320+ ArgumentNode ( ) { this = any ( DataFlowCall c ) .getArg ( _) }
293321
294322 /** Holds if this argument occurs at the given position in the given call. */
295- override predicate argumentOf ( DataFlowCall call , int pos ) { node = call .getArg ( pos ) }
323+ predicate argumentOf ( DataFlowCall call , int pos ) { this = call .getArg ( pos ) }
296324
297325 /** Gets the call in which this node is an argument. */
298- final override DataFlowCall getCall ( ) { this .argumentOf ( result , _) }
326+ final DataFlowCall getCall ( ) { this .argumentOf ( result , _) }
327+
328+ predicate isNotPostUpdate ( ) {
329+ // Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
330+ exists ( CallNodeCall c | this = c .getArg ( _) )
331+ or
332+ exists ( ClassCall c , int n | n > 0 | this = c .getArg ( n ) )
333+ or
334+ exists ( SpecialCall c | this = c .getArg ( _) )
335+ }
299336}
300337
301338/** Gets a viable run-time target for the call `call`. */
0 commit comments