Python: Adds preliminary modernization

This commit is contained in:
Rebecca Valentine
2020-03-10 08:51:20 -07:00
parent 4c1d76ee9a
commit 160f6cbc15
2 changed files with 24 additions and 4 deletions

View File

@@ -12,8 +12,8 @@
import python
Function iter_method(ClassObject t) {
result = ((FunctionObject)t.lookupAttribute("__iter__")).getFunction()
Function iter_method(ClassValue t) {
result = ((FunctionValue)t.lookup("__iter__")).getScope()
}
predicate is_self(Name value, Function f) {
@@ -28,6 +28,6 @@ predicate returns_non_self(Function f) {
exists(Return r | r.getScope() = f and not exists(r.getValue()))
}
from ClassObject t, Function iter
from ClassValue t, Function iter
where t.isIterator() and iter = iter_method(t) and returns_non_self(iter)
select t, "Class " + t.getName() + " is an iterator but its $@ method does not return 'self'.", iter, iter.getName()

View File

@@ -374,7 +374,7 @@ class CallableValue extends Value {
/** Class representing classes in the Python program, both Python and built-in.
*/
class ClassValue extends Value {
class ClassValue extends Value {
ClassValue() {
this.(ObjectInternal).isClass() = true
@@ -413,6 +413,26 @@ class ClassValue extends Value {
this.hasAttribute("__getitem__")
}
/** Holds if this class is an iterator. */
predicate isIterator() {
this.hasAttribute("__iter__") and
(major_version() = 3 and this.hasAttribute("__next__")
or
/* Because 'next' is a common method name we need to check that an __iter__
* method actually returns this class. This is not needed for Py3 as the
* '__next__' method exists to define a class as an iterator.
*/
major_version() = 2 and this.hasAttribute("next") and
exists(ClassObject other, FunctionObject iter |
other.declaredAttribute("__iter__") = iter |
iter.getAnInferredReturnType() = this
)
)
or
/* This will be redundant when we have C class information */
this = ClassValue::generator()
}
/** Holds if this class is a descriptor. */
predicate isDescriptorType() {
this.hasAttribute("__get__")