Skip to content

Commit 2fce1b3

Browse files
committed
Python: Add DuckTyping::isNewStyle
Approximates the behaviour of `Types::isNewStyle` but without depending on points-to
1 parent 576b560 commit 2fce1b3

File tree

1 file changed

+26
-0
lines changed

1 file changed

+26
-0
lines changed

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,4 +2012,30 @@ module DuckTyping {
20122012
hasMethod(cls, "__getitem__") and
20132013
(hasMethod(cls, "keys") or hasMethod(cls, "__iter__"))
20142014
}
2015+
2016+
/**
2017+
* Holds if `cls` is a new-style class. In Python 3, all classes are new-style.
2018+
* In Python 2, a class is new-style if it (transitively) inherits from `object`,
2019+
* or has a declared `__metaclass__`, or has an unresolved base class.
2020+
*/
2021+
predicate isNewStyle(Class cls) {
2022+
major_version() = 3
2023+
or
2024+
major_version() = 2 and
2025+
(
2026+
cls.getABase() = API::builtin("object").getAValueReachableFromSource().asExpr()
2027+
or
2028+
isNewStyle(getADirectSuperclass(cls))
2029+
or
2030+
hasUnresolvedBase(cls)
2031+
or
2032+
exists(cls.getMetaClass())
2033+
or
2034+
// Module-level __metaclass__ = type makes all classes in the module new-style
2035+
exists(Assign a |
2036+
a.getScope() = cls.getEnclosingModule() and
2037+
a.getATarget().(Name).getId() = "__metaclass__"
2038+
)
2039+
)
2040+
}
20152041
}

0 commit comments

Comments
 (0)