@@ -32,69 +32,83 @@ class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode {
3232 override Location getLocation ( ) { result = post .getLocation ( ) }
3333}
3434
35- /** A data flow node for which we should synthesise an associated post-update node. */
36- abstract class NeedsSyntheticPostUpdateNode extends Node {
37- /** A label for this kind of node. This will figure in the textual representation of the synthesized post-update node. */
38- abstract string label ( ) ;
39- }
35+ /** A module collecting the different reasons for synthesising a post-update node. */
36+ module needsSyntheticPostUpdateNode {
37+ /** A data flow node for which we should synthesise an associated post-update node. */
38+ class NeedsSyntheticPostUpdateNode extends Node {
39+ NeedsSyntheticPostUpdateNode ( ) {
40+ this = argumentPreUpdateNode ( )
41+ or
42+ this = storePreUpdateNode ( )
43+ or
44+ this = readPreUpdateNode ( )
45+ }
46+
47+ /**
48+ * A label for this kind of node. This will figure in the textual representation of the synthesized post-update node.
49+ * We favour being an arguments as the reason for the post-update node in case multiple reasons apply.
50+ */
51+ string label ( ) {
52+ if this = argumentPreUpdateNode ( )
53+ then result = "arg"
54+ else
55+ if this = storePreUpdateNode ( )
56+ then result = "store"
57+ else result = "read"
58+ }
59+ }
4060
41- /** An argument might have its value changed as a result of a call. */
42- class ArgumentPreUpdateNode extends NeedsSyntheticPostUpdateNode , ArgumentNode {
43- // Certain arguments, such as implicit self arguments are already post-update nodes
44- // and should not have an extra node synthesised.
45- ArgumentPreUpdateNode ( ) {
46- this = any ( FunctionCall c ) .getArg ( _)
61+ /**
62+ * An argument might have its value changed as a result of a call.
63+ * Certain arguments, such as implicit self arguments are already post-update nodes
64+ * and should not have an extra node synthesised.
65+ */
66+ ArgumentNode argumentPreUpdateNode ( ) {
67+ result = any ( FunctionCall c ) .getArg ( _)
4768 or
4869 // Avoid argument 0 of method calls as those have read post-update nodes.
49- exists ( MethodCall c , int n | n > 0 | this = c .getArg ( n ) )
70+ exists ( MethodCall c , int n | n > 0 | result = c .getArg ( n ) )
5071 or
51- this = any ( SpecialCall c ) .getArg ( _)
72+ result = any ( SpecialCall c ) .getArg ( _)
5273 or
5374 // Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
54- exists ( ClassCall c , int n | n > 0 | this = c .getArg ( n ) )
75+ exists ( ClassCall c , int n | n > 0 | result = c .getArg ( n ) )
5576 }
5677
57- override string label ( ) { result = "arg" }
58- }
59-
60- /** An object might have its value changed after a store. */
61- class StorePreUpdateNode extends NeedsSyntheticPostUpdateNode , CfgNode {
62- StorePreUpdateNode ( ) {
78+ /** An object might have its value changed after a store. */
79+ CfgNode storePreUpdateNode ( ) {
6380 exists ( Attribute a |
64- node = a .getObject ( ) .getAFlowNode ( ) and
81+ result . getNode ( ) = a .getObject ( ) .getAFlowNode ( ) and
6582 a .getCtx ( ) instanceof Store
6683 )
6784 }
6885
69- override string label ( ) { result = "store" }
70- }
71-
72- /**
73- * A node marking the state change of an object after a read.
74- *
75- * A reverse read happens when the result of a read is modified, e.g. in
76- * ```python
77- * l = [ mutable ]
78- * l[0].mutate()
79- * ```
80- * we may now have changed the content of `l`. To track this, there must be
81- * a postupdate node for `l`.
82- */
83- class ReadPreUpdateNode extends NeedsSyntheticPostUpdateNode , CfgNode {
84- ReadPreUpdateNode ( ) {
86+ /**
87+ * A node marking the state change of an object after a read.
88+ *
89+ * A reverse read happens when the result of a read is modified, e.g. in
90+ * ```python
91+ * l = [ mutable ]
92+ * l[0].mutate()
93+ * ```
94+ * we may now have changed the content of `l`. To track this, there must be
95+ * a postupdate node for `l`.
96+ */
97+ CfgNode readPreUpdateNode ( ) {
8598 exists ( Attribute a |
86- node = a .getObject ( ) .getAFlowNode ( ) and
99+ result . getNode ( ) = a .getObject ( ) .getAFlowNode ( ) and
87100 a .getCtx ( ) instanceof Load
88101 )
89102 or
90- node = any ( SubscriptNode s ) .getObject ( )
103+ result . getNode ( ) = any ( SubscriptNode s ) .getObject ( )
91104 or
92- node .getNode ( ) = any ( Call call ) .getKwargs ( )
105+ // The dictionary argument is read from if the callable has parameters matching the keys.
106+ result .getNode ( ) .getNode ( ) = any ( Call call ) .getKwargs ( )
93107 }
94-
95- override string label ( ) { result = "read" }
96108}
97109
110+ import needsSyntheticPostUpdateNode
111+
98112/** A post-update node is synthesized for all nodes which satisfy `NeedsSyntheticPostUpdateNode`. */
99113class SyntheticPostUpdateNode extends PostUpdateNode , TSyntheticPostUpdateNode {
100114 NeedsSyntheticPostUpdateNode pre ;
@@ -402,6 +416,12 @@ module ArgumentPassing {
402416 *
403417 * NOT SUPPORTED: Keyword-only parameters.
404418 */
419+ Node testGetArg ( CallNode call , int n , DataFlowCallable callable ) {
420+ result .getLocation ( ) .getStartLine ( ) = 685 and
421+ result .getLocation ( ) .getFile ( ) .getBaseName ( ) = "ElementTree.py" and
422+ result = getArg ( call , TNoShift ( ) , callable .getCallableValue ( ) , n )
423+ }
424+
405425 Node getArg ( CallNode call , ArgParamMapping mapping , CallableValue callable , int paramN ) {
406426 connects ( call , callable ) and
407427 (
0 commit comments