mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
Merge pull request #1840 from markshannon/python-better-hasattribute-handling
Python: Add 'hasAttribute' predicate to ObjectInternal and Value.
This commit is contained in:
@@ -97,6 +97,12 @@ abstract class ClassObjectInternal extends ObjectInternal {
|
||||
/* Classes aren't usually iterable, but can e.g. Enums */
|
||||
override ObjectInternal getIterNext() { result = ObjectInternal::unknown() }
|
||||
|
||||
override predicate hasAttribute(string name) {
|
||||
this.getClassDeclaration().declaresAttribute(name)
|
||||
or
|
||||
Types::getBase(this, _).hasAttribute(name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Class representing Python source classes */
|
||||
|
||||
@@ -59,6 +59,18 @@ abstract class ModuleObjectInternal extends ObjectInternal {
|
||||
/* Modules aren't iterable */
|
||||
override ObjectInternal getIterNext() { none() }
|
||||
|
||||
/** Holds if this module "exports" name.
|
||||
* That is, does it define `name` in `__all__` or is
|
||||
* `__all__` not defined and `name` a global variable that does not start with "_"
|
||||
* This is the set of names imported by `from ... import *`.
|
||||
*/
|
||||
predicate exports(string name) {
|
||||
not this.(ModuleObjectInternal).attribute("__all__", _, _) and this.hasAttribute(name)
|
||||
and not name.charAt(0) = "_"
|
||||
or
|
||||
py_exports(this.getSourceModule(), name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A class representing built-in modules */
|
||||
@@ -209,6 +221,13 @@ class PackageObjectInternal extends ModuleObjectInternal, TPackageObject {
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this value has the attribute `name` */
|
||||
override predicate hasAttribute(string name) {
|
||||
this.getInitModule().hasAttribute(name)
|
||||
or
|
||||
exists(this.submodule(name))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A class representing Python modules */
|
||||
@@ -261,6 +280,24 @@ class PythonModuleObjectInternal extends ModuleObjectInternal, TPythonModule {
|
||||
result = this.getSourceModule().getEntryNode()
|
||||
}
|
||||
|
||||
/** Holds if this value has the attribute `name` */
|
||||
override predicate hasAttribute(string name) {
|
||||
name = "__name__"
|
||||
or
|
||||
this.getSourceModule().(ImportTimeScope).definesName(name)
|
||||
or
|
||||
exists(ModuleObjectInternal mod, ImportStarNode imp |
|
||||
PointsToInternal::pointsTo(imp, _, mod, _) and
|
||||
imp.getScope() = this.getSourceModule() and
|
||||
mod.exports(name)
|
||||
)
|
||||
or
|
||||
exists(ObjectInternal defined |
|
||||
this.attribute(name, defined, _) and
|
||||
not defined instanceof UndefinedInternal
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** A class representing a module that is missing from the DB, but inferred to exists from imports. */
|
||||
|
||||
@@ -94,6 +94,11 @@ class Value extends TObject {
|
||||
result = this.(ObjectInternal).getName()
|
||||
}
|
||||
|
||||
/** Holds if this value has the attribute `name` */
|
||||
predicate hasAttribute(string name) {
|
||||
this.(ObjectInternal).hasAttribute(name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Class representing modules in the Python program
|
||||
@@ -111,10 +116,7 @@ class ModuleValue extends Value {
|
||||
* This is the set of names imported by `from ... import *`.
|
||||
*/
|
||||
predicate exports(string name) {
|
||||
not this.(ModuleObjectInternal).attribute("__all__", _, _) and exists(this.attr(name))
|
||||
and not name.charAt(0) = "_"
|
||||
or
|
||||
py_exports(this.getScope(), name)
|
||||
PointsTo::moduleExports(this, name)
|
||||
}
|
||||
|
||||
/** Gets the scope for this module, provided that it is a Python module. */
|
||||
|
||||
@@ -182,6 +182,11 @@ class ObjectInternal extends TObject {
|
||||
*/
|
||||
abstract ObjectInternal getIterNext();
|
||||
|
||||
/** Holds if this value has the attribute `name` */
|
||||
predicate hasAttribute(string name) {
|
||||
this.(ObjectInternal).attribute(name, _, _)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -166,6 +166,10 @@ module PointsTo {
|
||||
)
|
||||
}
|
||||
|
||||
cached predicate moduleExports(ModuleObjectInternal mod, string name) {
|
||||
InterModulePointsTo::moduleExportsBoolean(mod, name) = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cached module PointsToInternal {
|
||||
|
||||
@@ -151,7 +151,7 @@ class ClassObject extends Object {
|
||||
|
||||
/** Whether this class has a attribute named `name`, either declared or inherited.*/
|
||||
predicate hasAttribute(string name) {
|
||||
Types::getMro(theClass()).getAnItem().getClassDeclaration().declaresAttribute(name)
|
||||
theClass().hasAttribute(name)
|
||||
}
|
||||
|
||||
/** Whether it is impossible to know all the attributes of this class. Usually because it is
|
||||
|
||||
@@ -51,9 +51,8 @@ abstract class ModuleObject extends Object {
|
||||
result = this.getAttribute(name)
|
||||
}
|
||||
|
||||
|
||||
predicate hasAttribute(string name) {
|
||||
exists(theModule().attr(name))
|
||||
theModule().hasAttribute(name)
|
||||
}
|
||||
|
||||
predicate attributeRefersTo(string name, Object obj, ControlFlowNode origin) {
|
||||
|
||||
Reference in New Issue
Block a user