Rank multiple calls so only the first 2 calls are alerted

This commit is contained in:
Joe Farebrother
2025-09-01 16:23:42 +01:00
parent 8545c7d36f
commit f7097136f1
2 changed files with 43 additions and 37 deletions

View File

@@ -14,12 +14,23 @@ predicate multipleCallsToSuperclassMethod(
meth.getName() = name and
meth.getScope() = cls and
locationBefore(call1.getLocation(), call2.getLocation()) and
calledMulti = getASuperCallTargetFromCall(cls, meth, call1, name) and
calledMulti = getASuperCallTargetFromCall(cls, meth, call2, name) and
rankedSuperCallByLocation(1, cls, meth, call1, name, calledMulti) and
rankedSuperCallByLocation(2, cls, meth, call2, name, calledMulti) and
nonTrivial(calledMulti)
)
}
predicate rankedSuperCallByLocation(
int i, Class mroBase, Function meth, DataFlow::MethodCallNode call, string name, Function target
) {
call =
rank[i](DataFlow::MethodCallNode calli |
target = getASuperCallTargetFromCall(mroBase, meth, calli, name)
|
calli order by calli.getLocation().getStartLine(), calli.getLocation().getStartColumn()
)
}
/** Holds if l1 comes before l2, assuming they're in the same file. */
pragma[inline]
private predicate locationBefore(Location l1, Location l2) {
@@ -176,40 +187,7 @@ Function getPossibleMissingSuper(Class base, Function shouldCall, string name) {
)
}
private module FunctionOption = Option<Function>;
/** An optional `Function`. */
class FunctionOption extends FunctionOption::Option {
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.asSome()
.getLocation()
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
or
this.isNone() and
filepath = "" and
startline = 0 and
startcolumn = 0 and
endline = 0 and
endcolumn = 0
}
/** Gets the qualified name of this function. */
string getQualifiedName() {
result = this.asSome().getQualifiedName()
or
this.isNone() and
result = ""
}
}
private class FunctionOption = LocatableOption<Location, Function>::Option;
/** Gets the result of `getPossibleMissingSuper`, or None if none exists. */
bindingset[name]

View File

@@ -86,4 +86,32 @@ class F4(F2, F3):
F2.__init__(self)
F3.__init__(self)
F4()
F4()
class G1:
def __init__(self):
print("G1 init")
class G2(G1):
def __init__(self):
print("G2 init")
G1.__init__(self)
class G3(G1):
def __init__(self):
print("G3 init")
G1.__init__(self)
class G4(G1):
def __init__(self):
print("G4 init")
G1.__init__(self)
class G5(G2,G3,G4):
def __init__(self): # $ Alert # Only one alert is generated, that mentions the first two calls
print("G5 init")
G2.__init__(self)
G3.__init__(self)
G4.__init__(self)
G5()