Files
codeql/python/ql/src/Classes/OverwritingAttributeInSuperClass.ql
2018-11-19 15:10:42 +00:00

72 lines
3.1 KiB
Plaintext

/**
* @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