mirror of
https://github.com/golang/go
synced 2024-11-18 21:14:44 -07:00
7201abb308
The initial workspace load was happening when a view was created, in serial. It should really just be kicked off in a separate goroutine once we create a new view. Implementing this change required some other significant changes, particularly the additional work being done by the WorkspacePackageIDs method. Some other changes had to be made while debugging. In particular, the modification to the circular dependencies test was a consequence of golang/go#36265. Change-Id: I97586c9574f6c4106172d7983e4c6fad412e6aa1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/212102 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
113 lines
3.3 KiB
Go
113 lines
3.3 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/go/types/objectpath"
|
|
"golang.org/x/tools/internal/lsp/telemetry"
|
|
"golang.org/x/tools/internal/telemetry/log"
|
|
"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()
|
|
|
|
// 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())
|
|
}
|
|
var searchpkgs []Package
|
|
if i.Declaration.obj.Exported() {
|
|
// Only search all packages if the identifier is exported.
|
|
reverseDeps, err := i.Snapshot.GetReverseDependencies(ctx, i.pkg.ID())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, id := range reverseDeps {
|
|
ph, err := i.Snapshot.PackageHandle(ctx, id)
|
|
if err != nil {
|
|
log.Error(ctx, "References: no CheckPackageHandle", err, telemetry.Package.Of(id))
|
|
continue
|
|
}
|
|
pkg, err := ph.Check(ctx)
|
|
if err != nil {
|
|
log.Error(ctx, "References: no Package", err, telemetry.Package.Of(id))
|
|
continue
|
|
}
|
|
searchpkgs = append(searchpkgs, pkg)
|
|
}
|
|
}
|
|
// Add the package in which the identifier is declared.
|
|
searchpkgs = append(searchpkgs, i.pkg)
|
|
|
|
var references []*ReferenceInfo
|
|
for _, pkg := range searchpkgs {
|
|
for ident, obj := range pkg.GetTypesInfo().Uses {
|
|
if !sameObj(obj, i.Declaration.obj) {
|
|
continue
|
|
}
|
|
rng, err := posToMappedRange(i.Snapshot.View(), 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 either they have they have objectpaths
|
|
// and their objectpath and package are the same; or if they don't
|
|
// have object paths and they have the same Pos and Name.
|
|
func sameObj(obj, declObj types.Object) bool {
|
|
if obj == nil || declObj == nil {
|
|
return false
|
|
}
|
|
// TODO(suzmue): support the case where an identifier may have two different
|
|
// declaration positions.
|
|
if obj.Pkg() == nil || declObj.Pkg() == nil {
|
|
if obj.Pkg() != declObj.Pkg() {
|
|
return false
|
|
}
|
|
} else if obj.Pkg().Path() != declObj.Pkg().Path() {
|
|
return false
|
|
}
|
|
objPath, operr := objectpath.For(obj)
|
|
declObjPath, doperr := objectpath.For(declObj)
|
|
if operr != nil || doperr != nil {
|
|
return obj.Pos() == declObj.Pos() && obj.Name() == declObj.Name()
|
|
}
|
|
return objPath == declObjPath
|
|
}
|