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>
diff --git a/internal/lsp/source/inlay_hint.go b/internal/lsp/source/inlay_hint.go
index 406e4ae..af9e715 100644
--- a/internal/lsp/source/inlay_hint.go
+++ b/internal/lsp/source/inlay_hint.go
@@ -47,7 +47,7 @@
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 @@
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 @@
label := protocol.InlayHintLabelPart{
Value: s,
}
- if len(s) > maxLabelLength {
+ if len(s) > maxLabelLength+len("...") {
label.Value = s[:maxLabelLength] + "..."
label.Tooltip = s
}
diff --git a/internal/lsp/testdata/inlay_hint/composite_literals.go b/internal/lsp/testdata/inlay_hint/composite_literals.go
index 7eeed03..b05c95e 100644
--- a/internal/lsp/testdata/inlay_hint/composite_literals.go
+++ b/internal/lsp/testdata/inlay_hint/composite_literals.go
@@ -6,7 +6,19 @@
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"},
{"", ""},
} {
diff --git a/internal/lsp/testdata/inlay_hint/composite_literals.go.golden b/internal/lsp/testdata/inlay_hint/composite_literals.go.golden
index ecff780..eb2febd 100644
--- a/internal/lsp/testdata/inlay_hint/composite_literals.go.golden
+++ b/internal/lsp/testdata/inlay_hint/composite_literals.go.golden
@@ -4,12 +4,24 @@
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)
}