Files
codeql/python/ql/src/Classes/UselessClass.ql
Rasmus Wriedt Larsen 3fe715abb6 Python: Fix query names that inclde __ (dunder)
Without backticks, the text UNDERSCORE UNDERSCORE eq UNDERSCORE UNDERSCORE would
be considered to make things bold in our markdown output, making the query info
look strange.

Example https://codeql.github.com/codeql-query-help/python/py-slots-in-old-style-class/
2021-02-04 15:49:37 +01:00

89 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 = "pop" or
name = "remove" or
name = "discard" or
name = "extend" or
name = "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