Python points-to: Handle subclassing of ABCs.

This commit is contained in:
Mark Shannon
2019-04-17 12:32:40 +01:00
parent 2d4f64f2e5
commit ddc4ada130
6 changed files with 68 additions and 27 deletions

View File

@@ -62,6 +62,19 @@ abstract class ClassObjectInternal extends ObjectInternal {
override int length() { none() }
boolean isIterableSubclass() {
this = ObjectInternal::builtin("list") and result = true
or
this = ObjectInternal::builtin("set") and result = true
or
this = ObjectInternal::builtin("dict") and result = true
or
this != ObjectInternal::builtin("list") and
this != ObjectInternal::builtin("set") and
this != ObjectInternal::builtin("dict") and
result = false
}
}
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {

View File

@@ -31,7 +31,7 @@ class SpecificInstanceInternal extends TSpecificInstance, ObjectInternal {
override boolean isClass() { result = false }
override boolean isComparable() { result = false }
override boolean isComparable() { result = true }
override ObjectInternal getClass() {
this = TSpecificInstance(_, result, _)

View File

@@ -159,6 +159,8 @@ predicate literal_instantiation(ControlFlowNode n, ClassObjectInternal cls, Poin
or
n instanceof DictNode and cls = ObjectInternal::builtin("dict")
or
n instanceof SetNode and cls = ObjectInternal::builtin("set")
or
n.getNode() instanceof ImaginaryLiteral and cls = ObjectInternal::builtin("complex")
)
}

View File

@@ -1746,10 +1746,23 @@ cached module Types {
or
mro.getItem(n) = sup and result = true
or
mro.getItem(n) != sup and result = mroContains(mro, sup, n+1)
mro.getItem(n) = abc_to_concrete(sup) and result = true
or
mro.getItem(n) != sup and sup != AbstractBaseClass::named("Iterable") and
mro.getItem(n) != abc_to_concrete(sup) and result = mroContains(mro, sup, n+1)
or
sup = AbstractBaseClass::named("Iterable") and result = mro.getItem(n).isIterableSubclass()
)
}
private ClassObjectInternal abc_to_concrete(ClassObjectInternal c) {
c = AbstractBaseClass::named("Sequence") and result = ObjectInternal::builtin("list")
or
c = AbstractBaseClass::named("Set") and result = ObjectInternal::builtin("set")
or
c = AbstractBaseClass::named("Mapping") and result = ObjectInternal::builtin("dict")
}
cached boolean hasAttr(ObjectInternal cls, string name) {
result = mroHasAttr(Types::getMro(cls), name, 0)
}
@@ -1776,6 +1789,19 @@ cached module Types {
}
module AbstractBaseClass {
ClassObjectInternal named(string name) {
exists(ModuleObjectInternal m |
m.getName() = "_abcoll"
or
m.getName() = "_collections_abc"
|
m.attribute(name, result, _)
)
}
}
module AttributePointsTo {
predicate pointsTo(AttrNode f, Context context, ObjectInternal value, ControlFlowNode origin) {