Skip to content

Commit 5b1e08a

Browse files
committed
Python: Refactor special method query
Moves a bunch of `owner.declaredAttribute(name) = f` instances to the top level, in the process greatly cleaning up the code. The behaviour should be the unchanged. Having done this, there's only one place where we depend on points-to, and that's in the remaining `declaredAttribute` call. This should greatly simplify the move away from points to.
1 parent bf3d9ee commit 5b1e08a

File tree

1 file changed

+38
-44
lines changed

1 file changed

+38
-44
lines changed

python/ql/src/Functions/SignatureSpecialMethods.ql

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -40,75 +40,70 @@ predicate is_ternary_op(string name) {
4040

4141
predicate is_quad_op(string name) { name = "__setslice__" or name = "__exit__" }
4242

43-
int argument_count(PythonFunctionValue f, string name, ClassValue cls) {
44-
cls.declaredAttribute(name) = f and
45-
(
46-
is_unary_op(name) and result = 1
47-
or
48-
is_binary_op(name) and result = 2
49-
or
50-
is_ternary_op(name) and result = 3
51-
or
52-
is_quad_op(name) and result = 4
53-
)
43+
int argument_count(string name) {
44+
is_unary_op(name) and result = 1
45+
or
46+
is_binary_op(name) and result = 2
47+
or
48+
is_ternary_op(name) and result = 3
49+
or
50+
is_quad_op(name) and result = 4
51+
5452
}
5553

5654
predicate incorrect_special_method_defn(
57-
PythonFunctionValue func, string message, boolean show_counts, string name, ClassValue owner
55+
Function func, string message, boolean show_counts, string name
5856
) {
59-
exists(int required | required = argument_count(func, name, owner) |
57+
exists(int required | required = argument_count(name) |
6058
/* actual_non_default <= actual */
61-
if required > func.maxParameters()
59+
if required > func.getMaxPositionalArguments()
6260
then message = "Too few parameters" and show_counts = true
6361
else
64-
if required < func.minParameters()
62+
if required < func.getMinPositionalArguments()
6563
then message = "Too many parameters" and show_counts = true
6664
else (
67-
func.minParameters() < required and
68-
not func.getScope().hasVarArg() and
69-
message = (required - func.minParameters()) + " default values(s) will never be used" and
65+
func.getMinPositionalArguments() < required and
66+
not func.hasVarArg() and
67+
message =
68+
(required - func.getMinPositionalArguments()) + " default values(s) will never be used" and
7069
show_counts = false
7170
)
7271
)
7372
}
7473

75-
predicate incorrect_pow(FunctionValue func, string message, boolean show_counts, ClassValue owner) {
76-
owner.declaredAttribute("__pow__") = func and
74+
predicate incorrect_pow(Function func, string message, boolean show_counts) {
7775
(
78-
func.maxParameters() < 2 and message = "Too few parameters" and show_counts = true
76+
func.getMaxPositionalArguments() < 2 and message = "Too few parameters" and show_counts = true
7977
or
80-
func.minParameters() > 3 and message = "Too many parameters" and show_counts = true
78+
func.getMinPositionalArguments() > 3 and message = "Too many parameters" and show_counts = true
8179
or
82-
func.minParameters() < 2 and
83-
message = (2 - func.minParameters()) + " default value(s) will never be used" and
80+
func.getMinPositionalArguments() < 2 and
81+
message = (2 - func.getMinPositionalArguments()) + " default value(s) will never be used" and
8482
show_counts = false
8583
or
86-
func.minParameters() = 3 and
84+
func.getMinPositionalArguments() = 3 and
8785
message = "Third parameter to __pow__ should have a default value" and
8886
show_counts = false
8987
)
9088
}
9189

92-
predicate incorrect_get(FunctionValue func, string message, boolean show_counts, ClassValue owner) {
93-
owner.declaredAttribute("__get__") = func and
90+
predicate incorrect_get(Function func, string message, boolean show_counts) {
9491
(
95-
func.maxParameters() < 3 and message = "Too few parameters" and show_counts = true
92+
func.getMaxPositionalArguments() < 3 and message = "Too few parameters" and show_counts = true
9693
or
97-
func.minParameters() > 3 and message = "Too many parameters" and show_counts = true
94+
func.getMinPositionalArguments() > 3 and message = "Too many parameters" and show_counts = true
9895
or
99-
func.minParameters() < 2 and
100-
not func.getScope().hasVarArg() and
101-
message = (2 - func.minParameters()) + " default value(s) will never be used" and
96+
func.getMinPositionalArguments() < 2 and
97+
not func.hasVarArg() and
98+
message = (2 - func.getMinPositionalArguments()) + " default value(s) will never be used" and
10299
show_counts = false
103100
)
104101
}
105102

106-
string should_have_parameters(PythonFunctionValue f, string name, ClassValue owner) {
107-
exists(int i | i = argument_count(f, name, owner) | result = i.toString())
108-
or
109-
owner.declaredAttribute(name) = f and
110-
(name = "__get__" or name = "__pow__") and
111-
result = "2 or 3"
103+
string should_have_parameters(string name) {
104+
if name in ["__pow__", "__get__"]
105+
then result = "2 or 3"
106+
else result = argument_count(name).toString()
112107
}
113108

114109
string has_parameters(PythonFunctionValue f) {
@@ -125,19 +120,18 @@ from
125120
PythonFunctionValue f, string message, string sizes, boolean show_counts, string name,
126121
ClassValue owner
127122
where
123+
owner.declaredAttribute(name) = f and
128124
(
129-
incorrect_special_method_defn(f, message, show_counts, name, owner)
125+
incorrect_special_method_defn(f.getScope(), message, show_counts, name)
130126
or
131-
incorrect_pow(f, message, show_counts, owner) and name = "__pow__"
127+
incorrect_pow(f.getScope(), message, show_counts) and name = "__pow__"
132128
or
133-
incorrect_get(f, message, show_counts, owner) and name = "__get__"
129+
incorrect_get(f.getScope(), message, show_counts) and name = "__get__"
134130
) and
135131
(
136132
show_counts = false and sizes = ""
137133
or
138134
show_counts = true and
139-
sizes =
140-
", which has " + has_parameters(f) + ", but should have " +
141-
should_have_parameters(f, name, owner)
135+
sizes = ", which has " + has_parameters(f) + ", but should have " + should_have_parameters(name)
142136
)
143137
select f, message + " for special method " + name + sizes + ", in class $@.", owner, owner.getName()

0 commit comments

Comments
 (0)