Skip to content

Commit dd8fb29

Browse files
committed
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.
1 parent 30891ca commit dd8fb29

File tree

1 file changed

+34
-3
lines changed

1 file changed

+34
-3
lines changed

go/ql/lib/semmle/go/dataflow/internal/DataFlowNodes.qll

+34-3
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,11 @@ module Public {
480480
class CallNode extends ExprNode {
481481
override CallExpr expr;
482482

483-
/** Gets the declared target of this call */
483+
/**
484+
* Gets the declared target of this call, if it exists.
485+
*
486+
* This doesn't exist when a function is called via a variable.
487+
*/
484488
Function getTarget() { result = expr.getTarget() }
485489

486490
private DataFlow::Node getACalleeSource() { result = getACalleeSource(this) }
@@ -637,14 +641,41 @@ module Public {
637641
/** Gets a result of this call. */
638642
Node getAResult() { result = this.getResult(_) }
639643

640-
/** Gets the data flow node corresponding to the receiver of this call, if any. */
644+
/**
645+
* Gets the data flow node corresponding to the receiver of this call, if any.
646+
*
647+
* When a method value is assigned to a variable then when it is called it
648+
* looks like a function call, as in the following example.
649+
*
650+
* ```go
651+
* file, _ := os.Open("test.txt")
652+
* f := file.Close
653+
* f()
654+
* ```
655+
*
656+
* In this case we use local flow to try to find the receiver (`file` in
657+
* the above example).
658+
*/
641659
Node getReceiver() { result = this.getACalleeSource().(MethodReadNode).getReceiver() }
642660

643661
/** Holds if this call has an ellipsis after its last argument. */
644662
predicate hasEllipsis() { expr.hasEllipsis() }
645663
}
646664

647-
/** A data flow node that represents a call to a method. */
665+
/**
666+
* A data flow node that represents a direct call to a method.
667+
*
668+
* When a method value is assigned to a variable then when it is called it
669+
* syntactically looks like a function call, as in the following example.
670+
*
671+
* ```go
672+
* file, _ := os.Open("test.txt")
673+
* f := file.Close
674+
* f()
675+
* ```
676+
*
677+
* In this case it will not be considered a `MethodCallNode`.
678+
*/
648679
class MethodCallNode extends CallNode {
649680
MethodCallNode() { expr.getTarget() instanceof Method }
650681

0 commit comments

Comments
 (0)