Skip to content

Commit

Permalink
gopls/internal/golang: hover support return statements
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
madelinekalil committed Dec 23, 2024
1 parent 851152f commit 8194029
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 3 deletions.
5 changes: 5 additions & 0 deletions gopls/doc/release/v0.18.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,8 @@ The Definition query now supports additional locations:

- When invoked on a return statement, it reports the location
of the function's result variables.

## Improvements to "Hover"

When invoked on a return statement, hover reports the types of
the function's result variables.
51 changes: 48 additions & 3 deletions gopls/internal/golang/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"go/constant"
"go/doc"
"go/format"
"go/printer"
"go/token"
"go/types"
"go/version"
Expand Down Expand Up @@ -241,10 +242,15 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
return *hoverRange, hoverRes, nil // (hoverRes may be nil)
}
}
// Handle hovering over (non-import-path) literals.

// Handle hovering over various special kinds of syntax node.
if path, _ := astutil.PathEnclosingInterval(pgf.File, pos, pos); len(path) > 0 {
if lit, _ := path[0].(*ast.BasicLit); lit != nil {
return hoverLit(pgf, lit, pos)
switch node := path[0].(type) {
// Handle hovering over (non-import-path) literals.
case *ast.BasicLit:
return hoverLit(pgf, node, pos)
case *ast.ReturnStmt:
return hoverReturnStatement(pgf, path, node)
}
}

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

func hoverReturnStatement(pgf *parsego.File, path []ast.Node, ret *ast.ReturnStmt) (protocol.Range, *hoverResult, error) {
var funcType *ast.FuncType
// Find innermost enclosing function.
for _, n := range path {
switch n := n.(type) {
case *ast.FuncLit:
funcType = n.Type
case *ast.FuncDecl:
funcType = n.Type
}
if funcType != nil {
break
}
}
// Inv: funcType != nil because a ReturnStmt is always enclosed by a function.
if funcType.Results == nil {
return protocol.Range{}, nil, nil // no result variables
}
rng, err := pgf.PosRange(ret.Pos(), ret.End())
if err != nil {
return protocol.Range{}, nil, err
}
// Format the function's result type.
var buf strings.Builder
var cfg printer.Config
fset := token.NewFileSet()
buf.WriteString("returns (")
for i, field := range funcType.Results.List {
if i > 0 {
buf.WriteString(", ")
}
cfg.Fprint(&buf, fset, field.Type)
}
buf.WriteByte(')')
return rng, &hoverResult{
signature: buf.String(),
}, nil
}

// hoverEmbed computes hover information for a filepath.Match pattern.
// Assumes that the pattern is relative to the location of fh.
func hoverEmbed(fh file.Handle, rng protocol.Range, pattern string) (protocol.Range, *hoverResult, error) {
Expand Down
12 changes: 12 additions & 0 deletions gopls/internal/test/marker/testdata/hover/return.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
This test checks that hovering over a return statement reveals the result type.

-- a.go --
package a

func one() int {
return 1 //@hover("return", "return 1", "returns (int)")
}

func two() (int, int) {
return 1, 2 //@hover("return", "return 1, 2", "returns (int, int)")
}

0 comments on commit 8194029

Please sign in to comment.