Make DataFlowCallable either a Function or a FuncLit

This commit is contained in:
Sauyon Lee
2021-09-23 11:23:51 -07:00
committed by Owen Mansel-Chan
parent 3ac2a50497
commit 0b50b7b2b1
3 changed files with 62 additions and 15 deletions

View File

@@ -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()
)
}

View File

@@ -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`. */

View File

@@ -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() {