@@ -258,67 +258,16 @@ module API {
258258 }
259259
260260 /**
261- * Holds if `import_node` is an import of a module named `name`
261+ * Holds if `imp` is a data-flow node inside an import statement that refers to a module by the
262+ * name `name`.
262263 *
263- * Ignores relative imports (`from ..foo import bar`).
264- *
265- * Note that for the statement `import pkg.mod`, the new variable introduced is `pkg` that is a
266- * reference to the module `pkg`.
267- *
268- * This predicate handles (with optional `... as <new-name>`):
269- * 1. `import <name>`
270- * 2. `from <package> import <module>` when `<name> = <package> + "." + <module>`
271- * 3. `from <module> import <member>` when `<name> = <module> + "." + <member>`
272- *
273- * Finally, in `from <module> import <member>` we consider the `ImportExpr` corresponding to
274- * `<module>` to be a reference to that module.
275- *
276- * Note:
277- * While it is technically possible that `import mypkg.foo` and `from mypkg import foo` can give different values,
278- * it's highly unlikely that this will be a problem in production level code.
279- * Example: If `mypkg/__init__.py` contains `foo = 42`, then `from mypkg import foo` will not import the module
280- * `mypkg/foo.py` but the variable `foo` containing `42` -- however, `import mypkg.foo` will always cause `mypkg.foo`
281- * to refer to the module.
264+ * Ignores relative imports, such as `from ..foo.bar import baz`.
282265 */
283- private predicate imports ( DataFlow:: Node import_node , string name ) {
284- exists ( Variable var , Import imp , Alias alias |
285- alias = imp .getAName ( ) and
286- alias .getAsname ( ) = var .getAStore ( ) and
287- (
288- name = alias .getValue ( ) .( ImportMember ) .getImportedModuleName ( )
289- or
290- name = alias .getValue ( ) .( ImportExpr ) .getImportedModuleName ( ) and
291- not alias .getValue ( ) .( ImportExpr ) .isRelative ( )
292- ) and
293- import_node .asExpr ( ) = alias .getValue ( )
294- )
295- or
296- // Although it may seem superfluous to consider the `foo` part of `from foo import bar as baz` to
297- // be a reference to a module (since that reference only makes sense locally within the `import`
298- // statement), it's important for our use of type trackers to consider this local reference to
299- // also refer to the `foo` module. That way, if one wants to track references to the `bar`
300- // attribute using a type tracker, one can simply write
301- //
302- // ```ql
303- // DataFlow::Node bar_attr_tracker(TypeTracker t) {
304- // t.startInAttr("bar") and
305- // result = foo_module_tracker()
306- // or
307- // exists(TypeTracker t2 | result = bar_attr_tracker(t2).track(t2, t))
308- // }
309- // ```
310- //
311- // Where `foo_module_tracker` is a type tracker that tracks references to the `foo` module.
312- // Because named imports are modelled as `AttrRead`s, the statement `from foo import bar as baz`
313- // is interpreted as if it was an assignment `baz = foo.bar`, which means `baz` gets tracked as a
314- // reference to `foo.bar`, as desired.
315- exists ( ImportExpr imp_expr |
316- not imp_expr .isRelative ( ) and
317- imp_expr .getName ( ) = name and
318- import_node .asCfgNode ( ) .getNode ( ) = imp_expr and
319- // in `import foo.bar` we DON'T want to give a result for `importNode("foo.bar")`,
320- // only for `importNode("foo")`. We exclude those cases with the following clause.
321- not exists ( Import imp | imp .getAName ( ) .getValue ( ) = imp_expr )
266+ private predicate imports ( DataFlow:: Node imp , string name ) {
267+ exists ( ImportExprNode iexpr |
268+ imp .asCfgNode ( ) = iexpr and
269+ not iexpr .getNode ( ) .isRelative ( ) and
270+ name = iexpr .getNode ( ) .getName ( )
322271 )
323272 }
324273
0 commit comments