2019-06-11 13:09:43 -06:00
|
|
|
// 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.
|
|
|
|
|
2019-06-07 08:04:22 -06:00
|
|
|
package source
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"go/ast"
|
2019-06-11 13:09:43 -06:00
|
|
|
"go/types"
|
2019-06-07 08:04:22 -06:00
|
|
|
|
|
|
|
"golang.org/x/tools/internal/span"
|
|
|
|
)
|
|
|
|
|
|
|
|
// ReferenceInfo holds information about reference to an identifier in Go source.
|
|
|
|
type ReferenceInfo struct {
|
2019-06-20 13:24:17 -06:00
|
|
|
Name string
|
|
|
|
Range span.Range
|
|
|
|
ident *ast.Ident
|
|
|
|
obj types.Object
|
|
|
|
isDeclaration bool
|
2019-06-07 08:04:22 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// References returns a list of references for a given identifier within a package.
|
|
|
|
func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, error) {
|
2019-06-24 14:34:21 -06:00
|
|
|
var references []*ReferenceInfo
|
|
|
|
if i.pkg == nil || i.pkg.IsIllTyped() {
|
2019-06-07 08:04:22 -06:00
|
|
|
return nil, fmt.Errorf("package for %s is ill typed", i.File.URI())
|
|
|
|
}
|
2019-06-24 14:34:21 -06:00
|
|
|
info := i.pkg.GetTypesInfo()
|
|
|
|
if info == nil {
|
|
|
|
return nil, fmt.Errorf("package %s has no types info", i.pkg.PkgPath())
|
2019-06-07 08:04:22 -06:00
|
|
|
}
|
|
|
|
// If the object declaration is nil, assume it is an import spec and do not look for references.
|
2019-06-14 12:55:24 -06:00
|
|
|
if i.decl.obj == nil {
|
2019-06-24 14:34:21 -06:00
|
|
|
return nil, fmt.Errorf("no references for an import spec")
|
2019-06-07 08:04:22 -06:00
|
|
|
}
|
2019-06-14 12:55:24 -06:00
|
|
|
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{
|
2019-06-20 13:24:17 -06:00
|
|
|
Name: i.decl.obj.Name(),
|
|
|
|
Range: i.decl.rng,
|
|
|
|
obj: i.decl.obj,
|
|
|
|
isDeclaration: true,
|
2019-06-14 12:55:24 -06:00
|
|
|
})
|
|
|
|
}
|
2019-06-24 14:34:21 -06:00
|
|
|
for ident, obj := range info.Defs {
|
2019-06-14 12:55:24 -06:00
|
|
|
if obj == nil || obj.Pos() != i.decl.obj.Pos() {
|
|
|
|
continue
|
2019-06-07 08:04:22 -06:00
|
|
|
}
|
2019-06-14 12:55:24 -06:00
|
|
|
references = append(references, &ReferenceInfo{
|
2019-06-20 13:24:17 -06:00
|
|
|
Name: ident.Name,
|
|
|
|
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()),
|
|
|
|
ident: ident,
|
|
|
|
obj: obj,
|
|
|
|
isDeclaration: true,
|
2019-06-14 12:55:24 -06:00
|
|
|
})
|
2019-06-07 08:04:22 -06:00
|
|
|
}
|
2019-06-24 14:34:21 -06:00
|
|
|
for ident, obj := range info.Uses {
|
2019-06-14 12:55:24 -06:00
|
|
|
if obj == nil || obj.Pos() != i.decl.obj.Pos() {
|
|
|
|
continue
|
2019-06-07 08:04:22 -06:00
|
|
|
}
|
2019-06-14 12:55:24 -06:00
|
|
|
references = append(references, &ReferenceInfo{
|
|
|
|
Name: ident.Name,
|
|
|
|
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()),
|
|
|
|
ident: ident,
|
2019-06-11 13:09:43 -06:00
|
|
|
obj: obj,
|
2019-06-14 12:55:24 -06:00
|
|
|
})
|
2019-06-07 08:04:22 -06:00
|
|
|
}
|
|
|
|
return references, nil
|
|
|
|
}
|