Content-Length: 345931 | pFad | http://github.com/github/codeql/pull/20038/commits/fccdc30ac544ca6af17c132b69814543102d969f

08 Python: Modernize 3 quality queries for comparison methods by joefarebrother · Pull Request #20038 · github/codeql · GitHub
Skip to content

Python: Modernize 3 quality queries for comparison methods #20038

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Modernize incomplete ordering query
  • Loading branch information
joefarebrother committed Jul 9, 2025
commit fccdc30ac544ca6af17c132b69814543102d969f
80 changes: 32 additions & 48 deletions python/ql/src/Classes/IncompleteOrdering.ql
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
* @name Incomplete ordering
* @description Class defines one or more ordering method but does not define all 4 ordering comparison methods
* @kind problem
* @tags reliability
* @tags quality
* reliability
* correctness
* @problem.severity warning
* @sub-severity low
Expand All @@ -11,63 +12,46 @@
*/

import python
import semmle.python.dataflow.new.internal.DataFlowDispatch
import semmle.python.ApiGraphs

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")
}

string ordering_name(int n) {
result = "__lt__" and n = 1
or
result = "__le__" and n = 2
or
result = "__gt__" and n = 3
or
result = "__ge__" and n = 4
predicate totalOrdering(Class cls) {
cls.getADecorator() =
API::moduleImport("functools").getMember("total_ordering").asSource().asExpr()
}

predicate overrides_ordering_method(ClassValue c, string name) {
name = ordering_name(_) and
(
c.declaresAttribute(name)
or
exists(ClassValue sup | sup = c.getASuperType() and not sup = Value::named("object") |
sup.declaresAttribute(name)
)
)
Function getMethod(Class cls, string name) {
result = cls.getAMethod() and
result.getName() = name
}

string unimplemented_ordering(ClassValue c, int n) {
not c = Value::named("object") and
not overrides_ordering_method(c, result) and
result = ordering_name(n)
predicate definesStrictOrdering(Class cls, Function meth) {
meth = getMethod(cls, "__lt__")
or
not exists(getMethod(cls, "__lt__")) and
meth = getMethod(cls, "__gt__")
}

string unimplemented_ordering_methods(ClassValue c, int n) {
n = 0 and result = "" and exists(unimplemented_ordering(c, _))
predicate definesNonStrictOrdering(Class cls, Function meth) {
meth = getMethod(cls, "__le__")
or
exists(string prefix, int nm1 | n = nm1 + 1 and prefix = unimplemented_ordering_methods(c, nm1) |
prefix = "" and result = unimplemented_ordering(c, n)
or
result = prefix and not exists(unimplemented_ordering(c, n)) and n < 5
or
prefix != "" and result = prefix + " or " + unimplemented_ordering(c, n)
)
not exists(getMethod(cls, "__le__")) and
meth = getMethod(cls, "__ge__")
}

Value ordering_method(ClassValue c, string name) {
/* If class doesn't declare a method then don't blame this class (the superclass will be blamed). */
name = ordering_name(_) and result = c.declaredAttribute(name)
predicate missingComparison(Class cls, Function defined, string missing) {
definesStrictOrdering(cls, defined) and
not definesNonStrictOrdering(getADirectSuperclass*(cls), _) and
missing = "__le__ or __ge__"
or
definesNonStrictOrdering(cls, defined) and
not definesStrictOrdering(getADirectSuperclass*(cls), _) and
missing = "__lt__ or __gt__"
}

from ClassValue c, Value ordering, string name
from Class cls, Function defined, string missing
where
not c.failedInference(_) and
not total_ordering(c.getScope()) and
ordering = ordering_method(c, name) and
exists(unimplemented_ordering(c, _))
select c,
"Class " + c.getName() + " implements $@, but does not implement " +
unimplemented_ordering_methods(c, 4) + ".", ordering, name
not totalOrdering(cls) and
missingComparison(cls, defined, missing)
select cls, "This class implements $@, but does not implement an " + missing + " method.", defined,
defined.getName()








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/github/codeql/pull/20038/commits/fccdc30ac544ca6af17c132b69814543102d969f

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy