@@ -440,6 +440,23 @@ module API {
440
440
m = n .getEnclosingModule ( )
441
441
}
442
442
443
+ /**
444
+ * Holds if `n` is an access of a variable called `name` (which is _not_ the name of a
445
+ * built-in, and which is _not_ a global defined in the enclosing module) inside the scope `s`.
446
+ */
447
+ private predicate name_possibly_defined_in_import_star ( NameNode n , string name , Scope s ) {
448
+ n .isLoad ( ) and
449
+ name = n .getId ( ) and
450
+ // Not already defined in an enclosing scope.
451
+ not exists ( LocalVariable v |
452
+ v .getId ( ) = name and v .getScope ( ) .getEnclosingScope * ( ) = n .getScope ( )
453
+ ) and
454
+ not name = getBuiltInName ( ) and
455
+ s = n .getScope ( ) .getEnclosingScope * ( ) and
456
+ exists ( potential_import_star_base ( s ) ) and
457
+ not global_name_defined_in_module ( name , n .getEnclosingModule ( ) )
458
+ }
459
+
443
460
/** Holds if a global variable called `name` is assigned a value in the module `m`. */
444
461
private predicate global_name_defined_in_module ( string name , Module m ) {
445
462
exists ( NameNode n |
@@ -450,6 +467,24 @@ module API {
450
467
)
451
468
}
452
469
470
+ /**
471
+ * Gets the API graph node for all modules imported with `from ... import *` inside the scope `s`.
472
+ *
473
+ * For example, given
474
+ *
475
+ * `from foo.bar import *`
476
+ *
477
+ * this would be the API graph node with the path
478
+ *
479
+ * `moduleImport("foo").getMember("bar")`
480
+ */
481
+ private TApiNode potential_import_star_base ( Scope s ) {
482
+ exists ( DataFlow:: Node ref |
483
+ ref .asCfgNode ( ) = any ( ImportStarNode n | n .getScope ( ) = s ) .getModule ( ) and
484
+ use ( result , ref )
485
+ )
486
+ }
487
+
453
488
/**
454
489
* Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled
455
490
* `lbl` in the API graph.
@@ -492,6 +527,15 @@ module API {
492
527
// Built-ins, treated as members of the module `builtins`
493
528
base = MkModuleImport ( "builtins" ) and
494
529
lbl = Label:: member ( any ( string name | ref = likely_builtin ( name ) ) )
530
+ or
531
+ // Unknown variables that may belong to a module imported with `import *`
532
+ exists ( Scope s |
533
+ base = potential_import_star_base ( s ) and
534
+ lbl =
535
+ Label:: member ( any ( string name |
536
+ name_possibly_defined_in_import_star ( ref .asCfgNode ( ) , name , s )
537
+ ) )
538
+ )
495
539
}
496
540
497
541
/**
0 commit comments