Skip to content

Commit 8194029

Browse files
committed
gopls/internal/golang: hover support return statements
Hovering over a return statement now reveals the result type of the function. Updates golang/go#70462 Change-Id: Ib15c0b3db52311762f021a514c0db7bd71411eb3 Reviewed-on: https://go-review.googlesource.com/c/tools/+/637476 Reviewed-by: Alan Donovan <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 851152f commit 8194029

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

gopls/doc/release/v0.18.0.md

+5
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,8 @@ The Definition query now supports additional locations:
4040

4141
- When invoked on a return statement, it reports the location
4242
of the function's result variables.
43+
44+
## Improvements to "Hover"
45+
46+
When invoked on a return statement, hover reports the types of
47+
the function's result variables.

gopls/internal/golang/hover.go

+48-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"go/constant"
1313
"go/doc"
1414
"go/format"
15+
"go/printer"
1516
"go/token"
1617
"go/types"
1718
"go/version"
@@ -241,10 +242,15 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
241242
return *hoverRange, hoverRes, nil // (hoverRes may be nil)
242243
}
243244
}
244-
// Handle hovering over (non-import-path) literals.
245+
246+
// Handle hovering over various special kinds of syntax node.
245247
if path, _ := astutil.PathEnclosingInterval(pgf.File, pos, pos); len(path) > 0 {
246-
if lit, _ := path[0].(*ast.BasicLit); lit != nil {
247-
return hoverLit(pgf, lit, pos)
248+
switch node := path[0].(type) {
249+
// Handle hovering over (non-import-path) literals.
250+
case *ast.BasicLit:
251+
return hoverLit(pgf, node, pos)
252+
case *ast.ReturnStmt:
253+
return hoverReturnStatement(pgf, path, node)
248254
}
249255
}
250256

@@ -925,6 +931,45 @@ func hoverLit(pgf *parsego.File, lit *ast.BasicLit, pos token.Pos) (protocol.Ran
925931
}, nil
926932
}
927933

934+
func hoverReturnStatement(pgf *parsego.File, path []ast.Node, ret *ast.ReturnStmt) (protocol.Range, *hoverResult, error) {
935+
var funcType *ast.FuncType
936+
// Find innermost enclosing function.
937+
for _, n := range path {
938+
switch n := n.(type) {
939+
case *ast.FuncLit:
940+
funcType = n.Type
941+
case *ast.FuncDecl:
942+
funcType = n.Type
943+
}
944+
if funcType != nil {
945+
break
946+
}
947+
}
948+
// Inv: funcType != nil because a ReturnStmt is always enclosed by a function.
949+
if funcType.Results == nil {
950+
return protocol.Range{}, nil, nil // no result variables
951+
}
952+
rng, err := pgf.PosRange(ret.Pos(), ret.End())
953+
if err != nil {
954+
return protocol.Range{}, nil, err
955+
}
956+
// Format the function's result type.
957+
var buf strings.Builder
958+
var cfg printer.Config
959+
fset := token.NewFileSet()
960+
buf.WriteString("returns (")
961+
for i, field := range funcType.Results.List {
962+
if i > 0 {
963+
buf.WriteString(", ")
964+
}
965+
cfg.Fprint(&buf, fset, field.Type)
966+
}
967+
buf.WriteByte(')')
968+
return rng, &hoverResult{
969+
signature: buf.String(),
970+
}, nil
971+
}
972+
928973
// hoverEmbed computes hover information for a filepath.Match pattern.
929974
// Assumes that the pattern is relative to the location of fh.
930975
func hoverEmbed(fh file.Handle, rng protocol.Range, pattern string) (protocol.Range, *hoverResult, error) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
This test checks that hovering over a return statement reveals the result type.
2+
3+
-- a.go --
4+
package a
5+
6+
func one() int {
7+
return 1 //@hover("return", "return 1", "returns (int)")
8+
}
9+
10+
func two() (int, int) {
11+
return 1, 2 //@hover("return", "return 1, 2", "returns (int, int)")
12+
}

0 commit comments

Comments
 (0)