gopls/internal/lsp/source: eliminate a couple uses of posToMappedRange

Eliminate a couple uses of posToMappedRange, which potentially
type-checks, where it is clearly unnecessary.

Also improve test output for highlight.

Updates golang/go#57987
Updates golang/go#54845

Change-Id: I5580bf6431def0a6ee635e394932934ec7fe1afb
Reviewed-on: https://go-review.googlesource.com/c/tools/+/463556
TryBot-Result: Gopher Robot <gobot@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
diff --git a/gopls/internal/lsp/lsp_test.go b/gopls/internal/lsp/lsp_test.go
index eb5baf9..212ba0f 100644
--- a/gopls/internal/lsp/lsp_test.go
+++ b/gopls/internal/lsp/lsp_test.go
@@ -771,45 +771,56 @@
 	}
 }
 
-func (r *runner) Highlight(t *testing.T, src span.Span, locations []span.Span) {
+func (r *runner) Highlight(t *testing.T, src span.Span, spans []span.Span) {
 	m, err := r.data.Mapper(src.URI())
 	if err != nil {
 		t.Fatal(err)
 	}
 	loc, err := m.SpanLocation(src)
 	if err != nil {
-		t.Fatalf("failed for %v: %v", locations[0], err)
+		t.Fatal(err)
 	}
 	tdpp := protocol.TextDocumentPositionParams{
-		TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
-		Position:     loc.Range.Start,
+		TextDocument: protocol.TextDocumentIdentifier{
+			URI: loc.URI,
+		},
+		Position: loc.Range.Start,
+	}
+	if err != nil {
+		t.Fatalf("Mapper.SpanDocumentPosition(%v) failed: %v", src, err)
 	}
 	params := &protocol.DocumentHighlightParams{
 		TextDocumentPositionParams: tdpp,
 	}
 	highlights, err := r.server.DocumentHighlight(r.ctx, params)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("DocumentHighlight(%v) failed: %v", params, err)
 	}
-	if len(highlights) != len(locations) {
-		t.Fatalf("got %d highlights for highlight at %v:%v:%v, expected %d", len(highlights), src.URI().Filename(), src.Start().Line(), src.Start().Column(), len(locations))
+	var got []protocol.Range
+	for _, h := range highlights {
+		got = append(got, h.Range)
 	}
-	// Check to make sure highlights have a valid range.
-	var results []span.Span
-	for i := range highlights {
-		h, err := m.RangeSpan(highlights[i].Range)
+
+	var want []protocol.Range
+	for _, s := range spans {
+		rng, err := m.SpanRange(s)
 		if err != nil {
-			t.Fatalf("failed for %v: %v", highlights[i], err)
+			t.Fatalf("Mapper.SpanRange(%v) failed: %v", s, err)
 		}
-		results = append(results, h)
+		want = append(want, rng)
 	}
-	// Sort results to make tests deterministic since DocumentHighlight uses a map.
-	span.SortSpans(results)
-	// Check to make sure all the expected highlights are found.
-	for i := range results {
-		if results[i] != locations[i] {
-			t.Errorf("want %v, got %v\n", locations[i], results[i])
-		}
+
+	sortRanges := func(s []protocol.Range) {
+		sort.Slice(s, func(i, j int) bool {
+			return protocol.CompareRange(s[i], s[j]) < 0
+		})
+	}
+
+	sortRanges(got)
+	sortRanges(want)
+
+	if diff := cmp.Diff(want, got); diff != "" {
+		t.Errorf("DocumentHighlight(%v) mismatch (-want +got):\n%s", src, diff)
 	}
 }
 
diff --git a/gopls/internal/lsp/source/highlight.go b/gopls/internal/lsp/source/highlight.go
index 78718e5..e2f6c84 100644
--- a/gopls/internal/lsp/source/highlight.go
+++ b/gopls/internal/lsp/source/highlight.go
@@ -48,28 +48,28 @@
 			}
 		}
 	}
-	result, err := highlightPath(pkg, path)
+	result, err := highlightPath(path, pgf.File, pkg.GetTypesInfo())
 	if err != nil {
 		return nil, err
 	}
 	var ranges []protocol.Range
 	for rng := range result {
-		mRng, err := posToMappedRange(ctx, snapshot, pkg, rng.start, rng.end)
+		rng, err := pgf.PosRange(rng.start, rng.end)
 		if err != nil {
 			return nil, err
 		}
-		ranges = append(ranges, mRng.Range())
+		ranges = append(ranges, rng)
 	}
 	return ranges, nil
 }
 
-func highlightPath(pkg Package, path []ast.Node) (map[posRange]struct{}, error) {
+func highlightPath(path []ast.Node, file *ast.File, info *types.Info) (map[posRange]struct{}, error) {
 	result := make(map[posRange]struct{})
 	switch node := path[0].(type) {
 	case *ast.BasicLit:
 		if len(path) > 1 {
 			if _, ok := path[1].(*ast.ImportSpec); ok {
-				err := highlightImportUses(pkg, path, result)
+				err := highlightImportUses(path, info, result)
 				return result, err
 			}
 		}
@@ -77,7 +77,9 @@
 	case *ast.ReturnStmt, *ast.FuncDecl, *ast.FuncType:
 		highlightFuncControlFlow(path, result)
 	case *ast.Ident:
-		highlightIdentifiers(pkg, path, result)
+		// Check if ident is inside return or func decl.
+		highlightFuncControlFlow(path, result)
+		highlightIdentifier(node, file, info, result)
 	case *ast.ForStmt, *ast.RangeStmt:
 		highlightLoopControlFlow(path, result)
 	case *ast.SwitchStmt:
@@ -426,7 +428,7 @@
 	return stmt.Label
 }
 
-func highlightImportUses(pkg Package, path []ast.Node, result map[posRange]struct{}) error {
+func highlightImportUses(path []ast.Node, info *types.Info, result map[posRange]struct{}) error {
 	basicLit, ok := path[0].(*ast.BasicLit)
 	if !ok {
 		return fmt.Errorf("highlightImportUses called with an ast.Node of type %T", basicLit)
@@ -440,7 +442,7 @@
 		if !ok {
 			return true
 		}
-		obj, ok := pkg.GetTypesInfo().ObjectOf(n).(*types.PkgName)
+		obj, ok := info.ObjectOf(n).(*types.PkgName)
 		if !ok {
 			return true
 		}
@@ -453,19 +455,16 @@
 	return nil
 }
 
-func highlightIdentifiers(pkg Package, path []ast.Node, result map[posRange]struct{}) error {
-	id, ok := path[0].(*ast.Ident)
-	if !ok {
-		return fmt.Errorf("highlightIdentifiers called with an ast.Node of type %T", id)
-	}
-	// Check if ident is inside return or func decl.
-	highlightFuncControlFlow(path, result)
-
-	// TODO: maybe check if ident is a reserved word, if true then don't continue and return results.
-
-	idObj := pkg.GetTypesInfo().ObjectOf(id)
+func highlightIdentifier(id *ast.Ident, file *ast.File, info *types.Info, result map[posRange]struct{}) {
+	// TODO(rfindley): idObj may be nil. Note that returning early in this case
+	// causes tests to fail (because the nObj == idObj check below was succeeded
+	// for nil == nil!)
+	//
+	// Revisit this. If ObjectOf is nil, there are type errors, and it seems
+	// reasonable for identifier highlighting not to work.
+	idObj := info.ObjectOf(id)
 	pkgObj, isImported := idObj.(*types.PkgName)
-	ast.Inspect(path[len(path)-1], func(node ast.Node) bool {
+	ast.Inspect(file, func(node ast.Node) bool {
 		if imp, ok := node.(*ast.ImportSpec); ok && isImported {
 			highlightImport(pkgObj, imp, result)
 		}
@@ -476,12 +475,11 @@
 		if n.Name != id.Name {
 			return false
 		}
-		if nObj := pkg.GetTypesInfo().ObjectOf(n); nObj == idObj {
+		if nObj := info.ObjectOf(n); nObj == idObj {
 			result[posRange{start: n.Pos(), end: n.End()}] = struct{}{}
 		}
 		return false
 	})
-	return nil
 }
 
 func highlightImport(obj *types.PkgName, imp *ast.ImportSpec, result map[posRange]struct{}) {
diff --git a/gopls/internal/lsp/source/references.go b/gopls/internal/lsp/source/references.go
index 1fc7fde..5f3fdbb 100644
--- a/gopls/internal/lsp/source/references.go
+++ b/gopls/internal/lsp/source/references.go
@@ -141,7 +141,12 @@
 					continue
 				}
 				seen[key] = true
-				rng, err := posToMappedRange(ctx, snapshot, pkg, ident.Pos(), ident.End())
+				filename := pkg.FileSet().File(ident.Pos()).Name()
+				pgf, err := pkg.File(span.URIFromPath(filename))
+				if err != nil {
+					return nil, err
+				}
+				rng, err := pgf.PosMappedRange(ident.Pos(), ident.End())
 				if err != nil {
 					return nil, err
 				}