Skip to content

Commit 2ebe9e7

Browse files
Update tests, update alert messages
1 parent 65627f8 commit 2ebe9e7

File tree

5 files changed

+71
-22
lines changed

5 files changed

+71
-22
lines changed

python/ql/src/Functions/IncorrectlyOverriddenMethod.ql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/**
2+
* @deprecated
23
* @name Mismatch between signature and use of an overriding method
34
* @description Method has a different signature from the overridden method and, if it were called, would be likely to cause an error.
45
* @kind problem

python/ql/src/Functions/SignatureOverriddenMethod.ql

Lines changed: 58 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,63 @@ string plural(int num, string str) {
2929
num != 1 and result = num.toString() + " " + str + "s"
3030
}
3131

32+
string describeMin(Function func) {
33+
exists(string descr | descr = plural(func.getMinPositionalArguments(), "positional argument") |
34+
if func.getMinPositionalArguments() = func.getMaxPositionalArguments()
35+
then result = descr
36+
else result = "at least " + descr
37+
)
38+
}
39+
40+
string describeMax(Function func) {
41+
if func.hasVarArg()
42+
then result = "arbitrarily many positional arguments"
43+
else
44+
exists(string descr | descr = plural(func.getMaxPositionalArguments(), "positional argument") |
45+
if func.getMinPositionalArguments() = func.getMaxPositionalArguments()
46+
then result = descr
47+
else result = "at most " + descr
48+
)
49+
}
50+
51+
string describeMinShort(Function func) {
52+
exists(string descr | descr = func.getMinPositionalArguments().toString() |
53+
if func.getMinPositionalArguments() = func.getMaxPositionalArguments()
54+
then result = descr
55+
else result = "at least " + descr
56+
)
57+
}
58+
59+
string describeMaxShort(Function func) {
60+
if func.hasVarArg()
61+
then result = "arbitrarily many"
62+
else
63+
exists(string descr | descr = func.getMaxPositionalArguments().toString() |
64+
if func.getMinPositionalArguments() = func.getMaxPositionalArguments()
65+
then result = descr
66+
else result = "at most " + descr
67+
)
68+
}
69+
70+
string describeMaxBound(Function func) {
71+
if func.hasVarArg()
72+
then result = "arbitrarily many"
73+
else result = func.getMaxPositionalArguments().toString()
74+
}
75+
3276
/** Holds if no way to call `base` would be valid for `sub`. The `msg` applies to the `sub method. */
3377
predicate strongSignatureMismatch(Function base, Function sub, string msg) {
3478
overrides(base, sub) and
3579
(
3680
sub.getMinPositionalArguments() > base.getMaxPositionalArguments() and
3781
msg =
38-
"requires " +
39-
plural(sub.getMinPositionalArguments() - base.getMaxPositionalArguments(),
40-
"more positional argument") + " than overridden $@ allows."
82+
"requires " + describeMin(sub) + ", whereas overridden $@ requires " + describeMaxShort(base) +
83+
"."
4184
or
4285
sub.getMaxPositionalArguments() < base.getMinPositionalArguments() and
4386
msg =
44-
"requires " +
45-
plural(base.getMinPositionalArguments() - sub.getMaxPositionalArguments(),
46-
"fewer positional argument") + " than overridden $@ allows."
87+
"requires " + describeMax(sub) + ", whereas overridden $@ requires " + describeMinShort(base) +
88+
"."
4789
)
4890
}
4991

@@ -53,15 +95,13 @@ predicate weakSignatureMismatch(Function base, Function sub, string msg) {
5395
(
5496
sub.getMinPositionalArguments() > base.getMinPositionalArguments() and
5597
msg =
56-
"requires " +
57-
plural(sub.getMinPositionalArguments() - base.getMinPositionalArguments(),
58-
"more positional argument") + " than some possible calls to overridden $@."
98+
"requires " + describeMin(sub) + ", whereas overridden $@ may be called with " +
99+
base.getMinPositionalArguments().toString() + "."
59100
or
60101
sub.getMaxPositionalArguments() < base.getMaxPositionalArguments() and
61102
msg =
62-
"requires " +
63-
plural(base.getMaxPositionalArguments() - sub.getMaxPositionalArguments(),
64-
"fewer positional argument") + " than some possible calls to overridden $@."
103+
"requires " + describeMax(sub) + ", whereas overridden $@ may be called with " +
104+
describeMaxBound(base) + "."
65105
or
66106
sub.getMinPositionalArguments() <= base.getMinPositionalArguments() and
67107
sub.getMaxPositionalArguments() >= base.getMaxPositionalArguments() and
@@ -83,7 +123,9 @@ predicate weakSignatureMismatch(Function base, Function sub, string msg) {
83123
predicate ignore(Function f) {
84124
isClassmethod(f)
85125
or
86-
exists(Function g |
126+
exists(
127+
Function g // other functions with the same name, e.g. @property getters/setters.
128+
|
87129
g.getScope() = f.getScope() and
88130
g.getName() = f.getName() and
89131
g != f
@@ -96,7 +138,7 @@ Function resolveCall(Call call) {
96138
)
97139
}
98140

99-
predicate callViableForEither(Function base, Function sub, Call call) {
141+
predicate callViableForEitherOverride(Function base, Function sub, Call call) {
100142
overrides(base, sub) and
101143
base = resolveCall(call) and
102144
sub = resolveCall(call)
@@ -132,7 +174,7 @@ predicate callMatchesSignature(Function func, Call call) {
132174
}
133175

134176
Call getASignatureMismatchWitness(Function base, Function sub) {
135-
callViableForEither(base, sub, result) and
177+
callViableForEitherOverride(base, sub, result) and
136178
callMatchesSignature(base, result) and
137179
not callMatchesSignature(sub, result)
138180
}
@@ -195,6 +237,7 @@ where
195237
)
196238
or
197239
not exists(getASignatureMismatchWitness(base, sub)) and
240+
call.isNone() and
198241
strongSignatureMismatch(base, sub, msg) and
199242
extraMsg = ""
200243
)
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
| test.py:30:5:30:26 | Function Derived.meth3 | Overriding method 'meth3' has signature mismatch with $@. | test.py:11:5:11:20 | Function Base.meth3 | overridden method |
1+
| test.py:24:5:24:26 | Function meth1 | This method requires 2 positional arguments, whereas overridden $@ requires 1. $@ correctly calls the base method, but does not match the signature of the overriding method. | test.py:5:5:5:20 | Function meth1 | Base.meth1 | test.py:15:9:15:20 | Attribute() | This call |
2+
| test.py:27:5:27:20 | Function meth2 | This method requires 1 positional argument, whereas overridden $@ requires 2 positional arguments. $@ correctly calls the base method, but does not match the signature of the overriding method. | test.py:8:5:8:26 | Function meth2 | Base.meth2 | test.py:18:9:18:21 | Attribute() | This call |
3+
| test.py:30:5:30:26 | Function meth3 | This method requires 2 positional arguments, whereas overridden $@ requires 1. | test.py:11:5:11:20 | Function meth3 | Base.meth3 | file://:0:0:0:0 | (none) | This call |
4+
| test.py:69:5:69:24 | Function meth | This method requires 2 positional arguments, whereas overridden $@ requires 1. | test.py:64:5:64:19 | Function meth | BlameBase.meth | file://:0:0:0:0 | (none) | This call |
5+
| test.py:74:5:74:24 | Function meth | This method requires 2 positional arguments, whereas overridden $@ requires 1. | test.py:64:5:64:19 | Function meth | BlameBase.meth | file://:0:0:0:0 | (none) | This call |
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
Functions/SignatureOverriddenMethod.ql
1+
query: Functions/SignatureOverriddenMethod.ql
2+
postprocess: utils/test/InlineExpectationsTestQuery.ql

python/ql/test/query-tests/Functions/overriding/test.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ def foo(self):
2121

2222
class Derived(Base):
2323

24-
def meth1(self, spam):
24+
def meth1(self, spam): # $Alert[py/inheritance/signature-mismatch] # Has 1 more arg, base called in Base.foo
2525
pass
2626

27-
def meth2(self):
27+
def meth2(self): # $Alert[py/inheritance/signature-mismatch] # Has 1 fewer arg, base called in Base.foo
2828
pass
2929

30-
def meth3(self, eggs): #Incorrectly overridden and not called.
30+
def meth3(self, eggs): # $Alert[py/inheritance/signature-mismatch] # Has 1 more arg. Method is not called.
3131
pass
3232

3333
def bar(self):
@@ -66,12 +66,12 @@ def meth(self):
6666

6767
class Correct1(BlameBase):
6868

69-
def meth(self, arg):
69+
def meth(self, arg): # $Alert[py/inheritance/signature-mismatch] # Has 1 more arg. The incorrect-overriden-method query would alert for the base method in this case.
7070
pass
7171

7272
class Correct2(BlameBase):
7373

74-
def meth(self, arg):
74+
def meth(self, arg): # $Alert[py/inheritance/signature-mismatch] # Has 1 more arg
7575
pass
7676

7777
c = Correct2()

0 commit comments

Comments
 (0)