Skip to content

Commit f709713

Browse files
Rank multiple calls so only the first 2 calls are alerted
1 parent 8545c7d commit f709713

File tree

2 files changed

+43
-37
lines changed

2 files changed

+43
-37
lines changed

python/ql/src/Classes/CallsToInitDel/MethodCallOrder.qll

Lines changed: 14 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,23 @@ predicate multipleCallsToSuperclassMethod(
1414
meth.getName() = name and
1515
meth.getScope() = cls and
1616
locationBefore(call1.getLocation(), call2.getLocation()) and
17-
calledMulti = getASuperCallTargetFromCall(cls, meth, call1, name) and
18-
calledMulti = getASuperCallTargetFromCall(cls, meth, call2, name) and
17+
rankedSuperCallByLocation(1, cls, meth, call1, name, calledMulti) and
18+
rankedSuperCallByLocation(2, cls, meth, call2, name, calledMulti) and
1919
nonTrivial(calledMulti)
2020
)
2121
}
2222

23+
predicate rankedSuperCallByLocation(
24+
int i, Class mroBase, Function meth, DataFlow::MethodCallNode call, string name, Function target
25+
) {
26+
call =
27+
rank[i](DataFlow::MethodCallNode calli |
28+
target = getASuperCallTargetFromCall(mroBase, meth, calli, name)
29+
|
30+
calli order by calli.getLocation().getStartLine(), calli.getLocation().getStartColumn()
31+
)
32+
}
33+
2334
/** Holds if l1 comes before l2, assuming they're in the same file. */
2435
pragma[inline]
2536
private predicate locationBefore(Location l1, Location l2) {
@@ -176,40 +187,7 @@ Function getPossibleMissingSuper(Class base, Function shouldCall, string name) {
176187
)
177188
}
178189

179-
private module FunctionOption = Option<Function>;
180-
181-
/** An optional `Function`. */
182-
class FunctionOption extends FunctionOption::Option {
183-
/**
184-
* Holds if this element is at the specified location.
185-
* The location spans column `startcolumn` of line `startline` to
186-
* column `endcolumn` of line `endline` in file `filepath`.
187-
* For more information, see
188-
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
189-
*/
190-
predicate hasLocationInfo(
191-
string filepath, int startline, int startcolumn, int endline, int endcolumn
192-
) {
193-
this.asSome()
194-
.getLocation()
195-
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
196-
or
197-
this.isNone() and
198-
filepath = "" and
199-
startline = 0 and
200-
startcolumn = 0 and
201-
endline = 0 and
202-
endcolumn = 0
203-
}
204-
205-
/** Gets the qualified name of this function. */
206-
string getQualifiedName() {
207-
result = this.asSome().getQualifiedName()
208-
or
209-
this.isNone() and
210-
result = ""
211-
}
212-
}
190+
private class FunctionOption = LocatableOption<Location, Function>::Option;
213191

214192
/** Gets the result of `getPossibleMissingSuper`, or None if none exists. */
215193
bindingset[name]

python/ql/test/query-tests/Classes/multiple/multiple-init/multiple_init.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,32 @@ def __init__(self): # $ Alert # F2's super call calls F3
8686
F2.__init__(self)
8787
F3.__init__(self)
8888

89-
F4()
89+
F4()
90+
91+
class G1:
92+
def __init__(self):
93+
print("G1 init")
94+
95+
class G2(G1):
96+
def __init__(self):
97+
print("G2 init")
98+
G1.__init__(self)
99+
100+
class G3(G1):
101+
def __init__(self):
102+
print("G3 init")
103+
G1.__init__(self)
104+
105+
class G4(G1):
106+
def __init__(self):
107+
print("G4 init")
108+
G1.__init__(self)
109+
110+
class G5(G2,G3,G4):
111+
def __init__(self): # $ Alert # Only one alert is generated, that mentions the first two calls
112+
print("G5 init")
113+
G2.__init__(self)
114+
G3.__init__(self)
115+
G4.__init__(self)
116+
117+
G5()

0 commit comments

Comments
 (0)