mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
85 lines
2.3 KiB
Plaintext
85 lines
2.3 KiB
Plaintext
/**
|
|
* @name Useless class
|
|
* @description Class only defines one public method (apart from `__init__` or `__new__`) and should be replaced by a function
|
|
* @kind problem
|
|
* @tags maintainability
|
|
* useless-code
|
|
* @problem.severity recommendation
|
|
* @sub-severity low
|
|
* @precision medium
|
|
* @id py/useless-class
|
|
*/
|
|
|
|
import python
|
|
|
|
predicate fewer_than_two_public_methods(Class cls, int methods) {
|
|
(methods = 0 or methods = 1) and
|
|
methods = count(Function f | f = cls.getAMethod() and not f = cls.getInitMethod())
|
|
}
|
|
|
|
predicate does_not_define_special_method(Class cls) {
|
|
not exists(Function f | f = cls.getAMethod() and f.isSpecialMethod())
|
|
}
|
|
|
|
predicate no_inheritance(Class c) {
|
|
not exists(ClassValue cls, ClassValue other |
|
|
cls.getScope() = c and
|
|
other != ClassValue::object()
|
|
|
|
|
other.getABaseType() = cls or
|
|
cls.getABaseType() = other
|
|
) and
|
|
not exists(Expr base | base = c.getABase() |
|
|
not base instanceof Name or base.(Name).getId() != "object"
|
|
)
|
|
}
|
|
|
|
predicate is_decorated(Class c) { exists(c.getADecorator()) }
|
|
|
|
predicate is_stateful(Class c) {
|
|
exists(Function method, ExprContext ctx |
|
|
method.getScope() = c and
|
|
(ctx instanceof Store or ctx instanceof AugStore)
|
|
|
|
|
exists(Subscript s | s.getScope() = method and s.getCtx() = ctx)
|
|
or
|
|
exists(Attribute a | a.getScope() = method and a.getCtx() = ctx)
|
|
)
|
|
or
|
|
exists(Function method, Call call, Attribute a, string name |
|
|
method.getScope() = c and
|
|
call.getScope() = method and
|
|
call.getFunc() = a and
|
|
a.getName() = name
|
|
|
|
|
name in ["pop", "remove", "discard", "extend", "append"]
|
|
)
|
|
}
|
|
|
|
predicate useless_class(Class c, int methods) {
|
|
c.isTopLevel() and
|
|
c.isPublic() and
|
|
no_inheritance(c) and
|
|
fewer_than_two_public_methods(c, methods) and
|
|
does_not_define_special_method(c) and
|
|
not c.isProbableMixin() and
|
|
not is_decorated(c) and
|
|
not is_stateful(c)
|
|
}
|
|
|
|
from Class c, int methods, string msg
|
|
where
|
|
useless_class(c, methods) and
|
|
(
|
|
methods = 1 and
|
|
msg =
|
|
"Class " + c.getName() +
|
|
" defines only one public method, which should be replaced by a function."
|
|
or
|
|
methods = 0 and
|
|
msg =
|
|
"Class " + c.getName() +
|
|
" defines no public methods and could be replaced with a namedtuple or dictionary."
|
|
)
|
|
select c, msg
|