From dd8fb29a65e56c421db8061f1bb6a987fa4b8d75 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 22 Nov 2023 16:32:10 +0000 Subject: [PATCH] Improve QLDocs of CallNode and MethodCallNode When a function is assigned to a variable and called through that variable then we can't always tell it was a method. --- .../go/dataflow/internal/DataFlowNodes.qll | 37 +++++++++++++++++-- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll index 5a3c589197e..73f3f35fbb0 100644 --- a/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll +++ b/go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll @@ -480,7 +480,11 @@ module Public { class CallNode extends ExprNode { override CallExpr expr; - /** Gets the declared target of this call */ + /** + * Gets the declared target of this call, if it exists. + * + * This doesn't exist when a function is called via a variable. + */ Function getTarget() { result = expr.getTarget() } private DataFlow::Node getACalleeSource() { result = getACalleeSource(this) } @@ -637,14 +641,41 @@ module Public { /** Gets a result of this call. */ Node getAResult() { result = this.getResult(_) } - /** Gets the data flow node corresponding to the receiver of this call, if any. */ + /** + * Gets the data flow node corresponding to the receiver of this call, if any. + * + * When a method value is assigned to a variable then when it is called it + * looks like a function call, as in the following example. + * + * ```go + * file, _ := os.Open("test.txt") + * f := file.Close + * f() + * ``` + * + * In this case we use local flow to try to find the receiver (`file` in + * the above example). + */ Node getReceiver() { result = this.getACalleeSource().(MethodReadNode).getReceiver() } /** Holds if this call has an ellipsis after its last argument. */ predicate hasEllipsis() { expr.hasEllipsis() } } - /** A data flow node that represents a call to a method. */ + /** + * A data flow node that represents a direct call to a method. + * + * When a method value is assigned to a variable then when it is called it + * syntactically looks like a function call, as in the following example. + * + * ```go + * file, _ := os.Open("test.txt") + * f := file.Close + * f() + * ``` + * + * In this case it will not be considered a `MethodCallNode`. + */ class MethodCallNode extends CallNode { MethodCallNode() { expr.getTarget() instanceof Method }