internal/lsp: handle panic in hoverRune by using token.Pos
All operations within a file should be in terms of token.Pos, until the
value must be returned.
Fixes golang/go#48492
Change-Id: I2adfcad8b4729386700c08ba4618e033bf7c3db5
Reviewed-on: https://go-review.googlesource.com/c/tools/+/351629
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Trust: Rebecca Stambler <rstambler@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/gopls/internal/regtest/misc/hover_test.go b/gopls/internal/regtest/misc/hover_test.go
index fbd0ac5..293a26a 100644
--- a/gopls/internal/regtest/misc/hover_test.go
+++ b/gopls/internal/regtest/misc/hover_test.go
@@ -8,6 +8,7 @@
"strings"
"testing"
+ "golang.org/x/tools/internal/lsp/fake"
. "golang.org/x/tools/internal/lsp/regtest"
"golang.org/x/tools/internal/testenv"
)
@@ -113,3 +114,19 @@
env.Editor.Hover(env.Ctx, "main.go", env.RegexpSearch("main.go", "Example"))
})
}
+
+func TestHoverRune_48492(t *testing.T) {
+ const files = `
+-- go.mod --
+module mod.com
+
+go 1.18
+-- main.go --
+package main
+`
+ Run(t, files, func(t *testing.T, env *Env) {
+ env.OpenFile("main.go")
+ env.EditBuffer("main.go", fake.NewEdit(0, 0, 1, 0, "package main\nfunc main() {\nconst x = `\nfoo\n`\n}"))
+ env.Editor.Hover(env.Ctx, "main.go", env.RegexpSearch("main.go", "foo"))
+ })
+}
diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go
index a2c731a..2039dfe 100644
--- a/internal/lsp/source/hover.go
+++ b/internal/lsp/source/hover.go
@@ -137,12 +137,12 @@
var ErrNoRuneFound = errors.New("no rune found")
// findRune returns rune information for a position in a file.
-func findRune(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) (rune, MappedRange, error) {
+func findRune(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) (rune, MappedRange, error) {
pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
if err != nil {
return 0, MappedRange{}, err
}
- spn, err := pgf.Mapper.PointSpan(pos)
+ spn, err := pgf.Mapper.PointSpan(position)
if err != nil {
return 0, MappedRange{}, err
}
@@ -150,6 +150,7 @@
if err != nil {
return 0, MappedRange{}, err
}
+ pos := rng.Start
// Find the basic literal enclosing the given position, if there is one.
var lit *ast.BasicLit
@@ -158,7 +159,7 @@
if found {
return false
}
- if n, ok := n.(*ast.BasicLit); ok && rng.Start >= n.Pos() && rng.Start <= n.End() {
+ if n, ok := n.(*ast.BasicLit); ok && pos >= n.Pos() && pos <= n.End() {
lit = n
found = true
}
@@ -202,16 +203,9 @@
// It's a string, scan only if it contains a unicode escape sequence under or before the
// current cursor position.
var found bool
- strMappedRng, err := posToMappedRange(snapshot, pkg, lit.Pos(), lit.End())
- if err != nil {
- return 0, MappedRange{}, err
- }
- strRng, err := strMappedRng.Range()
- if err != nil {
- return 0, MappedRange{}, err
- }
- offset := strRng.Start.Character
- for i := pos.Character - offset; i > 0; i-- {
+ litOffset := pgf.Tok.Offset(lit.Pos())
+ offset := pgf.Tok.Offset(pos)
+ for i := offset - litOffset; i > 0; i-- {
// Start at the cursor position and search backward for the beginning of a rune escape sequence.
rr, _ := utf8.DecodeRuneInString(lit.Value[i:])
if rr == utf8.RuneError {