Skip to content

Commit

Permalink
gopls/internal/lsp/source: support hover over non-decimal int literals
Browse files Browse the repository at this point in the history
As an alternative to golang/go#45802, support hovering over non-decimal
literals rather than variables that were initialized with a non-decimal
literal.

Also fix a bug where '0X...' was not recognized as a valid hex literal.

Fixes golang/go#58220

Change-Id: I50e6ccc23b3c7f8d8bfb5f66ddb2ec82f44ec5da
Reviewed-on: https://go-review.googlesource.com/c/tools/+/482676
Run-TryBot: Robert Findley <[email protected]>
gopls-CI: kokoro <[email protected]>
TryBot-Result: Gopher Robot <[email protected]>
Reviewed-by: Alan Donovan <[email protected]>
  • Loading branch information
findleyr committed Apr 10, 2023
1 parent 40fb89c commit 0f415ef
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 31 deletions.
78 changes: 51 additions & 27 deletions gopls/internal/lsp/source/hover.go
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,11 @@ func hoverPackageName(pkg Package, pgf *ParsedGoFile) (protocol.Range, *HoverJSO
//
// '∑', U+2211, N-ARY SUMMATION
func hoverLit(pgf *ParsedGoFile, lit *ast.BasicLit, pos token.Pos) (protocol.Range, *HoverJSON, error) {
var r rune
var start, end token.Pos
var (
value string // if non-empty, a constant value to format in hover
r rune // if non-zero, format a description of this rune in hover
start, end token.Pos // hover span
)
// Extract a rune from the current position.
// 'Ω', "...Ω...", or 0x03A9 => 'Ω', U+03A9, GREEK CAPITAL LETTER OMEGA
switch lit.Kind {
Expand All @@ -504,23 +507,34 @@ func hoverLit(pgf *ParsedGoFile, lit *ast.BasicLit, pos token.Pos) (protocol.Ran
return protocol.Range{}, nil, fmt.Errorf("rune error")
}
start, end = lit.Pos(), lit.End()
case token.INT:
// TODO(rfindley): add support for hex/octal/binary->int conversion here.

// It's an integer, scan only if it is a hex literal whose bitsize in
// ranging from 8 to 32.
if !(strings.HasPrefix(lit.Value, "0x") && len(lit.Value[2:]) >= 2 && len(lit.Value[2:]) <= 8) {
case token.INT:
// Short literals (e.g. 99 decimal, 07 octal) are uninteresting.
if len(lit.Value) < 3 {
return protocol.Range{}, nil, nil
}
v, err := strconv.ParseUint(lit.Value[2:], 16, 32)
if err != nil {
return protocol.Range{}, nil, fmt.Errorf("parsing int: %v", err)

v := constant.MakeFromLiteral(lit.Value, lit.Kind, 0)
if v.Kind() != constant.Int {
return protocol.Range{}, nil, nil
}
r = rune(v)
if r == utf8.RuneError {
return protocol.Range{}, nil, fmt.Errorf("rune error")

switch lit.Value[:2] {
case "0x", "0X":
// As a special case, try to recognize hexadecimal literals as runes if
// they are within the range of valid unicode values.
if v, ok := constant.Int64Val(v); ok && v > 0 && v <= utf8.MaxRune && utf8.ValidRune(rune(v)) {
r = rune(v)
}
fallthrough
case "0o", "0O", "0b", "0B":
// Format the decimal value of non-decimal literals.
value = v.ExactString()
start, end = lit.Pos(), lit.End()
default:
return protocol.Range{}, nil, nil
}
start, end = lit.Pos(), lit.End()

case token.STRING:
// It's a string, scan only if it contains a unicode escape sequence under or before the
// current cursor position.
Expand Down Expand Up @@ -555,29 +569,39 @@ func hoverLit(pgf *ParsedGoFile, lit *ast.BasicLit, pos token.Pos) (protocol.Ran
}
}
}
if r == 0 {

if value == "" && r == 0 { // nothing to format
return protocol.Range{}, nil, nil
}

rng, err := pgf.PosRange(start, end)
if err != nil {
return protocol.Range{}, nil, err
}

var desc string
runeName := runenames.Name(r)
if len(runeName) > 0 && runeName[0] == '<' {
// Check if the rune looks like an HTML tag. If so, trim the surrounding <>
// characters to work around https://github.com/microsoft/vscode/issues/124042.
runeName = strings.TrimRight(runeName[1:], ">")
var b strings.Builder
if value != "" {
b.WriteString(value)
}
if strconv.IsPrint(r) {
desc = fmt.Sprintf("'%s', U+%04X, %s", string(r), uint32(r), runeName)
} else {
desc = fmt.Sprintf("U+%04X, %s", uint32(r), runeName)
if r != 0 {
runeName := runenames.Name(r)
if len(runeName) > 0 && runeName[0] == '<' {
// Check if the rune looks like an HTML tag. If so, trim the surrounding <>
// characters to work around https://github.com/microsoft/vscode/issues/124042.
runeName = strings.TrimRight(runeName[1:], ">")
}
if b.Len() > 0 {
b.WriteString(", ")
}
if strconv.IsPrint(r) {
fmt.Fprintf(&b, "'%c', ", r)
}
fmt.Fprintf(&b, "U+%04X, %s", r, runeName)
}
hover := b.String()
return rng, &HoverJSON{
Synopsis: desc,
FullDocumentation: desc,
Synopsis: hover,
FullDocumentation: hover,
}, nil
}

Expand Down
29 changes: 25 additions & 4 deletions gopls/internal/regtest/marker/testdata/hover/basiclit.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ package basiclit

func _() {
_ = 'a' //@hover("'a'", "'a'", latinA)
_ = 0x61 //@hover("0x61", "0x61", latinA)
_ = 0x61 //@hover("0x61", "0x61", latinAHex)

_ = '\u2211' //@hover("'\\u2211'", "'\\u2211'", summation)
_ = 0x2211 //@hover("0x2211", "0x2211", summation)
_ = 0x2211 //@hover("0x2211", "0x2211", summationHex)
_ = "foo \u2211 bar" //@hover("\\u2211", "\\u2211", summation)

_ = '\a' //@hover("'\\a'", "'\\a'", control)
_ = "foo \a bar" //@hover("\\a", "\\a", control)

_ = '\U0001F30A' //@hover("'\\U0001F30A'", "'\\U0001F30A'", waterWave)
_ = 0x0001F30A //@hover("0x0001F30A", "0x0001F30A", waterWave)
_ = 0x0001F30A //@hover("0x0001F30A", "0x0001F30A", waterWaveHex)
_ = 0X0001F30A //@hover("0X0001F30A", "0X0001F30A", waterWaveHex)
_ = "foo \U0001F30A bar" //@hover("\\U0001F30A", "\\U0001F30A", waterWave)

_ = '\x7E' //@hover("'\\x7E'", "'\\x7E'", tilde)
Expand Down Expand Up @@ -44,17 +45,37 @@ func _() {
_ = 1.2 //@hover("1.2", _, _)
_ = 1.2i //@hover("1.2i", _, _)
_ = 0123 //@hover("0123", _, _)
_ = 0x1234567890 //@hover("0x1234567890", _, _)
_ = 0b1001 //@hover("0b", "0b1001", binaryNumber)
_ = 0B1001 //@hover("0B", "0B1001", binaryNumber)
_ = 0o77 //@hover("0o", "0o77", octalNumber)
_ = 0O77 //@hover("0O", "0O77", octalNumber)
_ = 0x1234567890 //@hover("0x1234567890", "0x1234567890", hexNumber)
_ = 0X1234567890 //@hover("0X1234567890", "0X1234567890", hexNumber)
_ = 0x1000000000000000000 //@hover("0x1", "0x1000000000000000000", bigHex)
)
-- @bigHex/hover.md --
4722366482869645213696
-- @binaryNumber/hover.md --
9
-- @control/hover.md --
U+0007, control
-- @hexNumber/hover.md --
78187493520
-- @latinA/hover.md --
'a', U+0061, LATIN SMALL LETTER A
-- @latinAHex/hover.md --
97, 'a', U+0061, LATIN SMALL LETTER A
-- @leftCurly/hover.md --
'{', U+007B, LEFT CURLY BRACKET
-- @octalNumber/hover.md --
63
-- @summation/hover.md --
'∑', U+2211, N-ARY SUMMATION
-- @summationHex/hover.md --
8721, '∑', U+2211, N-ARY SUMMATION
-- @tilde/hover.md --
'~', U+007E, TILDE
-- @waterWave/hover.md --
'🌊', U+1F30A, WATER WAVE
-- @waterWaveHex/hover.md --
127754, '🌊', U+1F30A, WATER WAVE

0 comments on commit 0f415ef

Please sign in to comment.