-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathClass.qll
More file actions
171 lines (136 loc) · 5.64 KB
/
Class.qll
File metadata and controls
171 lines (136 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/**
* Provides classes representing Python classes.
*/
overlay[local]
module;
import python
/**
* An (artificial) expression corresponding to a class definition.
* It is recommended to use `ClassDef` instead.
*/
class ClassExpr extends ClassExpr_ {
/** Gets the metaclass expression */
Expr getMetaClass() {
if major_version() = 3
then
exists(Keyword metacls |
this.getAKeyword() = metacls and
metacls.getArg() = "metaclass" and
result = metacls.getValue()
)
else
exists(Assign a |
a = this.getInnerScope().getAStmt() and
a.getATarget().(Name).getId() = "__metaclass__" and
result = a.getValue()
)
}
/** Gets the nth keyword argument of this class definition. */
override DictUnpackingOrKeyword getKeyword(int index) {
result = this.getKeywords().getItem(index)
}
/** Gets a keyword argument of this class definition. */
override DictUnpackingOrKeyword getAKeyword() { result = this.getKeywords().getAnItem() }
override Expr getASubExpression() {
result = this.getABase() or
result = this.getAKeyword().getValue() or
result = this.getKwargs() or
result = this.getStarargs()
}
/** Gets a call corresponding to a decorator of this class definition. */
Call getADecoratorCall() {
result.getArg(0) = this or
result.getArg(0) = this.getADecoratorCall()
}
/** Gets a decorator of this function expression */
Expr getADecorator() { result = this.getADecoratorCall().getFunc() }
override AstNode getAChildNode() {
result = this.getASubExpression()
or
result = this.getInnerScope()
}
/** Gets a tuple (*) argument of this class definition. */
Expr getStarargs() { result = this.getABase().(Starred).getValue() }
/** Gets a dictionary (**) argument of this class definition. */
Expr getKwargs() { result = this.getAKeyword().(DictUnpacking).getValue() }
}
/** A class statement. Note that ClassDef extends Assign as a class definition binds the newly created class */
class ClassDef extends Assign {
/* syntax: class name(...): ... */
ClassDef() {
/* This is an artificial assignment the rhs of which is a (possibly decorated) ClassExpr */
exists(ClassExpr c | this.getValue() = c or this.getValue() = c.getADecoratorCall())
}
override string toString() { result = "ClassDef" }
/** Gets the class for this statement */
Class getDefinedClass() {
exists(ClassExpr c | this.getValue() = c or this.getValue() = c.getADecoratorCall() |
result = c.getInnerScope()
)
}
override Stmt getLastStatement() { result = this.getDefinedClass().getLastStatement() }
}
/** The scope of a class. This is the scope of all the statements within the class definition */
class Class extends Class_, Scope, AstNode {
/** Gets a defined init method of this class */
Function getInitMethod() { result.getScope() = this and result.isInitMethod() }
/** Gets a method defined in this class */
Function getAMethod() { result.getScope() = this }
/** Gets the method defined in this class with the specified name, if any. */
Function getMethod(string name) {
result = this.getAMethod() and
result.getName() = name
}
override Location getLocation() { py_scope_location(result, this) }
/** Gets the scope (module, class or function) in which this class is defined */
override Scope getEnclosingScope() { result = this.getParent().getScope() }
/** Use getEnclosingScope() instead */
override Scope getScope() { result = this.getParent().getScope() }
override string toString() { result = "Class " + this.getName() }
/** Gets the statements forming the body of this class */
override StmtList getBody() { result = Class_.super.getBody() }
/** Gets the nth statement in the class */
override Stmt getStmt(int index) { result = Class_.super.getStmt(index) }
/** Gets a statement in the class */
override Stmt getAStmt() { result = Class_.super.getAStmt() }
/** Gets the name used to define this class */
override string getName() { result = Class_.super.getName() }
/** Holds if this expression may have a side effect (as determined purely from its syntax). */
predicate hasSideEffects() { any() }
/** Holds if this is probably a mixin (has 'mixin' or similar in name or docstring) */
predicate isProbableMixin() {
(
this.getName().toLowerCase().matches("%mixin%")
or
this.getDocString().getText().toLowerCase().matches("%mixin%")
or
this.getDocString().getText().toLowerCase().matches("%mix-in%")
)
}
override AstNode getAChildNode() { result = this.getAStmt() }
/** Gets a decorator of this class. */
Expr getADecorator() { result = this.getParent().getADecorator() }
/** Gets the metaclass expression */
Expr getMetaClass() { result = this.getParent().getMetaClass() }
/** Gets the nth base of this class definition. */
Expr getBase(int index) { result = this.getParent().getBase(index) }
/** Gets a base of this class definition. */
Expr getABase() { result = this.getParent().getABase() }
/**
* Gets the qualified name for this class.
* Should return the same name as the `__qualname__` attribute on classes in Python 3.
*/
string getQualifiedName() {
this.getScope() instanceof Module and result = this.getName()
or
exists(string enclosing_name |
enclosing_name = this.getScope().(Function).getQualifiedName()
or
enclosing_name = this.getScope().(Class).getQualifiedName()
|
result = enclosing_name + "." + this.getName()
)
}
override predicate containsInScope(AstNode inner) { Scope.super.containsInScope(inner) }
override predicate contains(AstNode inner) { Scope.super.contains(inner) }
}