1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:04:44 -07:00
go/internal/lsp/source/references.go
Rebecca Stambler 3b4f30a44f internal/lsp: remove helpers for getting packages
We had too many options for functions to use to get type information for
a package. Now we stick with having one option to get the check package
handles, and then the caller can refine the results as needed.

Change-Id: I81f69a670e1539854ee23b6f364159a7de9b782f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/194457
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-09-17 16:23:42 +00:00

98 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")
}
info := i.pkg.GetTypesInfo()
if info == nil {
return nil, errors.Errorf("package %s has no types info", i.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: i.pkg,
isDeclaration: true,
})
}
for ident, obj := range info.Defs {
if obj == nil || !sameObj(obj, i.Declaration.obj) {
continue
}
rng, err := posToMappedRange(ctx, i.View, i.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: i.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, i.pkg, ident.Pos(), ident.End())
if err != nil {
return nil, err
}
references = append(references, &ReferenceInfo{
Name: ident.Name,
ident: ident,
pkg: i.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()
}