Python: Port a few queries to new API.

This commit is contained in:
Mark Shannon
2019-07-26 12:00:14 +01:00
parent fc4bb028b7
commit 4b242ddc86
11 changed files with 69 additions and 55 deletions

View File

@@ -13,19 +13,19 @@
import python
FunctionObject defines_equality(ClassObject c, string name) {
CallableValue defines_equality(ClassValue c, string name) {
(name = "__eq__" or major_version() = 2 and name = "__cmp__")
and
result = c.declaredAttribute(name)
}
FunctionObject implemented_method(ClassObject c, string name) {
CallableValue implemented_method(ClassValue c, string name) {
result = defines_equality(c, name)
or
result = c.declaredAttribute("__hash__") and name = "__hash__"
}
string unimplemented_method(ClassObject c) {
string unimplemented_method(ClassValue c) {
not exists(defines_equality(c, _)) and
(result = "__eq__" and major_version() = 3 or major_version() = 2 and result = "__eq__ or __cmp__")
or
@@ -33,14 +33,21 @@ string unimplemented_method(ClassObject c) {
not c.declaresAttribute(result) and result = "__hash__" and major_version() = 2
}
predicate violates_hash_contract(ClassObject c, string present, string missing, Object method) {
not c.unhashable() and
missing = unimplemented_method(c) and
method = implemented_method(c, present) and
not c.unknowableAttributes()
/** Holds if this class is unhashable */
predicate unhashable(ClassValue cls) {
cls.lookup("__hash__") = Value::named("None")
or
cls.lookup("__hash__").(CallableValue).neverReturns()
}
from ClassObject c, string present, string missing, FunctionObject method
predicate violates_hash_contract(ClassValue c, string present, string missing, Value method) {
not unhashable(c) and
missing = unimplemented_method(c) and
method = implemented_method(c, present) and
not c.failedInference(_)
}
from ClassValue c, string present, string missing, CallableValue method
where violates_hash_contract(c, present, missing, method) and
exists(c.getPyClass()) // Suppress results that aren't from source
exists(c.getScope()) // Suppress results that aren't from source
select method, "Class $@ implements " + present + " but does not define " + missing + ".", c, c.getName()

View File

@@ -25,26 +25,26 @@ predicate total_ordering(Class cls) {
n.getId() = "total_ordering")
}
FunctionObject implemented_method(ClassObject c, string name) {
CallableValue implemented_method(ClassValue c, string name) {
result = c.declaredAttribute(name) and name = equals_or_ne()
}
string unimplemented_method(ClassObject c) {
string unimplemented_method(ClassValue c) {
not c.declaresAttribute(result) and result = equals_or_ne()
}
predicate violates_equality_contract(ClassObject c, string present, string missing, FunctionObject method) {
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.unknowableAttributes() and
not total_ordering(c.getPyClass()) 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.getFunction() instanceof DelegatingEqualityMethod and
not c.lookupAttribute(missing).(FunctionObject).getFunction() instanceof DelegatingEqualityMethod
not method.getScope() instanceof DelegatingEqualityMethod and
not c.lookup(missing).(CallableValue).getScope() instanceof DelegatingEqualityMethod
}
from ClassObject c, string present, string missing, FunctionObject method
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()

View File

@@ -27,25 +27,25 @@ string ordering_name(int n) {
result = "__ge__" and n = 4
}
predicate overrides_ordering_method(ClassObject c, string name) {
predicate overrides_ordering_method(ClassValue c, string name) {
name = ordering_name(_) and
(
c.declaresAttribute(name)
or
exists(ClassObject sup |
sup = c.getASuperType() and not sup = theObjectType() |
exists(ClassValue sup |
sup = c.getASuperType() and not sup = Value::named("object") |
sup.declaresAttribute(name)
)
)
}
string unimplemented_ordering(ClassObject c, int n) {
not c = theObjectType() and
string unimplemented_ordering(ClassValue c, int n) {
not c = Value::named("object") and
not overrides_ordering_method(c, result) and
result = ordering_name(n)
}
string unimplemented_ordering_methods(ClassObject c, int n) {
string unimplemented_ordering_methods(ClassValue c, int n) {
n = 0 and result = "" and exists(unimplemented_ordering(c, _))
or
exists(string prefix, int nm1 |
@@ -58,14 +58,14 @@ string unimplemented_ordering_methods(ClassObject c, int n) {
)
}
Object ordering_method(ClassObject c, string name) {
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)
}
from ClassObject c, Object ordering, string name
where not c.unknowableAttributes() and
not total_ordering(c.getPyClass())
from ClassValue c, Value ordering, string name
where not c.failedInference(_) and
not total_ordering(c.getScope())
and ordering = ordering_method(c, name) and
exists(unimplemented_ordering(c, _))