1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:14:46 -07:00
go/internal/lsp/source/references.go
Suzy Mueller b76e30ffa0 internal/lsp: fix references for type switch vars
Implicit local variables for type switches do not appear in the Uses
map and do not have objects associated with them.  This change
associates all of the different types objects for the same local type
switch declaration with one another in the declaration.

The identifier for the implicit local variable does not have a type but
does have declaration objects.

Find references for type switch vars will return references to all the
identifiers in all of the case clauses and the declaration.

Fixes golang/go#32584

Change-Id: I5563a2a48d31ca615c1e4e73b46eabca0f5dd72a
Reviewed-on: https://go-review.googlesource.com/c/tools/+/182462
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-06-19 18:18:01 +00:00

70 lines
1.7 KiB
Go

package source
import (
"context"
"fmt"
"go/ast"
"golang.org/x/tools/internal/span"
)
// ReferenceInfo holds information about reference to an identifier in Go source.
type ReferenceInfo struct {
Name string
Range span.Range
ident *ast.Ident
}
// References returns a list of references for a given identifier within a package.
func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, error) {
pkg := i.File.GetPackage(ctx)
if pkg == nil || pkg.IsIllTyped() {
return nil, fmt.Errorf("package for %s is ill typed", i.File.URI())
}
pkgInfo := pkg.GetTypesInfo()
if pkgInfo == nil {
return nil, fmt.Errorf("package %s has no types info", pkg.PkgPath())
}
// If the object declaration is nil, assume it is an import spec and do not look for references.
if i.decl.obj == nil {
return []*ReferenceInfo{}, nil
}
var references []*ReferenceInfo
if i.decl.wasImplicit {
// The definition is implicit, so we must add it separately.
// This occurs when the variable is declared in a type switch statement
// or is an implicit package name.
references = append(references, &ReferenceInfo{
Name: i.decl.obj.Name(),
Range: i.decl.rng,
})
}
for ident, obj := range pkgInfo.Defs {
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,
})
}
for ident, obj := range pkgInfo.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,
})
}
return references, nil
}