2
2
3
3
import python
4
4
import semmle.python.ApiGraphs
5
+ import semmle.python.dataflow.new.internal.DataFlowDispatch
5
6
import DataFlow
6
7
7
8
/** Holds if `f` is a method of the class `c`. */
8
- private predicate methodOfClass ( Function f , Class c ) { f .getScope ( ) = c }
9
+ private predicate methodOfClass ( Function f , Class c ) {
10
+ exists ( FunctionDef d | d .getDefinedFunction ( ) = f and d .getScope ( ) = c )
11
+ }
9
12
10
13
/** Holds if `c` is a metaclass. */
11
14
private predicate isMetaclass ( Class c ) {
12
15
c = API:: builtin ( "type" ) .getASubclass * ( ) .asSource ( ) .asExpr ( ) .( ClassExpr ) .getInnerScope ( )
13
16
}
14
17
15
- /** Holds if `f` is a class method. */
16
- private predicate isClassMethod ( Function f ) {
17
- f .getADecorator ( ) = API:: builtin ( "classmethod" ) .asSource ( ) .asExpr ( )
18
- or
19
- f .getName ( ) in [ "__new__" , "__init_subclass__" , "__metaclass__" , "__class_getitem__" ]
20
- }
21
-
22
- /** Holds if `f` is a static method. */
23
- private predicate isStaticMethod ( Function f ) {
24
- f .getADecorator ( ) = API:: builtin ( "staticmethod" ) .asSource ( ) .asExpr ( )
25
- }
26
-
27
18
/** Holds if `c` is a Zope interface. */
28
19
private predicate isZopeInterface ( Class c ) {
29
20
c =
@@ -55,8 +46,8 @@ private predicate usedInInit(Function f, Class c) {
55
46
/** Holds if the first parameter of `f` should be named `self`. */
56
47
predicate shouldBeSelf ( Function f , Class c ) {
57
48
methodOfClass ( f , c ) and
58
- not isStaticMethod ( f ) and
59
- not isClassMethod ( f ) and
49
+ not isStaticmethod ( f ) and
50
+ not isClassmethod ( f ) and
60
51
not isMetaclass ( c ) and
61
52
not isZopeInterface ( c ) and
62
53
not usedInInit ( f , c )
@@ -65,24 +56,29 @@ predicate shouldBeSelf(Function f, Class c) {
65
56
/** Holds if the first parameter of `f` should be named `cls`. */
66
57
predicate shouldBeCls ( Function f , Class c ) {
67
58
methodOfClass ( f , c ) and
68
- not isStaticMethod ( f ) and
59
+ not isStaticmethod ( f ) and
69
60
(
70
- isClassMethod ( f ) and not isMetaclass ( c )
61
+ isClassmethod ( f ) and not isMetaclass ( c )
71
62
or
72
- isMetaclass ( c ) and not isClassMethod ( f )
63
+ isMetaclass ( c ) and not isClassmethod ( f )
73
64
)
74
65
}
75
66
76
67
/** Holds if the first parameter of `f` is named `self`. */
77
68
predicate firstArgNamedSelf ( Function f ) { f .getArgName ( 0 ) = "self" }
78
69
79
- /** Holds if the first parameter of `f` is named `cls`. */
80
- predicate firstArgNamedCls ( Function f ) {
70
+ /** Holds if the first parameter of `f` refers to the class - it is either named `cls`, or it is named `self` and is a method of a metaclass. */
71
+ predicate firstArgRefersToCls ( Function f , Class c ) {
72
+ methodOfClass ( f , c ) and
81
73
exists ( string argname | argname = f .getArgName ( 0 ) |
82
74
argname = "cls"
83
75
or
84
76
/* Not PEP8, but relatively common */
85
77
argname = "mcls"
78
+ or
79
+ /* If c is a metaclass, allow arguments named `self`. */
80
+ argname = "self" and
81
+ isMetaclass ( c )
86
82
)
87
83
}
88
84
@@ -92,17 +88,11 @@ predicate firstArgShouldBeNamedSelfAndIsnt(Function f) {
92
88
not firstArgNamedSelf ( f )
93
89
}
94
90
95
- /** Holds if `f` is a regular method of a metaclass, and its first argument is named `self`. */
96
- private predicate metaclassNamedSelf ( Function f , Class c ) {
97
- methodOfClass ( f , c ) and
98
- firstArgNamedSelf ( f ) and
99
- isMetaclass ( c ) and
100
- not isClassMethod ( f )
101
- }
102
-
103
91
/** Holds if the first parameter of `f` should be named `cls`, but isn't. */
104
- predicate firstArgShouldBeNamedClsAndIsnt ( Function f ) {
105
- shouldBeCls ( f , _) and
106
- not firstArgNamedCls ( f ) and
107
- not metaclassNamedSelf ( f , _)
92
+ predicate firstArgShouldReferToClsAndDoesnt ( Function f ) {
93
+ exists ( Class c |
94
+ methodOfClass ( f , c ) and
95
+ shouldBeCls ( f , c ) and
96
+ not firstArgRefersToCls ( f , c )
97
+ )
108
98
}
0 commit comments