diff --git a/ql/lib/semmle/go/Scopes.qll b/ql/lib/semmle/go/Scopes.qll index bc1aba221a4..9512704c53e 100644 --- a/ql/lib/semmle/go/Scopes.qll +++ b/ql/lib/semmle/go/Scopes.qll @@ -591,6 +591,54 @@ class BuiltinFunction extends Function, BuiltinEntity, @builtinfunctionobject { predicate isPure() { not this.mayHaveSideEffects() } } +private newtype TCallable = + TFunctionCallable(Function f) or + TFuncLitCallable(FuncLit l) + +/** + * 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 Callable 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) + } +} + /** A statement label. */ class Label extends Entity, @labelobject { } diff --git a/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll b/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll index 16f59c47b43..a8453792fe6 100644 --- a/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll +++ b/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll @@ -104,7 +104,7 @@ module Public { ControlFlow::Root getRoot() { none() } // overridden in subclasses /** INTERNAL: Use `getRoot()` instead. */ - DataFlowCallable getEnclosingCallable() { + Callable getEnclosingCallable() { result.getFuncDef() = this.getRoot() or this = MkSummarizedParameterNode(result, _) @@ -457,7 +457,7 @@ module Public { * For virtual calls, we look up possible targets in all types that implement the receiver * interface type. */ - DataFlowCallable getACalleeIncludingExternals() { + Callable getACalleeIncludingExternals() { result.asFunction() = this.getTarget() or exists(DataFlow::Node calleeSource | calleeSource = this.getACalleeSource() | @@ -558,7 +558,7 @@ module Public { /** A representation of a parameter initialization. */ abstract class ParameterNode extends DataFlow::Node { /** Holds if this node initializes the `i`th parameter of `fd`. */ - abstract predicate isParameterOf(DataFlowCallable c, int i); + abstract predicate isParameterOf(Callable c, int i); } /** @@ -566,7 +566,7 @@ module Public { * already have a parameter nodes. */ class SummarizedParameterNode extends ParameterNode, MkSummarizedParameterNode { - DataFlowCallable c; + Callable c; int i; SummarizedParameterNode() { this = MkSummarizedParameterNode(c, i) } @@ -582,7 +582,7 @@ module Public { i = -1 and result = c.asFunction().(Method).getReceiverType() } - override predicate isParameterOf(DataFlowCallable call, int idx) { c = call and i = idx } + override predicate isParameterOf(Callable call, int idx) { c = call and i = idx } override string toString() { result = "parameter " + i + " of " + c.toString() } @@ -601,9 +601,7 @@ module Public { /** Gets the parameter this node initializes. */ override Parameter asParameter() { result = parm } - override predicate isParameterOf(DataFlowCallable c, int i) { - parm.isParameterOf(c.getFuncDef(), i) - } + override predicate isParameterOf(Callable c, int i) { parm.isParameterOf(c.getFuncDef(), i) } } /** A representation of a receiver initialization. */ diff --git a/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll b/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll index e69c7fe39fd..5724e53f92e 100644 --- a/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll +++ b/ql/lib/semmle/go/dataflow/internal/DataFlowPrivate.qll @@ -191,68 +191,14 @@ class CastNode extends ExprNode { override ConversionExpr expr; } -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()] } - - FunctionNode asFunctionNode() { - this.asFunction() = result.getFunction() - or - this.asFuncLit() = result.asExpr() - } - - /** 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; class DataFlowType = Type; class DataFlowLocation = Location; +class DataFlowCallable = Callable; + /** A function call relevant for data flow. */ class DataFlowCall extends Expr { DataFlow::CallNode call;