From 1e14d994d8902691ecce91c8f344cd228f8c7fb7 Mon Sep 17 00:00:00 2001 From: Suzy Mueller Date: Mon, 13 Jun 2022 18:16:50 -0400 Subject: [PATCH] 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: {"hello", "goodbye"} For golang/go#52343 Change-Id: Ia1f03b82669387c864353b8033940759fa1128e7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/411905 gopls-CI: kokoro Run-TryBot: Suzy Mueller Reviewed-by: Jamal Carvalho TryBot-Result: Gopher Robot --- internal/lsp/source/inlay_hint.go | 24 ++++++++++++++++--- .../testdata/inlay_hint/composite_literals.go | 14 ++++++++++- .../inlay_hint/composite_literals.go.golden | 20 ++++++++++++---- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/internal/lsp/source/inlay_hint.go b/internal/lsp/source/inlay_hint.go index 406e4ae80e..af9e715c91 100644 --- a/internal/lsp/source/inlay_hint.go +++ b/internal/lsp/source/inlay_hint.go @@ -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 } diff --git a/internal/lsp/testdata/inlay_hint/composite_literals.go b/internal/lsp/testdata/inlay_hint/composite_literals.go index 7eeed03e81..b05c95ec80 100644 --- a/internal/lsp/testdata/inlay_hint/composite_literals.go +++ b/internal/lsp/testdata/inlay_hint/composite_literals.go @@ -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"}, {"", ""}, } { diff --git a/internal/lsp/testdata/inlay_hint/composite_literals.go.golden b/internal/lsp/testdata/inlay_hint/composite_literals.go.golden index ecff780038..eb2febdb6a 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 @@ 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 }{ - {"Hello, world", "dlrow ,olleH"}, - {"Hello, 世界", "界世 ,olleH"}, - {"", ""}, + struct{ in, want string }{"Hello, world", "dlrow ,olleH"}, + {"Hello, 世界", "界世 ,olleH"}, + {"", ""}, + } { + fmt.Println(c.in == c.want) + } +} + +func fieldNamesPointers() { + for _< int>, c< *struct{in string; want string}> := range []*struct { + in, want string + }{ + &struct{ in, want string }{"Hello, world", "dlrow ,olleH"}, + <&struct{in string; want string}>{"Hello, 世界", "界世 ,olleH"}, + <&struct{in string; want string}>{"", ""}, } { fmt.Println(c.in == c.want) }