Skip to content

Commit 83b0675

Browse files
committed
internal/lsp: add inlay hints for constant values
For golang/go#52343. For golang/vscode-go#1631. Change-Id: Iaef0beab2837502f6428767f457d1da21848fcb6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/411101 Run-TryBot: Jamal Carvalho <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Suzy Mueller <[email protected]> gopls-CI: kokoro <[email protected]>
1 parent ecc1479 commit 83b0675

File tree

3 files changed

+146
-0
lines changed

3 files changed

+146
-0
lines changed

internal/lsp/source/inlay_hint.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88
"context"
99
"fmt"
1010
"go/ast"
11+
"go/constant"
1112
"go/token"
1213
"go/types"
14+
"strings"
1315

1416
"golang.org/x/tools/internal/event"
1517
"golang.org/x/tools/internal/lsp/lsppos"
@@ -42,6 +44,8 @@ func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, _ protocol
4244
hints = append(hints, assignVariableTypes(n, tmap, info, &q)...)
4345
case *ast.RangeStmt:
4446
hints = append(hints, rangeVariableTypes(n, tmap, info, &q)...)
47+
case *ast.GenDecl:
48+
hints = append(hints, constantValues(n, tmap, info)...)
4549
}
4650
return true
4751
})
@@ -125,6 +129,56 @@ func variableType(e ast.Expr, tmap *lsppos.TokenMapper, info *types.Info, q *typ
125129
}
126130
}
127131

132+
func constantValues(node *ast.GenDecl, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint {
133+
if node.Tok != token.CONST {
134+
return nil
135+
}
136+
137+
var hints []protocol.InlayHint
138+
for _, v := range node.Specs {
139+
spec, ok := v.(*ast.ValueSpec)
140+
if !ok {
141+
continue
142+
}
143+
end, ok := tmap.Position(v.End())
144+
if !ok {
145+
continue
146+
}
147+
// Show hints when values are missing or at least one value is not
148+
// a basic literal.
149+
showHints := len(spec.Values) == 0
150+
checkValues := len(spec.Names) == len(spec.Values)
151+
var values []string
152+
for i, w := range spec.Names {
153+
obj, ok := info.ObjectOf(w).(*types.Const)
154+
if !ok || obj.Val().Kind() == constant.Unknown {
155+
return nil
156+
}
157+
if checkValues {
158+
switch spec.Values[i].(type) {
159+
case *ast.BadExpr:
160+
return nil
161+
case *ast.BasicLit:
162+
default:
163+
if obj.Val().Kind() != constant.Bool {
164+
showHints = true
165+
}
166+
}
167+
}
168+
values = append(values, fmt.Sprintf("%v", obj.Val()))
169+
}
170+
if !showHints || len(values) == 0 {
171+
continue
172+
}
173+
hints = append(hints, protocol.InlayHint{
174+
Position: &end,
175+
Label: buildLabel("= " + strings.Join(values, ", ")),
176+
PaddingLeft: true,
177+
})
178+
}
179+
return hints
180+
}
181+
128182
func buildLabel(s string) []protocol.InlayHintLabelPart {
129183
label := protocol.InlayHintLabelPart{
130184
Value: s,
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package inlayHint //@inlayHint("package")
2+
3+
const True = true
4+
5+
type Kind int
6+
7+
const (
8+
KindNone Kind = iota
9+
KindPrint
10+
KindPrintf
11+
KindErrorf
12+
)
13+
14+
const (
15+
u = iota * 4
16+
v float64 = iota * 42
17+
w = iota * 42
18+
)
19+
20+
const (
21+
a, b = 1, 2
22+
c, d
23+
e, f = 5 * 5, "hello" + "world"
24+
g, h
25+
i, j = true, f
26+
)
27+
28+
// No hint
29+
const (
30+
Int = 3
31+
Float = 3.14
32+
Bool = true
33+
Rune = '3'
34+
Complex = 2.7i
35+
String = "Hello, world!"
36+
)
37+
38+
var (
39+
varInt = 3
40+
varFloat = 3.14
41+
varBool = true
42+
varRune = '3' + '4'
43+
varComplex = 2.7i
44+
varString = "Hello, world!"
45+
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
-- inlayHint --
2+
package inlayHint //@inlayHint("package")
3+
4+
const True = true
5+
6+
type Kind int
7+
8+
const (
9+
KindNone Kind = iota<= 0>
10+
KindPrint<= 1>
11+
KindPrintf<= 2>
12+
KindErrorf<= 3>
13+
)
14+
15+
const (
16+
u = iota * 4<= 0>
17+
v float64 = iota * 42<= 42>
18+
w = iota * 42<= 84>
19+
)
20+
21+
const (
22+
a, b = 1, 2
23+
c, d<= 1, 2>
24+
e, f = 5 * 5, "hello" + "world"<= 25, "helloworld">
25+
g, h<= 25, "helloworld">
26+
i, j = true, f<= true, "helloworld">
27+
)
28+
29+
// No hint
30+
const (
31+
Int = 3
32+
Float = 3.14
33+
Bool = true
34+
Rune = '3'
35+
Complex = 2.7i
36+
String = "Hello, world!"
37+
)
38+
39+
var (
40+
varInt = 3
41+
varFloat = 3.14
42+
varBool = true
43+
varRune = '3' + '4'
44+
varComplex = 2.7i
45+
varString = "Hello, world!"
46+
)
47+

0 commit comments

Comments
 (0)