1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:44:43 -07:00

internal/lsp: improve highlighting functionality for fields and methods

Modified the way highlights are tested to allow for author to explicitly
mark the matches. Also added highlighting for fields and methods. Used
type checking in addition to ast to get better matching. Worked with
@stamblerre

Updates #34496

Change-Id: I462703e0011c4e0a4b98016e9c25af9bf1ead0b9
Reviewed-on: https://go-review.googlesource.com/c/tools/+/207899
Run-TryBot: Rohan Challa <rohan@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Rohan Challa 2019-11-19 14:18:53 -05:00 committed by Rohan Challa
parent b3340bdf36
commit 0a33398bd9
7 changed files with 89 additions and 34 deletions

View File

@ -65,7 +65,7 @@ func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completi
//TODO: add command line completions tests when it works
}
func (r *runner) Highlight(t *testing.T, name string, locations []span.Span) {
func (r *runner) Highlight(t *testing.T, src span.Span, locations []span.Span) {
//TODO: add command line highlight tests when it works
}

View File

@ -470,7 +470,7 @@ func (r *runner) Implementation(t *testing.T, spn span.Span, m tests.Implementat
}
}
func (r *runner) Highlight(t *testing.T, name string, locations []span.Span) {
func (r *runner) Highlight(t *testing.T, src span.Span, locations []span.Span) {
m, err := r.data.Mapper(locations[0].URI())
if err != nil {
t.Fatal(err)
@ -491,7 +491,7 @@ func (r *runner) Highlight(t *testing.T, name string, locations []span.Span) {
t.Fatal(err)
}
if len(highlights) != len(locations) {
t.Fatalf("got %d highlights for %s, expected %d", len(highlights), name, 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))
}
for i := range highlights {
if h, err := m.RangeSpan(highlights[i].Range); err != nil {

View File

@ -23,8 +23,27 @@ func Highlight(ctx context.Context, view View, uri span.URI, pos protocol.Positi
if err != nil {
return nil, err
}
fh := view.Snapshot().Handle(ctx, f)
ph := view.Session().Cache().ParseGoHandle(fh, ParseFull)
_, cphs, err := view.CheckPackageHandles(ctx, f)
if err != nil {
return nil, err
}
cph, err := WidestCheckPackageHandle(cphs)
if err != nil {
return nil, err
}
pkg, err := cph.Check(ctx)
if err != nil {
return nil, err
}
var ph ParseGoHandle
for _, file := range pkg.Files() {
if file.File().Identity().URI == f.URI() {
ph = file
}
}
if ph == nil {
return nil, errors.Errorf("no ParseGoHandle for %s", f.URI())
}
file, m, _, err := ph.Parse(ctx)
if err != nil {
return nil, err
@ -41,22 +60,35 @@ func Highlight(ctx context.Context, view View, uri span.URI, pos protocol.Positi
if len(path) == 0 {
return nil, errors.Errorf("no enclosing position found for %v:%v", int(pos.Line), int(pos.Character))
}
result := []protocol.Range{}
id, ok := path[0].(*ast.Ident)
if !ok {
// If the cursor is not within an identifier, return empty results.
return []protocol.Range{}, nil
return result, nil
}
var result []protocol.Range
if id.Obj != nil {
ast.Inspect(path[len(path)-1], func(n ast.Node) bool {
if n, ok := n.(*ast.Ident); ok && n.Obj == id.Obj {
rng, err := nodeToProtocolRange(ctx, view, m, n)
if err == nil {
result = append(result, rng)
}
}
idObj := pkg.GetTypesInfo().ObjectOf(id)
ast.Inspect(path[len(path)-1], func(node ast.Node) bool {
n, ok := node.(*ast.Ident)
if !ok {
return true
})
}
}
if n.Name != id.Name {
return true
}
if n.Obj != id.Obj {
return true
}
nodeObj := pkg.GetTypesInfo().ObjectOf(n)
if nodeObj != idObj {
return false
}
if rng, err := nodeToProtocolRange(ctx, view, m, n); err == nil {
result = append(result, rng)
}
return true
})
return result, nil
}

View File

@ -580,9 +580,8 @@ func (r *runner) Implementation(t *testing.T, spn span.Span, m tests.Implementat
}
}
func (r *runner) Highlight(t *testing.T, name string, locations []span.Span) {
func (r *runner) Highlight(t *testing.T, src span.Span, locations []span.Span) {
ctx := r.ctx
src := locations[0]
m, srcRng, err := spanToRange(r.data, src)
if err != nil {
t.Fatal(err)
@ -592,7 +591,7 @@ func (r *runner) Highlight(t *testing.T, name string, locations []span.Span) {
t.Errorf("highlight failed for %s: %v", src.URI(), err)
}
if len(highlights) != len(locations) {
t.Errorf("got %d highlights for %s, expected %d", len(highlights), name, len(locations))
t.Errorf("got %d highlights for highlight at %v:%v:%v, expected %d", len(highlights), src.URI().Filename(), src.Start().Line(), src.Start().Column(), len(locations))
}
for i, got := range highlights {
want, err := m.Range(locations[i])

View File

@ -1,15 +1,38 @@
package highlights
import "fmt"
import (
"fmt"
"golang.org/x/tools/internal/lsp/protocol"
)
type F struct{ bar int }
var foo = F{bar: 52} //@highlight("foo", "foo")
var foo = F{bar: 52} //@mark(fooDeclaration, "foo"),highlight(fooDeclaration, fooDeclaration, fooUse)
func Print() {
fmt.Println(foo) //@highlight("foo", "foo")
func Print() { //@mark(printFunc, "Print"),highlight(printFunc, printFunc, printTest)
fmt.Println(foo) //@mark(fooUse, "foo"),highlight(fooUse, fooDeclaration, fooUse)
fmt.Print("yo") //@mark(printSep, "Print"),highlight(printSep, printSep, print1, print2)
}
func (x *F) Inc() { //@highlight("x", "x")
x.bar++ //@highlight("x", "x")
func (x *F) Inc() { //@mark(xDeclaration, "x"),highlight(xDeclaration, xDeclaration, xUse)
x.bar++ //@mark(xUse, "x"),highlight(xUse, xDeclaration, xUse)
}
func testFunctions() {
fmt.Print("main start") //@mark(print1, "Print"),highlight(print1, printSep, print1, print2)
fmt.Print("ok") //@mark(print2, "Print"),highlight(print2, printSep, print1, print2)
Print() //@mark(printTest, "Print"),highlight(printTest, printFunc, printTest)
}
func toProtocolHighlight(rngs []protocol.Range) []protocol.DocumentHighlight { //@mark(doc1, "DocumentHighlight"),highlight(doc1, doc1, doc2, doc3)
result := make([]protocol.DocumentHighlight, 0, len(rngs)) //@mark(doc2, "DocumentHighlight"),highlight(doc2, doc1, doc2, doc3)
kind := protocol.Text
for _, rng := range rngs {
result = append(result, protocol.DocumentHighlight{ //@mark(doc3, "DocumentHighlight"),highlight(doc3, doc1, doc2, doc3)
Kind: kind,
Range: rng,
})
}
return result
}

View File

@ -13,7 +13,7 @@ ImportCount = 7
SuggestedFixCount = 1
DefinitionsCount = 38
TypeDefinitionsCount = 2
HighlightsCount = 2
HighlightsCount = 12
ReferencesCount = 7
RenamesCount = 22
PrepareRenamesCount = 8

View File

@ -53,7 +53,7 @@ type Imports []span.Span
type SuggestedFixes []span.Span
type Definitions map[span.Span]Definition
type Implementationses map[span.Span]Implementations
type Highlights map[string][]span.Span
type Highlights map[span.Span][]span.Span
type References map[span.Span][]span.Span
type Renames map[span.Span]string
type PrepareRenames map[span.Span]*source.PrepareItem
@ -113,7 +113,7 @@ type Tests interface {
SuggestedFix(*testing.T, span.Span)
Definition(*testing.T, span.Span, Definition)
Implementation(*testing.T, span.Span, Implementations)
Highlight(*testing.T, string, []span.Span)
Highlight(*testing.T, span.Span, []span.Span)
References(*testing.T, span.Span, []span.Span)
Rename(*testing.T, span.Span, string)
PrepareRename(*testing.T, span.Span, *source.PrepareItem)
@ -479,10 +479,10 @@ func Run(t *testing.T, tests Tests, data *Data) {
t.Run("Highlight", func(t *testing.T) {
t.Helper()
for name, locations := range data.Highlights {
t.Run(name, func(t *testing.T) {
for pos, locations := range data.Highlights {
t.Run(spanName(pos), func(t *testing.T) {
t.Helper()
tests.Highlight(t, name, locations)
tests.Highlight(t, pos, locations)
})
}
})
@ -826,8 +826,9 @@ func (data *Data) collectDefinitionNames(src span.Span, name string) {
data.Definitions[src] = d
}
func (data *Data) collectHighlights(name string, rng span.Span) {
data.Highlights[name] = append(data.Highlights[name], rng)
func (data *Data) collectHighlights(src span.Span, expected []span.Span) {
// Declaring a highlight in a test file: @highlight(src, expected1, expected2)
data.Highlights[src] = append(data.Highlights[src], expected...)
}
func (data *Data) collectReferences(src span.Span, expected []span.Span) {