@@ -76,15 +76,7 @@ newtype TNode =
7676 node .getNode ( ) = any ( Comp c ) .getIterable ( )
7777 } or
7878 /** A node representing a global (module-level) variable in a specific module. */
79- TModuleVariableNode ( Module m , GlobalVariable v ) {
80- v .getScope ( ) = m and
81- (
82- v .escapes ( )
83- or
84- isAccessedThroughImportStar ( m ) and
85- ImportStar:: globalNameDefinedInModule ( v .getId ( ) , m )
86- )
87- } or
79+ TModuleVariableNode ( Module m , GlobalVariable v ) { v .getScope ( ) = m } or
8880 /**
8981 * A synthetic node representing that an iterable sequence flows to consumer.
9082 */
@@ -129,6 +121,20 @@ newtype TNode =
129121 f = any ( VariableCapture:: CapturedVariable v ) .getACapturingScope ( ) and
130122 exists ( TFunction ( f ) )
131123 } or
124+ /**
125+ * A synthetic node representing the values of the variables captured
126+ * by the callable being called.
127+ */
128+ TSynthCapturedVariablesArgumentNode ( ControlFlowNode callable ) {
129+ callable = any ( CallNode c ) .getFunction ( )
130+ } or
131+ /**
132+ * A synthetic node representing the values of the variables captured
133+ * by the callable being called, after the output has been computed.
134+ */
135+ TSynthCapturedVariablesArgumentPostUpdateNode ( ControlFlowNode callable ) {
136+ callable = any ( CallNode c ) .getFunction ( )
137+ } or
132138 /** A synthetic node representing the values of variables captured by a comprehension. */
133139 TSynthCompCapturedVariablesArgumentNode ( Comp comp ) {
134140 comp .getFunction ( ) = any ( VariableCapture:: CapturedVariable v ) .getACapturingScope ( )
@@ -347,27 +353,51 @@ abstract class ArgumentNode extends Node {
347353 final ExtractedDataFlowCall getCall ( ) { this .argumentOf ( result , _) }
348354}
349355
356+ /** Gets an overapproximation of the argument nodes that are included in `getCallArg`. */
357+ Node getCallArgApproximation ( ) {
358+ // pre-update nodes for calls
359+ result = any ( CallCfgNode c ) .( PostUpdateNode ) .getPreUpdateNode ( )
360+ or
361+ // self parameters in methods
362+ exists ( Class c | result .asExpr ( ) = c .getAMethod ( ) .getArg ( 0 ) )
363+ or
364+ // the object part of an attribute expression (which might be a bound method)
365+ result .asCfgNode ( ) = any ( AttrNode a ) .getObject ( )
366+ or
367+ // the function part of any call
368+ result .asCfgNode ( ) = any ( CallNode c ) .getFunction ( )
369+ }
370+
371+ /** Gets the extracted argument nodes that do not rely on `getCallArg`. */
372+ private Node implicitArgumentNode ( ) {
373+ // for potential summaries we allow all normal call arguments
374+ normalCallArg ( _, result , _)
375+ or
376+ // and self arguments
377+ result .asCfgNode ( ) = any ( CallNode c ) .getFunction ( ) .( AttrNode ) .getObject ( )
378+ or
379+ // for comprehensions, we allow the synthetic `iterable` argument
380+ result .asExpr ( ) = any ( Comp c ) .getIterable ( )
381+ }
382+
350383/**
351384 * A data flow node that represents a call argument found in the source code.
352385 */
353386class ExtractedArgumentNode extends ArgumentNode {
354387 ExtractedArgumentNode ( ) {
355- // for resolved calls, we need to allow all argument nodes
356- getCallArg ( _, _, _, this , _)
357- or
358- // for potential summaries we allow all normal call arguments
359- normalCallArg ( _, this , _)
388+ this = getCallArgApproximation ( )
360389 or
361- // and self arguments
362- this .asCfgNode ( ) = any ( CallNode c ) .getFunction ( ) .( AttrNode ) .getObject ( )
363- or
364- // for comprehensions, we allow the synthetic `iterable` argument
365- this .asExpr ( ) = any ( Comp c ) .getIterable ( )
390+ this = implicitArgumentNode ( )
366391 }
367392
368393 final override predicate argumentOf ( DataFlowCall call , ArgumentPosition pos ) {
369394 this = call .getArgument ( pos ) and
370- call instanceof ExtractedDataFlowCall
395+ call instanceof ExtractedDataFlowCall and
396+ (
397+ this = implicitArgumentNode ( )
398+ or
399+ this = getCallArgApproximation ( ) and getCallArg ( _, _, _, this , _)
400+ )
371401 }
372402}
373403
@@ -440,13 +470,17 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
440470
441471 /** Gets a node that reads this variable. */
442472 Node getARead ( ) {
443- result .asCfgNode ( ) = var .getALoad ( ) .getAFlowNode ( ) and
444- // Ignore reads that happen when the module is imported. These are only executed once.
445- not result .getScope ( ) = mod
473+ result = this .getALocalRead ( )
446474 or
447475 this = import_star_read ( result )
448476 }
449477
478+ /** Gets a node that reads this variable, excluding reads that happen through `from ... import *`. */
479+ Node getALocalRead ( ) {
480+ result .asCfgNode ( ) = var .getALoad ( ) .getAFlowNode ( ) and
481+ not result .getScope ( ) = mod
482+ }
483+
450484 /** Gets an `EssaNode` that corresponds to an assignment of this global variable. */
451485 Node getAWrite ( ) {
452486 any ( EssaNodeDefinition def ) .definedBy ( var , result .asCfgNode ( ) .( DefinitionNode ) )
@@ -466,8 +500,6 @@ class ModuleVariableNode extends Node, TModuleVariableNode {
466500 override Location getLocation ( ) { result = mod .getLocation ( ) }
467501}
468502
469- private predicate isAccessedThroughImportStar ( Module m ) { m = ImportStar:: getStarImported ( _) }
470-
471503private ModuleVariableNode import_star_read ( Node n ) {
472504 resolved_import_star_module ( result .getModule ( ) , result .getVariable ( ) .getId ( ) , n )
473505}
0 commit comments