1
0
mirror of https://github.com/golang/go synced 2024-11-19 01:44:40 -07:00
go/internal/lsp/source/references.go
Rebecca Stambler 3cbd95df51 internal/lsp: support a file belonging to multiple packages
This change adds supports for a package belonging to multiple files.
It requires additional packages.Loads for all of the packages to which a
file belongs (for example, if a non-test file also belongs to a package's
test variant).

For now, we re-run go/packages.Load for each file we open, regardless of
whether or not we already know about it.

This solves the issue of packages randomly belonging to a test or not.
Follow-up work needs to be done to support multiple packages in
references, rename, and diagnostics.

Fixes golang/go#32791
Fixes golang/go#30100

Change-Id: I0a5870a05825fc16cc46d405ef50c775094b0fbb
Reviewed-on: https://go-review.googlesource.com/c/tools/+/183628
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-06-26 17:56:19 +00:00

75 lines
2.1 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 a package.
func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, error) {
var references []*ReferenceInfo
if i.pkg == nil || i.pkg.IsIllTyped() {
return nil, fmt.Errorf("package for %s is ill typed", i.File.URI())
}
info := i.pkg.GetTypesInfo()
if info == nil {
return nil, fmt.Errorf("package %s has no types info", i.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 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.
references = append(references, &ReferenceInfo{
Name: i.decl.obj.Name(),
Range: i.decl.rng,
obj: i.decl.obj,
isDeclaration: true,
})
}
for ident, obj := range info.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,
obj: obj,
isDeclaration: true,
})
}
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
}