From 6d1e33f1d0d12eab80f5cdf8432b0f6684c7f0ff Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Wed, 22 Sep 2021 19:03:50 -0400 Subject: [PATCH] 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 Trust: Rebecca Stambler gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Robert Findley --- gopls/internal/regtest/misc/hover_test.go | 17 +++++++++++++++++ internal/lsp/source/hover.go | 20 +++++++------------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/gopls/internal/regtest/misc/hover_test.go b/gopls/internal/regtest/misc/hover_test.go index fbd0ac5c9e5..293a26abf6a 100644 --- a/gopls/internal/regtest/misc/hover_test.go +++ b/gopls/internal/regtest/misc/hover_test.go @@ -8,6 +8,7 @@ import ( "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 @@ type Example struct` 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 a2c731a71bf..2039dfe5bae 100644 --- a/internal/lsp/source/hover.go +++ b/internal/lsp/source/hover.go @@ -137,12 +137,12 @@ func hoverRune(ctx context.Context, snapshot Snapshot, fh FileHandle, position p 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 @@ func findRune(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protoco 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 @@ func findRune(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protoco 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 @@ func findRune(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protoco // 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 {