Skip to content

Commit

Permalink
internal/lsp: support textDocument/inlayHint for parameter names
Browse files Browse the repository at this point in the history
This change implements support for textDocument/inlayHint and
adds inlay hints for parameter names.

For golang/go#52343.
For golang/vscode-go#1631.

Change-Id: I3f989838b86cef4fd2b4076cb6340010fff7c24c
Reviewed-on: https://go-review.googlesource.com/c/tools/+/411094
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Reviewed-by: Suzy Mueller <suzmue@golang.org>
Run-TryBot: Jamal Carvalho <jamal@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
  • Loading branch information
jamalc committed Jun 10, 2022
1 parent 9651276 commit 65c0181
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 2 deletions.
21 changes: 21 additions & 0 deletions internal/lsp/inlay_hint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package lsp

import (
"context"

"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/lsp/source"
)

func (s *Server) inlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
defer release()
if !ok {
return nil, err
}
return source.InlayHint(ctx, snapshot, fh, params.ViewPort)
}
4 changes: 2 additions & 2 deletions internal/lsp/server_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ func (s *Server) Initialized(ctx context.Context, params *protocol.InitializedPa
return s.initialized(ctx, params)
}

func (s *Server) InlayHint(context.Context, *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
return nil, notImplemented("InlayHint")
func (s *Server) InlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
return s.inlayHint(ctx, params)
}

func (s *Server) InlayHintRefresh(context.Context) error {
Expand Down
90 changes: 90 additions & 0 deletions internal/lsp/source/inlay_hint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package source

import (
"context"
"fmt"
"go/ast"
"go/types"

"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/lsp/lsppos"
"golang.org/x/tools/internal/lsp/protocol"
)

const (
maxLabelLength = 28
)

func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, _ protocol.Range) ([]protocol.InlayHint, error) {
ctx, done := event.Start(ctx, "source.InlayHint")
defer done()

pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
if err != nil {
return nil, fmt.Errorf("getting file for InlayHint: %w", err)
}

tmap := lsppos.NewTokenMapper(pgf.Src, pgf.Tok)
info := pkg.GetTypesInfo()

var hints []protocol.InlayHint
ast.Inspect(pgf.File, func(node ast.Node) bool {
switch n := node.(type) {
case *ast.CallExpr:
hints = append(hints, parameterNames(n, tmap, info)...)
}
return true
})
return hints, nil
}

func parameterNames(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint {
signature, ok := info.TypeOf(node.Fun).(*types.Signature)
if !ok {
return nil
}

var hints []protocol.InlayHint
for i, v := range node.Args {
start, ok := tmap.Position(v.Pos())
if !ok {
continue
}
params := signature.Params()
// When a function has variadic params, we skip args after
// params.Len().
if i > params.Len()-1 {
break
}
value := params.At(i).Name()
// param.Name is empty for built-ins like append
if value == "" {
continue
}
if signature.Variadic() && i == params.Len()-1 {
value = value + "..."
}
hints = append(hints, protocol.InlayHint{
Position: &start,
Label: buildLabel(value + ":"),
Kind: protocol.Parameter,
PaddingRight: true,
})
}
return hints
}

func buildLabel(s string) []protocol.InlayHintLabelPart {
label := protocol.InlayHintLabelPart{
Value: s,
}
if len(s) > maxLabelLength {
label.Value = s[:maxLabelLength] + "..."
label.Tooltip = s
}
return []protocol.InlayHintLabelPart{label}
}
45 changes: 45 additions & 0 deletions internal/lsp/testdata/inlay_hint/parameter_names.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package inlayHint //@inlayHint("package")

import "fmt"

func hello(name string) string {
return "Hello " + name
}

func helloWorld() string {
return hello("World")
}

type foo struct{}

func (*foo) bar(baz string, qux int) int {
if baz != "" {
return qux + 1
}
return qux
}

func kase(foo int, bar bool, baz ...string) {
fmt.Println(foo, bar, baz)
}

func kipp(foo string, bar, baz string) {
fmt.Println(foo, bar, baz)
}

func plex(foo, bar string, baz string) {
fmt.Println(foo, bar, baz)
}

func tars(foo string, bar, baz string) {
fmt.Println(foo, bar, baz)
}

func foobar() {
var x foo
x.bar("", 1)
kase(0, true, "c", "d", "e")
kipp("a", "b", "c")
plex("a", "b", "c")
tars("a", "b", "c")
}
47 changes: 47 additions & 0 deletions internal/lsp/testdata/inlay_hint/parameter_names.go.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
-- inlayHint --
package inlayHint //@inlayHint("package")

import "fmt"

func hello(name string) string {
return "Hello " + name
}

func helloWorld() string {
return hello(<name:>"World")
}

type foo struct{}

func (*foo) bar(baz string, qux int) int {
if baz != "" {
return qux + 1
}
return qux
}

func kase(foo int, bar bool, baz ...string) {
fmt.Println(<a...:>foo, bar, baz)
}

func kipp(foo string, bar, baz string) {
fmt.Println(<a...:>foo, bar, baz)
}

func plex(foo, bar string, baz string) {
fmt.Println(<a...:>foo, bar, baz)
}

func tars(foo string, bar, baz string) {
fmt.Println(<a...:>foo, bar, baz)
}

func foobar() {
var x foo
x.bar(<baz:>"", <qux:>1)
kase(<foo:>0, <bar:>true, <baz...:>"c", "d", "e")
kipp(<foo:>"a", <bar:>"b", <baz:>"c")
plex(<foo:>"a", <bar:>"b", <baz:>"c")
tars(<foo:>"a", <bar:>"b", <baz:>"c")
}

0 comments on commit 65c0181

Please sign in to comment.