Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e54c925

Browse files
committed
Python: Greatly simplify imports/2 predicate
1 parent d01d7ee commit e54c925

1 file changed

Lines changed: 8 additions & 59 deletions

File tree

python/ql/src/semmle/python/ApiGraphs.qll

Lines changed: 8 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)