@@ -216,6 +216,9 @@ module API {
216216 */
217217 Node moduleImport ( string m ) { result = Impl:: MkModuleImport ( m ) }
218218
219+ /** Gets a node corresponding to the built-in with the given name, if any. */
220+ Node builtin ( string n ) { result = moduleImport ( "builtins" ) .getMember ( n ) }
221+
219222 /**
220223 * Provides the actual implementation of API graphs, cached for performance.
221224 *
@@ -300,11 +303,18 @@ module API {
300303 MkRoot ( ) or
301304 /** An abstract representative for imports of the module called `name`. */
302305 MkModuleImport ( string name ) {
303- imports ( _, name )
306+ (
307+ imports ( _, name )
308+ or
309+ // When we `import foo.bar.baz` we want to create API graph nodes also for the prefixes
310+ // `foo` and `foo.bar`:
311+ name = any ( ImportExpr e | not e .isRelative ( ) ) .getAnImportedModuleName ( )
312+ ) and
313+ // Ignore the following module name, as we alias `__builtin__` to `builtins` elsewhere
314+ name != "__builtin__"
304315 or
305- // When we `import foo.bar.baz` we want to create API graph nodes also for the prefixes
306- // `foo` and `foo.bar`:
307- name = any ( ImportExpr e | not e .isRelative ( ) ) .getAnImportedModuleName ( )
316+ // The `builtins` module should always be implicitly available
317+ name = "builtins"
308318 } or
309319 /** A use of an API member at the node `nd`. */
310320 MkUse ( DataFlow:: Node nd ) { use ( _, _, nd ) }
@@ -339,6 +349,24 @@ module API {
339349 )
340350 }
341351
352+ private import semmle.python.types.Builtins as Builtins
353+
354+ /**
355+ * Gets a data flow node that is likely to refer to a built-in with the name `name`.
356+ *
357+ * Currently this is an over-approximation, and does not account for things like overwriting a
358+ * built-in with a different value.
359+ */
360+ private DataFlow:: Node likely_builtin ( string name ) {
361+ result .asCfgNode ( ) =
362+ any ( NameNode n |
363+ n .isGlobal ( ) and
364+ n .isLoad ( ) and
365+ name = n .getId ( ) and
366+ name = any ( Builtins:: Builtin b ) .getName ( )
367+ )
368+ }
369+
342370 /**
343371 * Holds if `ref` is a use of a node that should have an incoming edge from `base` labeled
344372 * `lbl` in the API graph.
@@ -369,6 +397,10 @@ module API {
369397 ref .asExpr ( ) .( ClassExpr ) .getABase ( ) = superclass .asExpr ( )
370398 )
371399 )
400+ or
401+ // Built-ins, treated as members of the module `builtins`
402+ base = MkModuleImport ( "builtins" ) and
403+ lbl = Label:: member ( any ( string name | ref = likely_builtin ( name ) ) )
372404 }
373405
374406 /**
@@ -381,6 +413,10 @@ module API {
381413 imports ( ref , name )
382414 )
383415 or
416+ // Ensure the Python 2 `__builtin__` module gets the name of the Python 3 `builtins` module.
417+ nd = MkModuleImport ( "builtins" ) and
418+ imports ( ref , "__builtin__" )
419+ or
384420 nd = MkUse ( ref )
385421 }
386422
0 commit comments