mirror of
https://github.com/github/codeql.git
synced 2026-05-03 20:58:03 +02:00
Make DataFlowCallable either a Function or a FuncLit
This commit is contained in:
committed by
Owen Mansel-Chan
parent
3ac2a50497
commit
0b50b7b2b1
@@ -53,12 +53,11 @@ private predicate isConcreteInterfaceCall(DataFlow::Node call, DataFlow::Node re
|
||||
* Gets a function that might be called by `call`, where the receiver of `call` has interface type,
|
||||
* but its concrete types can be determined by local reasoning.
|
||||
*/
|
||||
private FuncDecl getConcreteTarget(DataFlow::CallNode call) {
|
||||
private DataFlowCallable getConcreteTarget(DataFlow::CallNode call) {
|
||||
exists(DataFlow::Node recv, string m | isConcreteInterfaceCall(call, recv, m) |
|
||||
exists(Type concreteReceiverType, DeclaredFunction concreteTarget |
|
||||
exists(Type concreteReceiverType |
|
||||
concreteReceiverType = getConcreteType(getInterfaceCallReceiverSource(call)) and
|
||||
concreteTarget = concreteReceiverType.getMethod(m) and
|
||||
result = concreteTarget.getFuncDecl()
|
||||
result.asFunction() = concreteReceiverType.getMethod(m)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -74,10 +73,10 @@ private predicate isInterfaceMethodCall(DataFlow::CallNode call) {
|
||||
* Gets a method that might be called by `call`, where we restrict the result to
|
||||
* implement the interface type of the receiver of `call`.
|
||||
*/
|
||||
private MethodDecl getRestrictedInterfaceTarget(DataFlow::CallNode call) {
|
||||
private DataFlowCallable getRestrictedInterfaceTarget(DataFlow::CallNode call) {
|
||||
exists(InterfaceType tp, Type recvtp, string m |
|
||||
isInterfaceCallReceiver(call, _, tp, m) and
|
||||
result = recvtp.getMethod(m).(DeclaredFunction).getFuncDecl() and
|
||||
result.asFunction() = recvtp.getMethod(m) and
|
||||
recvtp.implements(tp)
|
||||
)
|
||||
}
|
||||
@@ -92,7 +91,7 @@ DataFlowCallable viableCallable(CallExpr ma) {
|
||||
else
|
||||
if isInterfaceMethodCall(call)
|
||||
then result = getRestrictedInterfaceTarget(call)
|
||||
else result = call.getACallee()
|
||||
else result.getFuncDef() = call.getACallee()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +184,55 @@ class CastNode extends ExprNode {
|
||||
override ConversionExpr expr;
|
||||
}
|
||||
|
||||
class DataFlowCallable = FuncDef;
|
||||
private newtype TCallable =
|
||||
TFunctionCallable(Function f) or
|
||||
TFuncLitCallable(FuncLit l)
|
||||
|
||||
/**
|
||||
* A data-flow callable.
|
||||
*
|
||||
* This is either a `Function` or a `FuncLit`, because of limitations of both
|
||||
* `Function` and `FuncDef`:
|
||||
* - `Function` is an entity, and therefore does not include function literals, and
|
||||
* - `FuncDef` is an AST node, and so is not extracted for functions from external libraries.
|
||||
*/
|
||||
class DataFlowCallable extends TCallable {
|
||||
/** Gets a textual representation of this callable. */
|
||||
string toString() { result = [this.asFunction().toString(), this.asFuncLit().toString()] }
|
||||
|
||||
/** Gets this callable as a function, if it is one. */
|
||||
Function asFunction() { this = TFunctionCallable(result) }
|
||||
|
||||
/** Gets this callable as a function literal, if it is one. */
|
||||
FuncLit asFuncLit() { this = TFuncLitCallable(result) }
|
||||
|
||||
/** Gets this function's definition, if it exists. */
|
||||
FuncDef getFuncDef() { result = [this.asFuncLit().(FuncDef), this.asFunction().getFuncDecl()] }
|
||||
|
||||
/** Gets the type of this callable. */
|
||||
SignatureType getType() {
|
||||
result = this.asFunction().getType() or
|
||||
result = this.asFuncLit().getType()
|
||||
}
|
||||
|
||||
/** Gets the name of this callable. */
|
||||
string getName() {
|
||||
result = this.asFunction().getName() or
|
||||
result = this.asFuncLit().getName()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `sc` of line `sl` to
|
||||
* column `ec` of line `el` in file `fp`.
|
||||
* For more information, see
|
||||
* [Locations](https://help.semmle.com/QL/learn-ql/ql/locations.html).
|
||||
*/
|
||||
predicate hasLocationInfo(string fp, int sl, int sc, int el, int ec) {
|
||||
this.asFunction().hasLocationInfo(fp, sl, sc, el, ec) or
|
||||
this.asFuncLit().hasLocationInfo(fp, sl, sc, el, ec)
|
||||
}
|
||||
}
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
@@ -207,7 +255,7 @@ class DataFlowCall extends Expr {
|
||||
ExprNode getNode() { result = call }
|
||||
|
||||
/** Gets the enclosing callable of this call. */
|
||||
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
DataFlowCallable getEnclosingCallable() { result.getFuncDef() = this.getEnclosingFunction() }
|
||||
}
|
||||
|
||||
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
|
||||
|
||||
@@ -52,11 +52,7 @@ predicate summaryElement(DataFlowCallable c, string input, string output, string
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
|
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and
|
||||
c =
|
||||
interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
.asEntity()
|
||||
.(Function)
|
||||
.getFuncDecl()
|
||||
c.asFunction() = interpretElement(namespace, type, subtypes, name, signature, ext).asEntity()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -130,7 +126,11 @@ class InterpretNode extends TInterpretNode {
|
||||
DataFlowCall asCall() { result = this.asElement().asAstNode() }
|
||||
|
||||
/** Gets the callable that this node corresponds to, if any. */
|
||||
DataFlowCallable asCallable() { result = this.asElement().asEntity().(Function).getFuncDecl() }
|
||||
DataFlowCallable asCallable() {
|
||||
result.asFunction() = this.asElement().asEntity()
|
||||
or
|
||||
result.asFuncLit() = this.asElement().asAstNode()
|
||||
}
|
||||
|
||||
/** Gets the target of this call, if any. */
|
||||
SourceOrSinkElement getCallTarget() {
|
||||
|
||||
Reference in New Issue
Block a user