-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathOverwritingAttributeInSuperClass.ql
92 lines (85 loc) · 3.05 KB
/
OverwritingAttributeInSuperClass.ql
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
/**
* @name Overwriting attribute in super-class or sub-class
* @description Assignment to self attribute overwrites attribute previously defined in subclass or superclass `__init__` method.
* @kind problem
* @tags reliability
* maintainability
* modularity
* @problem.severity warning
* @sub-severity low
* @precision medium
* @id py/overwritten-inherited-attribute
*/
import python
class InitCallStmt extends ExprStmt {
InitCallStmt() {
exists(Call call, Attribute attr | call = this.getValue() and attr = call.getFunc() |
attr.getName() = "__init__"
)
}
}
predicate overwrites_which(Function subinit, AssignStmt write_attr, string which) {
write_attr.getScope() = subinit and
self_write_stmt(write_attr, _) and
exists(Stmt top | top.contains(write_attr) or top = write_attr |
(
exists(int i, int j, InitCallStmt call | call.getScope() = subinit |
i > j and top = subinit.getStmt(i) and call = subinit.getStmt(j) and which = "superclass"
)
or
exists(int i, int j, InitCallStmt call | call.getScope() = subinit |
i < j and top = subinit.getStmt(i) and call = subinit.getStmt(j) and which = "subclass"
)
)
)
}
predicate self_write_stmt(Stmt s, string attr) {
exists(Attribute a, Name self |
self = a.getObject() and
s.contains(a) and
self.getId() = "self" and
a.getCtx() instanceof Store and
a.getName() = attr
)
}
predicate both_assign_attribute(Stmt s1, Stmt s2, Function f1, Function f2) {
exists(string name |
s1.getScope() = f1 and
s2.getScope() = f2 and
self_write_stmt(s1, name) and
self_write_stmt(s2, name)
)
}
predicate attribute_overwritten(
AssignStmt overwrites, AssignStmt overwritten, string name, string classtype, string classname
) {
exists(
FunctionObject superinit, FunctionObject subinit, ClassObject superclass, ClassObject subclass,
AssignStmt subattr, AssignStmt superattr
|
(
classtype = "superclass" and
classname = superclass.getName() and
overwrites = subattr and
overwritten = superattr
or
classtype = "subclass" and
classname = subclass.getName() and
overwrites = superattr and
overwritten = subattr
) and
/* OK if overwritten in subclass and is a class attribute */
(not exists(superclass.declaredAttribute(name)) or classtype = "subclass") and
superclass.declaredAttribute("__init__") = superinit and
subclass.declaredAttribute("__init__") = subinit and
superclass = subclass.getASuperType() and
overwrites_which(subinit.getFunction(), subattr, classtype) and
both_assign_attribute(subattr, superattr, subinit.getFunction(), superinit.getFunction()) and
self_write_stmt(superattr, name)
)
}
from string classtype, AssignStmt overwrites, AssignStmt overwritten, string name, string classname
where attribute_overwritten(overwrites, overwritten, name, classtype, classname)
select overwrites,
"Assignment overwrites attribute " + name + ", which was previously defined in " + classtype +
" $@.", overwritten, classname