[tools] internal/astutil: return enclosing node when Select finds no enclosing node

1 view
Skip to first unread message

Hongxiang Jiang (Gerrit)

unread,
Dec 15, 2025, 7:57:11 PM (19 hours ago) Dec 15
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Hongxiang Jiang has uploaded the change for review

Commit message

internal/astutil: return enclosing node when Select finds no enclosing node

Previously, Select returned an error ("no syntax selected") if the
provided range did not wholly enclose any syntax nodes. This behavior
was problematic for point selections (where start == end) or selections
that covered only tokens or whitespace, as callers often still require
the enclosing context (e.g., for code actions or hover information).

Select now returns the enclosing cursor with NoCursor for the start and
end nodes in these cases, rather than returning an error. This allows
callers to inspect the surrounding syntax tree even without a specific
sub-node selection.

This change also documents NoCursor as the sentinel value for checking
validity.
Change-Id: I623cd5bc1b4173970ad1dc3e7baae79aa74cc5de

Change diff

diff --git a/gopls/internal/golang/type_definition.go b/gopls/internal/golang/type_definition.go
index 3de9230..51f8126 100644
--- a/gopls/internal/golang/type_definition.go
+++ b/gopls/internal/golang/type_definition.go
@@ -31,9 +31,9 @@
if err != nil {
return nil, err
}
- cur, ok := pgf.Cursor.FindByPos(start, end)
- if !ok {
- return nil, fmt.Errorf("no enclosing syntax") // can't happen
+ cur, _, _, err := astutil.Select(pgf.Cursor, start, end)
+ if err != nil {
+ return nil, err
}

// Find innermost enclosing expression that has a type.
diff --git a/internal/astutil/util.go b/internal/astutil/util.go
index 6986a51..a022995 100644
--- a/internal/astutil/util.go
+++ b/internal/astutil/util.go
@@ -178,6 +178,10 @@
//
// Select returns the enclosing BlockStmt, the f() CallExpr, and the g() CallExpr.
//
+// If the selection does not wholly enclose any nodes (for example, a
+// point selection at a token position, or a selection of only whitespace),
+// enclosing is returned with zero start and end Cursors.
+//
// Callers that require exactly one syntax tree (e.g. just f() or just
// g()) should check that the returned start and end nodes are
// identical.
@@ -190,7 +194,7 @@
func Select(curFile inspector.Cursor, start, end token.Pos) (_enclosing, _start, _end inspector.Cursor, _ error) {
curEnclosing, ok := curFile.FindByPos(start, end)
if !ok {
- return noCursor, noCursor, noCursor, fmt.Errorf("invalid selection")
+ return NoCursor, NoCursor, NoCursor, fmt.Errorf("invalid selection")
}

// Find the first and last node wholly within the (start, end) range.
@@ -214,7 +218,11 @@
}
}
if !CursorValid(curStart) {
- return noCursor, noCursor, noCursor, fmt.Errorf("no syntax selected")
+ // The selection is valid (inside curEnclosing) but contains no
+ // complete nodes. This happens for point selections (start == end),
+ // or selections covering only tokens/whitespace.
+ // Return the enclosing node so the caller can still use the context.
+ return curEnclosing, NoCursor, NoCursor, nil
}
return curEnclosing, curStart, curEnd, nil
}
@@ -230,4 +238,8 @@
return cur.Inspector() != nil
}

-var noCursor inspector.Cursor
+// NoCursor is the zero value of a Cursor, representing an invalid or
+// absent node. It is returned by functions like Select when no syntax
+// node matches the query. Callers may compare a Cursor against NoCursor
+// to check if it is valid.
+var NoCursor inspector.Cursor

Change information

Files:
  • M gopls/internal/golang/type_definition.go
  • M internal/astutil/util.go
Change size: S
Delta: 2 files changed, 18 insertions(+), 6 deletions(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: tools
Gerrit-Branch: master
Gerrit-Change-Id: I623cd5bc1b4173970ad1dc3e7baae79aa74cc5de
Gerrit-Change-Number: 730320
Gerrit-PatchSet: 1
Gerrit-Owner: Hongxiang Jiang <hxj...@golang.org>
unsatisfied_requirement
satisfied_requirement
open
diffy

Hongxiang Jiang (Gerrit)

unread,
Dec 15, 2025, 7:57:20 PM (19 hours ago) Dec 15
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Hongxiang Jiang voted Commit-Queue+1

Commit-Queue+1
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: tools
Gerrit-Branch: master
Gerrit-Change-Id: I623cd5bc1b4173970ad1dc3e7baae79aa74cc5de
Gerrit-Change-Number: 730320
Gerrit-PatchSet: 1
Gerrit-Owner: Hongxiang Jiang <hxj...@golang.org>
Gerrit-Reviewer: Hongxiang Jiang <hxj...@golang.org>
Gerrit-Comment-Date: Tue, 16 Dec 2025 00:57:14 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
unsatisfied_requirement
satisfied_requirement
open
diffy

Hongxiang Jiang (Gerrit)

unread,
Dec 15, 2025, 8:31:05 PM (18 hours ago) Dec 15
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
Attention needed from Hongxiang Jiang

Hongxiang Jiang uploaded new patchset

Hongxiang Jiang uploaded patch set #2 to this change.
Following approvals got outdated and were removed:
  • TryBots-Pass: LUCI-TryBot-Result-1 by Go LUCI
Open in Gerrit

Related details

Attention is currently required from:
  • Hongxiang Jiang
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newpatchset
Gerrit-Project: tools
Gerrit-Branch: master
Gerrit-Change-Id: I623cd5bc1b4173970ad1dc3e7baae79aa74cc5de
Gerrit-Change-Number: 730320
Gerrit-PatchSet: 2
Gerrit-Owner: Hongxiang Jiang <hxj...@golang.org>
Gerrit-Reviewer: Hongxiang Jiang <hxj...@golang.org>
Gerrit-Attention: Hongxiang Jiang <hxj...@golang.org>
unsatisfied_requirement
satisfied_requirement
open
diffy

Hongxiang Jiang (Gerrit)

unread,
Dec 15, 2025, 8:31:15 PM (18 hours ago) Dec 15
to goph...@pubsubhelper.golang.org, Go LUCI, golang-co...@googlegroups.com

Hongxiang Jiang voted Commit-Queue+1

Commit-Queue+1
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: tools
Gerrit-Branch: master
Gerrit-Change-Id: I623cd5bc1b4173970ad1dc3e7baae79aa74cc5de
Gerrit-Change-Number: 730320
Gerrit-PatchSet: 2
Gerrit-Owner: Hongxiang Jiang <hxj...@golang.org>
Gerrit-Reviewer: Hongxiang Jiang <hxj...@golang.org>
Gerrit-Comment-Date: Tue, 16 Dec 2025 01:31:10 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
unsatisfied_requirement
satisfied_requirement
open
diffy

Hongxiang Jiang (Gerrit)

unread,
Dec 15, 2025, 9:09:53 PM (17 hours ago) Dec 15
to goph...@pubsubhelper.golang.org, Alan Donovan, Madeline Kalil, Go LUCI, golang-co...@googlegroups.com
Attention needed from Alan Donovan and Madeline Kalil

Hongxiang Jiang added 2 comments

Patchset-level comments
File-level comment, Patchset 2 (Latest):
Hongxiang Jiang . resolved

I'm not sure

File internal/astutil/util.go
Line 225, Patchset 2 (Latest): return curEnclosing, NoCursor, NoCursor, nil
Hongxiang Jiang . resolved

I'm not sure this is right way of returning this. This feels weird that the caller have to check the 2nd the 3rd return value against "NoCursor" to figure out if this return value is valid.

Open in Gerrit

Related details

Attention is currently required from:
  • Alan Donovan
  • Madeline Kalil
Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement satisfiedTryBots-Pass
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: tools
    Gerrit-Branch: master
    Gerrit-Change-Id: I623cd5bc1b4173970ad1dc3e7baae79aa74cc5de
    Gerrit-Change-Number: 730320
    Gerrit-PatchSet: 2
    Gerrit-Owner: Hongxiang Jiang <hxj...@golang.org>
    Gerrit-Reviewer: Alan Donovan <adon...@google.com>
    Gerrit-Reviewer: Hongxiang Jiang <hxj...@golang.org>
    Gerrit-Reviewer: Madeline Kalil <mka...@google.com>
    Gerrit-Attention: Madeline Kalil <mka...@google.com>
    Gerrit-Attention: Alan Donovan <adon...@google.com>
    Gerrit-Comment-Date: Tue, 16 Dec 2025 02:09:46 +0000
    Gerrit-HasComments: Yes
    Gerrit-Has-Labels: No
    unsatisfied_requirement
    satisfied_requirement
    open
    diffy
    Reply all
    Reply to author
    Forward
    0 new messages