Skip to content

Commit 0bf8d4e

Browse files
Exclude 'methods' used in initialisation, and allow self for metaclass methods
1 parent fa76bf3 commit 0bf8d4e

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

python/ql/src/Functions/MethodArgNames.qll

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import python
44
import semmle.python.ApiGraphs
5+
import DataFlow
56

67
/** Holds if `f` is a method of the class `c`. */
78
private predicate methodOfClass(Function f, Class c) { f.getScope() = c }
@@ -34,13 +35,29 @@ private predicate isZopeInterface(Class c) {
3435
.asExpr()
3536
}
3637

38+
/**
39+
* Holds if `f` is used in the initialisation of `c`.
40+
* This means `f` isn't being used as a normal method.
41+
* Ideally it should be a `@staticmethod`; however this wasn't possible prior to Python 3.10.
42+
* We exclude this case from the `not-named-self` query.
43+
* However there is potential for a new query that specifically covers and alerts for this case.
44+
*/
45+
private predicate usedInInit(Function f, Class c) {
46+
methodOfClass(f, c) and
47+
exists(Call call |
48+
call.getScope() = c and
49+
DataFlow::localFlow(DataFlow::exprNode(f.getDefinition()), DataFlow::exprNode(call.getFunc()))
50+
)
51+
}
52+
3753
/** Holds if the first parameter of `f` should be named `self`. */
3854
predicate shouldBeSelf(Function f, Class c) {
3955
methodOfClass(f, c) and
4056
not isStaticMethod(f) and
4157
not isClassMethod(f) and
4258
not isMetaclass(c) and
43-
not isZopeInterface(c)
59+
not isZopeInterface(c) and
60+
not usedInInit(f, c)
4461
}
4562

4663
/** Holds if the first parameter of `f` should be named `cls`. */
@@ -73,8 +90,17 @@ predicate firstArgShouldBeNamedSelfAndIsnt(Function f) {
7390
not firstArgNamedSelf(f)
7491
}
7592

93+
/** Holds if `f` is a regular method of a metaclass, and its first argument is named `self`. */
94+
private predicate metaclassNamedSelf(Function f, Class c) {
95+
methodOfClass(f, c) and
96+
firstArgNamedSelf(f) and
97+
isMetaclass(c) and
98+
not isClassMethod(f)
99+
}
100+
76101
/** Holds if the first parameter of `f` should be named `cls`, but isn't. */
77102
predicate firstArgShouldBeNamedClsAndIsnt(Function f) {
78103
shouldBeCls(f, _) and
79-
not firstArgNamedCls(f)
104+
not firstArgNamedCls(f) and
105+
not metaclassNamedSelf(f, _)
80106
}

0 commit comments

Comments
 (0)