Exclude 'methods' used in initialisation, and allow self for metaclass methods

This commit is contained in:
Joe Farebrother
2025-01-30 13:55:49 +00:00
parent fa76bf3c9f
commit 0bf8d4ec4b

View File

@@ -2,6 +2,7 @@
import python
import semmle.python.ApiGraphs
import DataFlow
/** Holds if `f` is a method of the class `c`. */
private predicate methodOfClass(Function f, Class c) { f.getScope() = c }
@@ -34,13 +35,29 @@ private predicate isZopeInterface(Class c) {
.asExpr()
}
/**
* Holds if `f` is used in the initialisation of `c`.
* This means `f` isn't being used as a normal method.
* Ideally it should be a `@staticmethod`; however this wasn't possible prior to Python 3.10.
* We exclude this case from the `not-named-self` query.
* However there is potential for a new query that specifically covers and alerts for this case.
*/
private predicate usedInInit(Function f, Class c) {
methodOfClass(f, c) and
exists(Call call |
call.getScope() = c and
DataFlow::localFlow(DataFlow::exprNode(f.getDefinition()), DataFlow::exprNode(call.getFunc()))
)
}
/** Holds if the first parameter of `f` should be named `self`. */
predicate shouldBeSelf(Function f, Class c) {
methodOfClass(f, c) and
not isStaticMethod(f) and
not isClassMethod(f) and
not isMetaclass(c) and
not isZopeInterface(c)
not isZopeInterface(c) and
not usedInInit(f, c)
}
/** Holds if the first parameter of `f` should be named `cls`. */
@@ -73,8 +90,17 @@ predicate firstArgShouldBeNamedSelfAndIsnt(Function f) {
not firstArgNamedSelf(f)
}
/** Holds if `f` is a regular method of a metaclass, and its first argument is named `self`. */
private predicate metaclassNamedSelf(Function f, Class c) {
methodOfClass(f, c) and
firstArgNamedSelf(f) and
isMetaclass(c) and
not isClassMethod(f)
}
/** Holds if the first parameter of `f` should be named `cls`, but isn't. */
predicate firstArgShouldBeNamedClsAndIsnt(Function f) {
shouldBeCls(f, _) and
not firstArgNamedCls(f)
not firstArgNamedCls(f) and
not metaclassNamedSelf(f, _)
}