Skip to content

Commit 160f6cb

Browse files
committed
Python: Adds preliminary modernization
1 parent 4c1d76e commit 160f6cb

File tree

2 files changed

+24
-4
lines changed

2 files changed

+24
-4
lines changed

python/ql/src/Functions/IterReturnsNonSelf.ql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
import python
1414

15-
Function iter_method(ClassObject t) {
16-
result = ((FunctionObject)t.lookupAttribute("__iter__")).getFunction()
15+
Function iter_method(ClassValue t) {
16+
result = ((FunctionValue)t.lookup("__iter__")).getScope()
1717
}
1818

1919
predicate is_self(Name value, Function f) {
@@ -28,6 +28,6 @@ predicate returns_non_self(Function f) {
2828
exists(Return r | r.getScope() = f and not exists(r.getValue()))
2929
}
3030

31-
from ClassObject t, Function iter
31+
from ClassValue t, Function iter
3232
where t.isIterator() and iter = iter_method(t) and returns_non_self(iter)
3333
select t, "Class " + t.getName() + " is an iterator but its $@ method does not return 'self'.", iter, iter.getName()

python/ql/src/semmle/python/objects/ObjectAPI.qll

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ class CallableValue extends Value {
374374

375375
/** Class representing classes in the Python program, both Python and built-in.
376376
*/
377-
class ClassValue extends Value {
377+
class ClassValue extends Value {
378378

379379
ClassValue() {
380380
this.(ObjectInternal).isClass() = true
@@ -413,6 +413,26 @@ class ClassValue extends Value {
413413
this.hasAttribute("__getitem__")
414414
}
415415

416+
/** Holds if this class is an iterator. */
417+
predicate isIterator() {
418+
this.hasAttribute("__iter__") and
419+
(major_version() = 3 and this.hasAttribute("__next__")
420+
or
421+
/* Because 'next' is a common method name we need to check that an __iter__
422+
* method actually returns this class. This is not needed for Py3 as the
423+
* '__next__' method exists to define a class as an iterator.
424+
*/
425+
major_version() = 2 and this.hasAttribute("next") and
426+
exists(ClassObject other, FunctionObject iter |
427+
other.declaredAttribute("__iter__") = iter |
428+
iter.getAnInferredReturnType() = this
429+
)
430+
)
431+
or
432+
/* This will be redundant when we have C class information */
433+
this = ClassValue::generator()
434+
}
435+
416436
/** Holds if this class is a descriptor. */
417437
predicate isDescriptorType() {
418438
this.hasAttribute("__get__")

0 commit comments

Comments
 (0)