mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Rank multiple calls so only the first 2 calls are alerted
This commit is contained in:
@@ -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]
|
||||
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user