internal/lsp: find references in test packages

Find references to identifiers in both a package and its test package.

Change-Id: I9d9da4aa37c36c448336aed044df79cfd1c903f1
Reviewed-on: https://go-review.googlesource.com/c/tools/+/183990
Run-TryBot: Suzy Mueller <suzmue@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Suzy Mueller 2019-06-26 18:05:29 -04:00
parent e750c417fb
commit 58bb5bbe30
7 changed files with 68 additions and 43 deletions

View File

@ -474,7 +474,11 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
want := make(map[protocol.Location]bool) want := make(map[protocol.Location]bool)
for _, pos := range itemList { for _, pos := range itemList {
loc, err := sm.Location(pos) m, err := r.mapper(pos.URI())
if err != nil {
t.Fatal(err)
}
loc, err := m.Location(pos)
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", src, err) t.Fatalf("failed for %v: %v", src, err)
} }
@ -491,12 +495,12 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
t.Fatalf("failed for %v: %v", src, err) t.Fatalf("failed for %v: %v", src, err)
} }
if len(got) != len(itemList) { if len(got) != len(want) {
t.Errorf("references failed: different lengths got %v want %v", len(got), len(itemList)) t.Errorf("references failed: different lengths got %v want %v", len(got), len(want))
} }
for _, loc := range got { for _, loc := range got {
if !want[loc] { if !want[loc] {
t.Errorf("references failed: incorrect references got %v want %v", got, want) t.Errorf("references failed: incorrect references got %v want %v", loc, want)
} }
} }
} }

View File

@ -38,11 +38,17 @@ func (s *Server) references(ctx context.Context, params *protocol.ReferenceParam
} }
// Get the location of each reference to return as the result. // Get the location of each reference to return as the result.
locations := make([]protocol.Location, 0, len(references)) locations := make([]protocol.Location, 0, len(references))
seen := make(map[span.Span]bool)
for _, ref := range references { for _, ref := range references {
refSpan, err := ref.Range.Span() refSpan, err := ref.Range.Span()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if seen[refSpan] {
continue // already added this location
}
seen[refSpan] = true
_, refM, err := getSourceFile(ctx, view, refSpan.URI()) _, refM, err := getSourceFile(ctx, view, refSpan.URI())
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -22,16 +22,11 @@ type ReferenceInfo struct {
isDeclaration bool isDeclaration bool
} }
// References returns a list of references for a given identifier within a package. // References returns a list of references for a given identifier within the packages
// containing i.File.
func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, error) { func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, error) {
var references []*ReferenceInfo var references []*ReferenceInfo
if i.pkg == nil || i.pkg.IsIllTyped() {
return nil, fmt.Errorf("package for %s is ill typed", i.File.URI())
}
info := i.pkg.GetTypesInfo()
if info == nil {
return nil, fmt.Errorf("package %s has no types info", i.pkg.PkgPath())
}
// If the object declaration is nil, assume it is an import spec and do not look for references. // If the object declaration is nil, assume it is an import spec and do not look for references.
if i.decl.obj == nil { if i.decl.obj == nil {
return nil, fmt.Errorf("no references for an import spec") return nil, fmt.Errorf("no references for an import spec")
@ -39,7 +34,7 @@ func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, erro
if i.decl.wasImplicit { if i.decl.wasImplicit {
// The definition is implicit, so we must add it separately. // The definition is implicit, so we must add it separately.
// This occurs when the variable is declared in a type switch statement // This occurs when the variable is declared in a type switch statement
// or is an implicit package name. // or is an implicit package name. Both implicits are local to a file.
references = append(references, &ReferenceInfo{ references = append(references, &ReferenceInfo{
Name: i.decl.obj.Name(), Name: i.decl.obj.Name(),
Range: i.decl.rng, Range: i.decl.rng,
@ -47,28 +42,42 @@ func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, erro
isDeclaration: true, isDeclaration: true,
}) })
} }
for ident, obj := range info.Defs {
if obj == nil || obj.Pos() != i.decl.obj.Pos() { pkgs := i.File.GetPackages(ctx)
continue for _, pkg := range pkgs {
if pkg == nil || pkg.IsIllTyped() {
return nil, fmt.Errorf("package for %s is ill typed", i.File.URI())
} }
references = append(references, &ReferenceInfo{ info := pkg.GetTypesInfo()
Name: ident.Name, if info == nil {
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()), return nil, fmt.Errorf("package %s has no types info", pkg.PkgPath())
ident: ident,
obj: obj,
isDeclaration: true,
})
}
for ident, obj := range info.Uses {
if obj == nil || obj.Pos() != i.decl.obj.Pos() {
continue
} }
references = append(references, &ReferenceInfo{ for ident, obj := range info.Defs {
Name: ident.Name, // TODO(suzmue): support the case where an identifier may have two different declarations.
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()), if obj == nil || obj.Pos() != i.decl.obj.Pos() {
ident: ident, continue
obj: obj, }
}) references = append(references, &ReferenceInfo{
Name: ident.Name,
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()),
ident: ident,
obj: obj,
isDeclaration: true,
})
}
for ident, obj := range info.Uses {
if obj == nil || obj.Pos() != i.decl.obj.Pos() {
continue
}
references = append(references, &ReferenceInfo{
Name: ident.Name,
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()),
ident: ident,
obj: obj,
})
}
} }
return references, nil return references, nil
} }

View File

@ -450,20 +450,26 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
want[pos] = true want[pos] = true
} }
got, err := ident.References(ctx) refs, err := ident.References(ctx)
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", src, err) t.Fatalf("failed for %v: %v", src, err)
} }
if len(got) != len(itemList) { got := make(map[span.Span]bool)
t.Errorf("references failed: different lengths got %v want %v", len(got), len(itemList)) for _, refInfo := range refs {
}
for _, refInfo := range got {
refSpan, err := refInfo.Range.Span() refSpan, err := refInfo.Range.Span()
if err != nil { if err != nil {
t.Errorf("failed for %v item %v: %v", src, refInfo.Name, err) t.Errorf("failed for %v item %v: %v", src, refInfo.Name, err)
} }
if !want[refSpan] { got[refSpan] = true
}
if len(got) != len(want) {
t.Errorf("references failed: different lengths got %v want %v", len(got), len(want))
}
for spn, _ := range got {
if !want[spn] {
t.Errorf("references failed: incorrect references got %v want locations %v", got, want) t.Errorf("references failed: incorrect references got %v want locations %v", got, want)
} }
} }

View File

@ -1,5 +1,5 @@
package testy package testy
func a() { //@item(funcA, "a()", "", "func") func a() { //@mark(identA, "a"),item(funcA, "a()", "", "func"),refs("a", identA, testyA)
//@complete("", funcA) //@complete("", funcA)
} }

View File

@ -3,6 +3,6 @@ package testy
import "testing" import "testing"
func TestSomething(t *testing.T) { //@item(TestSomething, "TestSomething(t *testing.T)", "", "func") func TestSomething(t *testing.T) { //@item(TestSomething, "TestSomething(t *testing.T)", "", "func")
var x int //@diag("x", "LSP", "x declared but not used") var x int //@mark(testyX, "x"),diag("x", "LSP", "x declared but not used"),refs("x", testyX)
a() a() //@mark(testyA, "a")
} }

View File

@ -33,7 +33,7 @@ const (
ExpectedDefinitionsCount = 38 ExpectedDefinitionsCount = 38
ExpectedTypeDefinitionsCount = 2 ExpectedTypeDefinitionsCount = 2
ExpectedHighlightsCount = 2 ExpectedHighlightsCount = 2
ExpectedReferencesCount = 2 ExpectedReferencesCount = 4
ExpectedRenamesCount = 8 ExpectedRenamesCount = 8
ExpectedSymbolsCount = 1 ExpectedSymbolsCount = 1
ExpectedSignaturesCount = 20 ExpectedSignaturesCount = 20