mirror of
https://github.com/golang/go
synced 2024-11-18 16:44:43 -07:00
2dc213d980
This function incorrectly used cached packages to get ASTs and type information that should have been directly found from the origin package. Shift to using pkg.FindFile instead. Change-Id: I9f73209bb1a1343f53b430150e78ffd180e14a44 Reviewed-on: https://go-review.googlesource.com/c/tools/+/195797 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
100 lines
2.9 KiB
Go
100 lines
2.9 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package source
|
|
|
|
import (
|
|
"context"
|
|
"go/ast"
|
|
"go/types"
|
|
|
|
"golang.org/x/tools/internal/telemetry/trace"
|
|
errors "golang.org/x/xerrors"
|
|
)
|
|
|
|
// ReferenceInfo holds information about reference to an identifier in Go source.
|
|
type ReferenceInfo struct {
|
|
Name string
|
|
mappedRange
|
|
ident *ast.Ident
|
|
obj types.Object
|
|
pkg Package
|
|
isDeclaration bool
|
|
}
|
|
|
|
// References returns a list of references for a given identifier within the packages
|
|
// containing i.File. Declarations appear first in the result.
|
|
func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, error) {
|
|
ctx, done := trace.StartSpan(ctx, "source.References")
|
|
defer done()
|
|
var references []*ReferenceInfo
|
|
|
|
// If the object declaration is nil, assume it is an import spec and do not look for references.
|
|
if i.Declaration.obj == nil {
|
|
return nil, errors.Errorf("no references for an import spec")
|
|
}
|
|
for _, pkg := range i.pkgs {
|
|
info := pkg.GetTypesInfo()
|
|
if info == nil {
|
|
return nil, errors.Errorf("package %s has no types info", pkg.PkgPath())
|
|
}
|
|
|
|
if i.Declaration.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. Both implicits are local to a file.
|
|
references = append(references, &ReferenceInfo{
|
|
Name: i.Declaration.obj.Name(),
|
|
mappedRange: i.Declaration.mappedRange,
|
|
obj: i.Declaration.obj,
|
|
pkg: pkg,
|
|
isDeclaration: true,
|
|
})
|
|
}
|
|
for ident, obj := range info.Defs {
|
|
if obj == nil || !sameObj(obj, i.Declaration.obj) {
|
|
continue
|
|
}
|
|
rng, err := posToMappedRange(ctx, i.View, pkg, ident.Pos(), ident.End())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Add the declarations at the beginning of the references list.
|
|
references = append([]*ReferenceInfo{{
|
|
Name: ident.Name,
|
|
ident: ident,
|
|
obj: obj,
|
|
pkg: pkg,
|
|
isDeclaration: true,
|
|
mappedRange: rng,
|
|
}}, references...)
|
|
}
|
|
for ident, obj := range info.Uses {
|
|
if obj == nil || !sameObj(obj, i.Declaration.obj) {
|
|
continue
|
|
}
|
|
rng, err := posToMappedRange(ctx, i.View, pkg, ident.Pos(), ident.End())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
references = append(references, &ReferenceInfo{
|
|
Name: ident.Name,
|
|
ident: ident,
|
|
pkg: pkg,
|
|
obj: obj,
|
|
mappedRange: rng,
|
|
})
|
|
}
|
|
}
|
|
return references, nil
|
|
}
|
|
|
|
// sameObj returns true if obj is the same as declObj.
|
|
// Objects are the same if they have the some Pos and Name.
|
|
func sameObj(obj, declObj types.Object) bool {
|
|
// TODO(suzmue): support the case where an identifier may have two different
|
|
// declaration positions.
|
|
return obj.Pos() == declObj.Pos() && obj.Name() == declObj.Name()
|
|
}
|