Files
codeql/python/ql/src/Classes/EqualsOrNotEquals.ql
Taus Brock-Nannestad f07a7bf8cf Python: Autoformat everything using qlformat.
Will need subsequent PRs fixing up test failures (due to deprecated
methods moving around), but other than that everything should be
straight-forward.
2020-07-07 15:43:52 +02:00

49 lines
1.7 KiB
Plaintext

/**
* @name Inconsistent equality and inequality
* @description Defining only an equality method or an inequality method for a class violates the object model.
* @kind problem
* @tags reliability
* correctness
* @problem.severity warning
* @sub-severity high
* @precision very-high
* @id py/inconsistent-equality
*/
import python
import Equality
string equals_or_ne() { result = "__eq__" or result = "__ne__" }
predicate total_ordering(Class cls) {
exists(Attribute a | a = cls.getADecorator() | a.getName() = "total_ordering")
or
exists(Name n | n = cls.getADecorator() | n.getId() = "total_ordering")
}
CallableValue implemented_method(ClassValue c, string name) {
result = c.declaredAttribute(name) and name = equals_or_ne()
}
string unimplemented_method(ClassValue c) {
not c.declaresAttribute(result) and result = equals_or_ne()
}
predicate violates_equality_contract(
ClassValue c, string present, string missing, CallableValue method
) {
missing = unimplemented_method(c) and
method = implemented_method(c, present) and
not c.failedInference(_) and
not total_ordering(c.getScope()) and
/* Python 3 automatically implements __ne__ if __eq__ is defined, but not vice-versa */
not (major_version() = 3 and present = "__eq__" and missing = "__ne__") and
not method.getScope() instanceof DelegatingEqualityMethod and
not c.lookup(missing).(CallableValue).getScope() instanceof DelegatingEqualityMethod
}
from ClassValue c, string present, string missing, CallableValue method
where violates_equality_contract(c, present, missing, method)
select method, "Class $@ implements " + present + " but does not implement " + missing + ".", c,
c.getName()