Skip to content

Commit 70a67aa

Browse files
committed
Python: Add DuckTyping::isNewStyle
Approximates the behaviour of `Types::isNewStyle` but without depending on points-to
1 parent 4928947 commit 70a67aa

1 file changed

Lines changed: 26 additions & 0 deletions

File tree

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2047,4 +2047,30 @@ module DuckTyping {
20472047
hasMethod(cls, "__getitem__") and
20482048
(hasMethod(cls, "keys") or hasMethod(cls, "__iter__"))
20492049
}
2050+
2051+
/**
2052+
* Holds if `cls` is a new-style class. In Python 3, all classes are new-style.
2053+
* In Python 2, a class is new-style if it (transitively) inherits from `object`,
2054+
* or has a declared `__metaclass__`, or has an unresolved base class.
2055+
*/
2056+
predicate isNewStyle(Class cls) {
2057+
major_version() = 3
2058+
or
2059+
major_version() = 2 and
2060+
(
2061+
cls.getABase() = API::builtin("object").getAValueReachableFromSource().asExpr()
2062+
or
2063+
isNewStyle(getADirectSuperclass(cls))
2064+
or
2065+
hasUnresolvedBase(cls)
2066+
or
2067+
exists(cls.getMetaClass())
2068+
or
2069+
// Module-level __metaclass__ = type makes all classes in the module new-style
2070+
exists(Assign a |
2071+
a.getScope() = cls.getEnclosingModule() and
2072+
a.getATarget().(Name).getId() = "__metaclass__"
2073+
)
2074+
)
2075+
}
20502076
}

0 commit comments

Comments
 (0)