Python: Fix points-to for unrelated modules with the same name.#3628
Python: Fix points-to for unrelated modules with the same name.#3628tausbn wants to merge 4 commits into
Conversation
|
You can make |
Git was getting a bit confused, and thinking an init file in `copy1` was being renamed into its counterpart in `copy2`. This should avoid that problem.
In general, we cannot expect overlapping modules to be disambiguated based on the _packages_ they reside in (as they may be inside directories that cannot be interpreted as packages). To better model this, I have changed the names from `copy1` to `copy-1` etc. This also cleans up the test case a bit. Note that it still contains twice as many results as we want.
Basically, this predicate looks for a common `Container` that contains both the module itself and the module being imported. In general there will be many such containers (since if a given container has this property, then so does its parent), so we require that the container itself is "close enough" to properly disambiguate the imported module based solely on its name.
RasmusWL
left a comment
There was a problem hiding this comment.
I got going with the reviewing before I noticed the WIP label. If it's still so much a WIP that you don't want a review, you can just convert it to a draft pr 😉
| /* Holds if `import name` will import the module `m`. */ | ||
| cached | ||
| predicate module_imported_as(ModuleObjectInternal m, string name) { | ||
| deprecated predicate module_imported_as(ModuleObjectInternal m, string name) { |
There was a problem hiding this comment.
The comment should say what predicate should be used instead.
| predicate module_imported_as(ModuleObjectInternal m, string name) { | ||
| deprecated predicate module_imported_as(ModuleObjectInternal m, string name) { | ||
| /* Normal imports */ | ||
| m.getName() = name |
There was a problem hiding this comment.
nitpick: Can the body of this method be replaced with module_imported_as_with_context(m, name, _)? (that would be a bit more clean in my opinion)
| c = mod.getPath().getParent*() and | ||
| imp.getEnclosingModule() = this and | ||
| imp.getAnImportedModuleName() = mod.getName() and | ||
| count(Module other | other.getName() = mod.getName() and other.getPath().getParent*() = c) = 1 |
There was a problem hiding this comment.
I have a slight recollection of strictcount being preferred to count whenever possible. I don't quite remember why, so we'll have to dig that up tomorrow.
| count(Module other | other.getName() = mod.getName() and other.getPath().getParent*() = c) = 1 | |
| strictcount(Module other | other.getName() = mod.getName() and other.getPath().getParent*() = c) = 1 |
The setup for the test case is as follows:
In both cases,
module/test.pydefines a variable (i.e. module attribute) namedvaluewith the value1and2respectively. The__init__.pyfiles are empty (needed in order to getmoduleto be a package in Python 2).Each of the
test1.pyandtest2.pyfiles importvaluefrom their local version ofmodule.test, and print the value.As the test shows, we are getting two potential values for
valuein each of these imports. One is the correct one, and one is from the other copy.The trouble here is that we have an implicit assumption that modules are uniquely determined by their names. This means even something like
getPackagemay pick the wrong module, as it just tests whether the right relationship exists between thegetNames of the relevant modules.I think the best way of addressing this is to introduce a notion of "fully qualified name". In the above test example this would result in the full names
copy1.module.testandcopy2.module.test, and these would then be sufficiently disambiguated.