Skip to content

Commit 2df8973

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

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
@@ -2068,4 +2068,30 @@ module DuckTyping {
20682068
hasMethod(cls, "__getitem__") and
20692069
(hasMethod(cls, "keys") or hasMethod(cls, "__iter__"))
20702070
}
2071+
2072+
/**
2073+
* Holds if `cls` is a new-style class. In Python 3, all classes are new-style.
2074+
* In Python 2, a class is new-style if it (transitively) inherits from `object`,
2075+
* or has a declared `__metaclass__`, or has an unresolved base class.
2076+
*/
2077+
predicate isNewStyle(Class cls) {
2078+
major_version() = 3
2079+
or
2080+
major_version() = 2 and
2081+
(
2082+
cls.getABase() = API::builtin("object").getAValueReachableFromSource().asExpr()
2083+
or
2084+
isNewStyle(getADirectSuperclass(cls))
2085+
or
2086+
hasUnresolvedBase(cls)
2087+
or
2088+
exists(cls.getMetaClass())
2089+
or
2090+
// Module-level __metaclass__ = type makes all classes in the module new-style
2091+
exists(Assign a |
2092+
a.getScope() = cls.getEnclosingModule() and
2093+
a.getATarget().(Name).getId() = "__metaclass__"
2094+
)
2095+
)
2096+
}
20712097
}

0 commit comments

Comments
 (0)