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 {