Skip to content

Commit 9d2822c

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 9d2822c

File tree

1 file changed

+39
-44
lines changed

1 file changed

+39
-44
lines changed

python/ql/src/Functions/SignatureSpecialMethods.ql

Lines changed: 39 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -40,75 +40,71 @@ 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+
}
52+
5453
}
5554

5655
predicate incorrect_special_method_defn(
57-
PythonFunctionValue func, string message, boolean show_counts, string name, ClassValue owner
56+
Function func, string message, boolean show_counts, string name
5857
) {
59-
exists(int required | required = argument_count(func, name, owner) |
58+
exists(int required | required = argument_count(name) |
6059
/* actual_non_default <= actual */
61-
if required > func.maxParameters()
60+
if required > func.getMaxPositionalArguments()
6261
then message = "Too few parameters" and show_counts = true
6362
else
64-
if required < func.minParameters()
63+
if required < func.getMinPositionalArguments()
6564
then message = "Too many parameters" and show_counts = true
6665
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
66+
func.getMinPositionalArguments() < required and
67+
not func.hasVarArg() and
68+
message =
69+
(required - func.getMinPositionalArguments()) + " default values(s) will never be used" and
7070
show_counts = false
7171
)
7272
)
7373
}
7474

75-
predicate incorrect_pow(FunctionValue func, string message, boolean show_counts, ClassValue owner) {
76-
owner.declaredAttribute("__pow__") = func and
75+
predicate incorrect_pow(Function func, string message, boolean show_counts) {
7776
(
78-
func.maxParameters() < 2 and message = "Too few parameters" and show_counts = true
77+
func.getMaxPositionalArguments() < 2 and message = "Too few parameters" and show_counts = true
7978
or
80-
func.minParameters() > 3 and message = "Too many parameters" and show_counts = true
79+
func.getMinPositionalArguments() > 3 and message = "Too many parameters" and show_counts = true
8180
or
82-
func.minParameters() < 2 and
83-
message = (2 - func.minParameters()) + " default value(s) will never be used" and
81+
func.getMinPositionalArguments() < 2 and
82+
message = (2 - func.getMinPositionalArguments()) + " default value(s) will never be used" and
8483
show_counts = false
8584
or
86-
func.minParameters() = 3 and
85+
func.getMinPositionalArguments() = 3 and
8786
message = "Third parameter to __pow__ should have a default value" and
8887
show_counts = false
8988
)
9089
}
9190

92-
predicate incorrect_get(FunctionValue func, string message, boolean show_counts, ClassValue owner) {
93-
owner.declaredAttribute("__get__") = func and
91+
predicate incorrect_get(Function func, string message, boolean show_counts) {
9492
(
95-
func.maxParameters() < 3 and message = "Too few parameters" and show_counts = true
93+
func.getMaxPositionalArguments() < 3 and message = "Too few parameters" and show_counts = true
9694
or
97-
func.minParameters() > 3 and message = "Too many parameters" and show_counts = true
95+
func.getMinPositionalArguments() > 3 and message = "Too many parameters" and show_counts = true
9896
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
97+
func.getMinPositionalArguments() < 2 and
98+
not func.hasVarArg() and
99+
message = (2 - func.getMinPositionalArguments()) + " default value(s) will never be used" and
102100
show_counts = false
103101
)
104102
}
105103

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"
104+
string should_have_parameters(string name) {
105+
if name in ["__pow__", "__get__"]
106+
then result = "2 or 3"
107+
else result = argument_count(name).toString()
112108
}
113109

114110
string has_parameters(PythonFunctionValue f) {
@@ -125,19 +121,18 @@ from
125121
PythonFunctionValue f, string message, string sizes, boolean show_counts, string name,
126122
ClassValue owner
127123
where
124+
owner.declaredAttribute(name) = f and
128125
(
129-
incorrect_special_method_defn(f, message, show_counts, name, owner)
126+
incorrect_special_method_defn(f.getScope(), message, show_counts, name)
130127
or
131-
incorrect_pow(f, message, show_counts, owner) and name = "__pow__"
128+
incorrect_pow(f.getScope(), message, show_counts) and name = "__pow__"
132129
or
133-
incorrect_get(f, message, show_counts, owner) and name = "__get__"
130+
incorrect_get(f.getScope(), message, show_counts) and name = "__get__"
134131
) and
135132
(
136133
show_counts = false and sizes = ""
137134
or
138135
show_counts = true and
139-
sizes =
140-
", which has " + has_parameters(f) + ", but should have " +
141-
should_have_parameters(f, name, owner)
136+
sizes = ", which has " + has_parameters(f) + ", but should have " + should_have_parameters(name)
142137
)
143138
select f, message + " for special method " + name + sizes + ", in class $@.", owner, owner.getName()

0 commit comments

Comments
 (0)