mirror of
https://github.com/golang/go
synced 2024-09-30 22:58:34 -06:00
abb7e64e89
A client can specify "IncludeDeclaration" in its ReferenceParams. When they do so, we want to include the declaration, even if it was not in the scope we searched for references. Additionally, we also return the location of the declaration first in the result array when it is included in the results. Updates golang/go#32572 Change-Id: I12837cd98102ee8d531f0f4bac2fb7bded2564c0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/184723 Run-TryBot: Suzy Mueller <suzmue@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
85 lines
2.5 KiB
Go
85 lines
2.5 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"
|
|
"fmt"
|
|
"go/ast"
|
|
"go/types"
|
|
|
|
"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
|
|
obj types.Object
|
|
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) {
|
|
var references []*ReferenceInfo
|
|
|
|
// If the object declaration is nil, assume it is an import spec and do not look for references.
|
|
if i.decl.obj == nil {
|
|
return nil, fmt.Errorf("no references for an import spec")
|
|
}
|
|
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. Both implicits are local to a file.
|
|
references = append(references, &ReferenceInfo{
|
|
Name: i.decl.obj.Name(),
|
|
Range: i.decl.rng,
|
|
obj: i.decl.obj,
|
|
isDeclaration: true,
|
|
})
|
|
}
|
|
|
|
pkgs := i.File.GetPackages(ctx)
|
|
for _, pkg := range pkgs {
|
|
if pkg == nil || pkg.IsIllTyped() {
|
|
return nil, fmt.Errorf("package for %s is ill typed", i.File.URI())
|
|
}
|
|
info := pkg.GetTypesInfo()
|
|
if info == nil {
|
|
return nil, fmt.Errorf("package %s has no types info", pkg.PkgPath())
|
|
}
|
|
for ident, obj := range info.Defs {
|
|
// TODO(suzmue): support the case where an identifier may have two different declarations.
|
|
if obj == nil || obj.Pos() != i.decl.obj.Pos() {
|
|
continue
|
|
}
|
|
// Add the declarations at the beginning of the references list.
|
|
references = append([]*ReferenceInfo{&ReferenceInfo{
|
|
Name: ident.Name,
|
|
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()),
|
|
ident: ident,
|
|
obj: obj,
|
|
isDeclaration: true,
|
|
}}, references...)
|
|
}
|
|
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
|
|
}
|