@@ -126,7 +126,7 @@ module syntheticPostUpdateNode {
126126 * Certain arguments, such as implicit self arguments are already post-update nodes
127127 * and should not have an extra node synthesised.
128128 */
129- ArgumentNode argumentPreUpdateNode ( ) {
129+ Node argumentPreUpdateNode ( ) {
130130 result = any ( FunctionCall c ) .getArg ( _)
131131 or
132132 // Avoid argument 0 of method calls as those have read post-update nodes.
@@ -136,6 +136,11 @@ module syntheticPostUpdateNode {
136136 or
137137 // Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
138138 exists ( ClassCall c , int n | n > 0 | result = c .getArg ( n ) )
139+ or
140+ // any argument of any call that we have not been able to resolve
141+ exists ( CallNode call | not call = any ( DataFlowCall c ) .getNode ( ) |
142+ result .( CfgNode ) .getNode ( ) in [ call .getArg ( _) , call .getArgByName ( _) ]
143+ )
139144 }
140145
141146 /** An object might have its value changed after a store. */
@@ -704,7 +709,7 @@ newtype TDataFlowCall =
704709 TFunctionCall ( CallNode call ) { call = any ( FunctionValue f ) .getAFunctionCall ( ) } or
705710 /** Bound methods need to make room for the explicit self parameter */
706711 TMethodCall ( CallNode call ) { call = any ( FunctionValue f ) .getAMethodCall ( ) } or
707- TClassCall ( CallNode call ) { call = any ( ClassValue c ) .getACall ( ) } or
712+ TClassCall ( CallNode call ) { call = any ( ClassValue c | not c . isAbsent ( ) ) .getACall ( ) } or
708713 TSpecialCall ( SpecialMethodCallNode special )
709714
710715/** Represents a call. */
@@ -1067,19 +1072,18 @@ predicate comprehensionStoreStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
10671072}
10681073
10691074/**
1070- * Holds if `nodeFrom` flows into an attribute (corresponding to `c`) of `nodeTo` via an attribute assignment.
1075+ * Holds if `nodeFrom` flows into the attribute `c` of `nodeTo` via an attribute assignment.
10711076 *
10721077 * For example, in
10731078 * ```python
10741079 * obj.foo = x
10751080 * ```
1076- * data flows from `x` to (the post-update node for) `obj` via assignment to `foo `.
1081+ * data flows from `x` to the attribute `foo` of (the post-update node for) `obj`.
10771082 */
1078- predicate attributeStoreStep ( CfgNode nodeFrom , AttributeContent c , PostUpdateNode nodeTo ) {
1079- exists ( AttrNode attr |
1080- nodeFrom .asCfgNode ( ) = attr .( DefinitionNode ) .getValue ( ) and
1081- attr .getName ( ) = c .getAttribute ( ) and
1082- attr .getObject ( ) = nodeTo .getPreUpdateNode ( ) .( CfgNode ) .getNode ( )
1083+ predicate attributeStoreStep ( Node nodeFrom , AttributeContent c , PostUpdateNode nodeTo ) {
1084+ exists ( AttrWrite write |
1085+ write .accesses ( nodeTo .getPreUpdateNode ( ) , c .getAttribute ( ) ) and
1086+ nodeFrom = write .getValue ( )
10831087 )
10841088}
10851089
@@ -1923,21 +1927,16 @@ pragma[noinline]
19231927TupleElementContent small_tuple ( ) { result .getIndex ( ) <= 7 }
19241928
19251929/**
1926- * Holds if `nodeTo` is a read of an attribute (corresponding to `c`) of the object in `nodeFrom`.
1930+ * Holds if `nodeTo` is a read of the attribute `c` of the object `nodeFrom`.
19271931 *
1928- * For example, in
1932+ * For example
19291933 * ```python
19301934 * obj.foo
19311935 * ```
1932- * data flows from `obj` to `obj. foo` via a read from `foo `.
1936+ * is a read of the attribute ` foo` from the object `obj `.
19331937 */
1934- predicate attributeReadStep ( CfgNode nodeFrom , AttributeContent c , CfgNode nodeTo ) {
1935- exists ( AttrNode attr |
1936- nodeFrom .asCfgNode ( ) = attr .getObject ( ) and
1937- nodeTo .asCfgNode ( ) = attr and
1938- attr .getName ( ) = c .getAttribute ( ) and
1939- attr .isLoad ( )
1940- )
1938+ predicate attributeReadStep ( Node nodeFrom , AttributeContent c , AttrRead nodeTo ) {
1939+ nodeTo .accesses ( nodeFrom , c .getAttribute ( ) )
19411940}
19421941
19431942/**
@@ -1973,6 +1972,18 @@ predicate clearsContent(Node n, Content c) {
19731972 kwOverflowClearStep ( n , c )
19741973 or
19751974 matchClearStep ( n , c )
1975+ or
1976+ attributeClearStep ( n , c )
1977+ }
1978+
1979+ /**
1980+ * Holds if values stored inside attribute `c` are cleared at node `n`.
1981+ *
1982+ * In `obj.foo = x` any old value stored in `foo` is cleared at the pre-update node
1983+ * associated with `obj`
1984+ */
1985+ predicate attributeClearStep ( Node n , AttributeContent c ) {
1986+ exists ( PostUpdateNode post | post .getPreUpdateNode ( ) = n | attributeStoreStep ( _, c , post ) )
19761987}
19771988
19781989//--------
0 commit comments