internal/lsp: add inlay hints for composite literal types

Add inlay hints for composite literal types. This will show type
information for composite literals with no explicit types.

Example:
<struct {in, want string}>{"hello", "goodbye"}

For golang/go#52343

Change-Id: Ia1f03b82669387c864353b8033940759fa1128e7
Reviewed-on: https://go-review.googlesource.com/c/tools/+/411905
gopls-CI: kokoro <noreply+kokoro@google.com>
Run-TryBot: Suzy Mueller <suzmue@golang.org>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Suzy Mueller 2022-06-13 18:16:50 -04:00
parent e9870152b0
commit 1e14d994d8
3 changed files with 50 additions and 8 deletions

View File

@ -47,7 +47,7 @@ func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, _ protocol
case *ast.GenDecl:
hints = append(hints, constantValues(n, tmap, info)...)
case *ast.CompositeLit:
hints = append(hints, compositeLiterals(n, tmap, info)...)
hints = append(hints, compositeLiterals(n, tmap, info, &q)...)
}
return true
})
@ -181,17 +181,35 @@ func constantValues(node *ast.GenDecl, tmap *lsppos.TokenMapper, info *types.Inf
return hints
}
func compositeLiterals(node *ast.CompositeLit, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint {
func compositeLiterals(node *ast.CompositeLit, tmap *lsppos.TokenMapper, info *types.Info, q *types.Qualifier) []protocol.InlayHint {
typ := info.TypeOf(node)
if typ == nil {
return nil
}
prefix := ""
if t, ok := typ.(*types.Pointer); ok {
typ = t.Elem()
prefix = "&"
}
strct, ok := typ.Underlying().(*types.Struct)
if !ok {
return nil
}
var hints []protocol.InlayHint
if node.Type == nil {
// The type for this struct is implicit, add an inlay hint.
if start, ok := tmap.Position(node.Lbrace); ok {
hints = append(hints, protocol.InlayHint{
Position: &start,
Label: buildLabel(fmt.Sprintf("%s%s", prefix, types.TypeString(typ, *q))),
Kind: protocol.Type,
})
}
}
for i, v := range node.Elts {
if _, ok := v.(*ast.KeyValueExpr); !ok {
start, ok := tmap.Position(v.Pos())
@ -216,7 +234,7 @@ func buildLabel(s string) []protocol.InlayHintLabelPart {
label := protocol.InlayHintLabelPart{
Value: s,
}
if len(s) > maxLabelLength {
if len(s) > maxLabelLength+len("...") {
label.Value = s[:maxLabelLength] + "..."
label.Tooltip = s
}

View File

@ -6,7 +6,19 @@ func fieldNames() {
for _, c := range []struct {
in, want string
}{
{"Hello, world", "dlrow ,olleH"},
struct{ in, want string }{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
} {
fmt.Println(c.in == c.want)
}
}
func fieldNamesPointers() {
for _, c := range []*struct {
in, want string
}{
&struct{ in, want string }{"Hello, world", "dlrow ,olleH"},
{"Hello, 世界", "界世 ,olleH"},
{"", ""},
} {

View File

@ -4,12 +4,24 @@ package inlayHint //@inlayHint("package")
import "fmt"
func fieldNames() {
for _< int>, c< struct{in string; want strin...> := range []struct {
for _< int>, c< struct{in string; want string}> := range []struct {
in, want string
}{
{<in: >"Hello, world", <want: >"dlrow ,olleH"},
{<in: >"Hello, 世界", <want: >"界世 ,olleH"},
{<in: >"", <want: >""},
struct{ in, want string }{<in: >"Hello, world", <want: >"dlrow ,olleH"},
<struct{in string; want string}>{<in: >"Hello, 世界", <want: >"界世 ,olleH"},
<struct{in string; want string}>{<in: >"", <want: >""},
} {
fmt.Println(<a...: >c.in == c.want)
}
}
func fieldNamesPointers() {
for _< int>, c< *struct{in string; want string}> := range []*struct {
in, want string
}{
&struct{ in, want string }{<in: >"Hello, world", <want: >"dlrow ,olleH"},
<&struct{in string; want string}>{<in: >"Hello, 世界", <want: >"界世 ,olleH"},
<&struct{in string; want string}>{<in: >"", <want: >""},
} {
fmt.Println(<a...: >c.in == c.want)
}