mirror of
https://github.com/golang/go.git
synced 2025-05-05 07:33:00 +00:00
internal/lsp: use protocol.Ranges for source.Identifier
Change-Id: I42cb957e3c1676e2ec7e3f50dd5e3613f3dd9555 Reviewed-on: https://go-review.googlesource.com/c/tools/+/191880 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
aed303cbaa
commit
42f498d34c
1
go.sum
1
go.sum
@ -3,6 +3,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwL
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
|
14
internal/lsp/cache/gofile.go
vendored
14
internal/lsp/cache/gofile.go
vendored
@ -162,6 +162,10 @@ func (f *goFile) GetCachedPackage(ctx context.Context) (source.Package, error) {
|
||||
}
|
||||
f.mu.Unlock()
|
||||
|
||||
if len(cphs) == 0 {
|
||||
return nil, errors.Errorf("no CheckPackageHandles for %s", f.URI())
|
||||
}
|
||||
|
||||
cph, err := bestCheckPackageHandle(f.URI(), cphs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -202,6 +206,16 @@ func (f *goFile) wrongParseMode(ctx context.Context, mode source.ParseMode) bool
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *goFile) Builtin() (*ast.File, bool) {
|
||||
builtinPkg := f.View().BuiltinPackage()
|
||||
for filename, file := range builtinPkg.Files {
|
||||
if filename == f.URI().Filename() {
|
||||
return file, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// isDirty is true if the file needs to be type-checked.
|
||||
// It assumes that the file's view's mutex is held by the caller.
|
||||
func (f *goFile) isDirty(ctx context.Context) bool {
|
||||
|
@ -19,39 +19,20 @@ func (s *Server) definition(ctx context.Context, params *protocol.TextDocumentPo
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := getMapper(ctx, f)
|
||||
ident, err := source.Identifier(ctx, view, f, params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spn, err := m.PointSpan(params.Position)
|
||||
decRange, err := ident.Declaration.Range()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rng, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ident, err := source.Identifier(ctx, f, rng.Start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decSpan, err := ident.DeclarationRange().Span()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decFile, err := getGoFile(ctx, view, decSpan.URI())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decM, err := getMapper(ctx, decFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loc, err := decM.Location(decSpan)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []protocol.Location{loc}, nil
|
||||
return []protocol.Location{
|
||||
{
|
||||
URI: protocol.NewURI(ident.Declaration.URI()),
|
||||
Range: decRange,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Server) typeDefinition(ctx context.Context, params *protocol.TextDocumentPositionParams) ([]protocol.Location, error) {
|
||||
@ -61,37 +42,18 @@ func (s *Server) typeDefinition(ctx context.Context, params *protocol.TextDocume
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := getMapper(ctx, f)
|
||||
ident, err := source.Identifier(ctx, view, f, params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spn, err := m.PointSpan(params.Position)
|
||||
identRange, err := ident.Type.Range()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rng, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ident, err := source.Identifier(ctx, f, rng.Start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
identSpan, err := ident.Type.Range.Span()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
identFile, err := getGoFile(ctx, view, identSpan.URI())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
identM, err := getMapper(ctx, identFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loc, err := identM.Location(identSpan)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []protocol.Location{loc}, nil
|
||||
return []protocol.Location{
|
||||
{
|
||||
URI: protocol.NewURI(ident.Type.URI()),
|
||||
Range: identRange,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
@ -38,19 +38,7 @@ func (s *Server) hover(ctx context.Context, params *protocol.TextDocumentPositio
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := getMapper(ctx, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spn, err := m.PointSpan(params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
identRange, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ident, err := source.Identifier(ctx, f, identRange.Start)
|
||||
ident, err := source.Identifier(ctx, view, f, params.Position)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
@ -58,11 +46,7 @@ func (s *Server) hover(ctx context.Context, params *protocol.TextDocumentPositio
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
identSpan, err := ident.Range.Span()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rng, err := m.Range(identSpan)
|
||||
rng, err := ident.Range()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
||||
} else {
|
||||
locs, err = r.server.Definition(r.ctx, params)
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", d.Src, err)
|
||||
t.Fatalf("failed for %v: %+v", d.Src, err)
|
||||
}
|
||||
hover, err = r.server.Hover(r.ctx, params)
|
||||
}
|
||||
|
@ -21,44 +21,21 @@ func (s *Server) references(ctx context.Context, params *protocol.ReferenceParam
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := getMapper(ctx, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spn, err := m.PointSpan(params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rng, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Find all references to the identifier at the position.
|
||||
ident, err := source.Identifier(ctx, f, rng.Start)
|
||||
ident, err := source.Identifier(ctx, view, f, params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
references, err := ident.References(ctx)
|
||||
references, err := ident.References(ctx, view)
|
||||
if err != nil {
|
||||
log.Error(ctx, "no references", err, tag.Of("Identifier", ident.Name))
|
||||
}
|
||||
if params.Context.IncludeDeclaration {
|
||||
// The declaration of this identifier may not be in the
|
||||
// scope that we search for references, so make sure
|
||||
// it is added to the beginning of the list if IncludeDeclaration
|
||||
// was specified.
|
||||
references = append([]*source.ReferenceInfo{
|
||||
&source.ReferenceInfo{
|
||||
Range: ident.DeclarationRange(),
|
||||
},
|
||||
}, references...)
|
||||
}
|
||||
|
||||
// Get the location of each reference to return as the result.
|
||||
locations := make([]protocol.Location, 0, len(references))
|
||||
seen := make(map[span.Span]bool)
|
||||
for _, ref := range references {
|
||||
refSpan, err := ref.Range.Span()
|
||||
refSpan, err := ref.Span()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -66,20 +43,31 @@ func (s *Server) references(ctx context.Context, params *protocol.ReferenceParam
|
||||
continue // already added this location
|
||||
}
|
||||
seen[refSpan] = true
|
||||
refRange, err := ref.Range()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
locations = append(locations, protocol.Location{
|
||||
URI: protocol.NewURI(ref.URI()),
|
||||
Range: refRange,
|
||||
})
|
||||
}
|
||||
// The declaration of this identifier may not be in the
|
||||
// scope that we search for references, so make sure
|
||||
// it is added to the beginning of the list if IncludeDeclaration
|
||||
// was specified.
|
||||
if params.Context.IncludeDeclaration {
|
||||
rng, err := ident.Declaration.Range()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
locations = append([]protocol.Location{
|
||||
{
|
||||
URI: protocol.NewURI(ident.Declaration.URI()),
|
||||
Range: rng,
|
||||
},
|
||||
}, locations...)
|
||||
|
||||
refFile, err := getGoFile(ctx, view, refSpan.URI())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
refM, err := getMapper(ctx, refFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loc, err := refM.Location(refSpan)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
locations = append(locations, loc)
|
||||
}
|
||||
return locations, nil
|
||||
}
|
||||
|
@ -19,23 +19,11 @@ func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*pr
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err := getMapper(ctx, f)
|
||||
ident, err := source.Identifier(ctx, view, f, params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
spn, err := m.PointSpan(params.Position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rng, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ident, err := source.Identifier(ctx, f, rng.Start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
edits, err := ident.Rename(ctx, params.NewName)
|
||||
edits, err := ident.Rename(ctx, view, params.NewName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ func (s *Server) signatureHelp(ctx context.Context, params *protocol.TextDocumen
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info, err := source.SignatureHelp(ctx, f, rng.Start)
|
||||
info, err := source.SignatureHelp(ctx, view, f, params.Position)
|
||||
if err != nil {
|
||||
log.Print(ctx, "no signature help", tag.Of("At", rng), tag.Of("Failure", err))
|
||||
return nil, nil
|
||||
|
@ -115,11 +115,11 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
}
|
||||
// TODO(rstambler): Log errors when this feature is enabled.
|
||||
if c.opts.WantDocumentaton {
|
||||
declRange, err := objToRange(c.ctx, c.view.Session().Cache().FileSet(), obj)
|
||||
declRange, err := objToRange(c.ctx, c.view, obj)
|
||||
if err != nil {
|
||||
goto Return
|
||||
}
|
||||
pos := declRange.FileSet.Position(declRange.Start)
|
||||
pos := c.view.Session().Cache().FileSet().Position(declRange.spanRange.Start)
|
||||
if !pos.IsValid() {
|
||||
goto Return
|
||||
}
|
||||
@ -136,16 +136,20 @@ func (c *completer) item(cand candidate) (CompletionItem, error) {
|
||||
if err != nil {
|
||||
goto Return
|
||||
}
|
||||
var file *ast.File
|
||||
for _, ph := range pkg.GetHandles() {
|
||||
if ph.File().Identity().URI == gof.URI() {
|
||||
file, _ = ph.Cached(c.ctx)
|
||||
var ph ParseGoHandle
|
||||
for _, h := range pkg.GetHandles() {
|
||||
if h.File().Identity().URI == gof.URI() {
|
||||
ph = h
|
||||
}
|
||||
}
|
||||
if ph == nil {
|
||||
goto Return
|
||||
}
|
||||
file, _ := ph.Cached(c.ctx)
|
||||
if file == nil {
|
||||
goto Return
|
||||
}
|
||||
ident, err := findIdentifier(c.ctx, gof, pkg, file, declRange.Start)
|
||||
ident, err := findIdentifier(c.ctx, c.view, gof, pkg, file, declRange.spanRange.Start)
|
||||
if err != nil {
|
||||
goto Return
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ func (i *IdentifierInfo) Hover(ctx context.Context) (*HoverInformation, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "source.Hover")
|
||||
defer done()
|
||||
|
||||
h, err := i.decl.hover(ctx)
|
||||
h, err := i.Declaration.hover(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -55,8 +55,8 @@ func (i *IdentifierInfo) Hover(ctx context.Context) (*HoverInformation, error) {
|
||||
}
|
||||
|
||||
// Set the documentation.
|
||||
if i.decl.obj != nil {
|
||||
h.SingleLine = types.ObjectString(i.decl.obj, i.qf)
|
||||
if i.Declaration.obj != nil {
|
||||
h.SingleLine = types.ObjectString(i.Declaration.obj, i.qf)
|
||||
}
|
||||
if h.comment != nil {
|
||||
h.FullDocumentation = h.comment.Text()
|
||||
@ -65,7 +65,7 @@ func (i *IdentifierInfo) Hover(ctx context.Context) (*HoverInformation, error) {
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (d declaration) hover(ctx context.Context) (*HoverInformation, error) {
|
||||
func (d Declaration) hover(ctx context.Context) (*HoverInformation, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "source.hover")
|
||||
defer done()
|
||||
obj := d.obj
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/span"
|
||||
"golang.org/x/tools/internal/telemetry/trace"
|
||||
errors "golang.org/x/xerrors"
|
||||
@ -20,13 +21,15 @@ import (
|
||||
// IdentifierInfo holds information about an identifier in Go source.
|
||||
type IdentifierInfo struct {
|
||||
Name string
|
||||
Range span.Range
|
||||
mappedRange
|
||||
File GoFile
|
||||
|
||||
Type struct {
|
||||
Range span.Range
|
||||
mappedRange
|
||||
Object types.Object
|
||||
}
|
||||
decl declaration
|
||||
|
||||
Declaration Declaration
|
||||
|
||||
pkg Package
|
||||
ident *ast.Ident
|
||||
@ -34,44 +37,39 @@ type IdentifierInfo struct {
|
||||
qf types.Qualifier
|
||||
}
|
||||
|
||||
type declaration struct {
|
||||
rng span.Range
|
||||
type Declaration struct {
|
||||
mappedRange
|
||||
node ast.Node
|
||||
obj types.Object
|
||||
wasImplicit bool
|
||||
}
|
||||
|
||||
func (i *IdentifierInfo) DeclarationRange() span.Range {
|
||||
return i.decl.rng
|
||||
}
|
||||
|
||||
// Identifier returns identifier information for a position
|
||||
// in a file, accounting for a potentially incomplete selector.
|
||||
func Identifier(ctx context.Context, f GoFile, pos token.Pos) (*IdentifierInfo, error) {
|
||||
pkg, err := f.GetPackage(ctx)
|
||||
func Identifier(ctx context.Context, view View, f GoFile, pos protocol.Position) (*IdentifierInfo, error) {
|
||||
file, pkg, m, err := fileToMapper(ctx, view, f.URI())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var file *ast.File
|
||||
for _, ph := range pkg.GetHandles() {
|
||||
if ph.File().Identity().URI == f.URI() {
|
||||
file, err = ph.Cached(ctx)
|
||||
}
|
||||
}
|
||||
if file == nil {
|
||||
spn, err := m.PointSpan(pos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return findIdentifier(ctx, f, pkg, file, pos)
|
||||
rng, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return findIdentifier(ctx, view, f, pkg, file, rng.Start)
|
||||
}
|
||||
|
||||
func findIdentifier(ctx context.Context, f GoFile, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) {
|
||||
if result, err := identifier(ctx, f, pkg, file, pos); err != nil || result != nil {
|
||||
func findIdentifier(ctx context.Context, view View, f GoFile, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) {
|
||||
if result, err := identifier(ctx, view, f, pkg, file, pos); err != nil || result != nil {
|
||||
return result, err
|
||||
}
|
||||
// If the position is not an identifier but immediately follows
|
||||
// an identifier or selector period (as is common when
|
||||
// requesting a completion), use the path to the preceding node.
|
||||
result, err := identifier(ctx, f, pkg, file, pos-1)
|
||||
result, err := identifier(ctx, view, f, pkg, file, pos-1)
|
||||
if result == nil && err == nil {
|
||||
err = errors.Errorf("no identifier found for %s", f.FileSet().Position(pos))
|
||||
}
|
||||
@ -79,14 +77,14 @@ func findIdentifier(ctx context.Context, f GoFile, pkg Package, file *ast.File,
|
||||
}
|
||||
|
||||
// identifier checks a single position for a potential identifier.
|
||||
func identifier(ctx context.Context, f GoFile, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) {
|
||||
func identifier(ctx context.Context, view View, f GoFile, pkg Package, file *ast.File, pos token.Pos) (*IdentifierInfo, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "source.identifier")
|
||||
defer done()
|
||||
|
||||
var err error
|
||||
|
||||
// Handle import specs separately, as there is no formal position for a package declaration.
|
||||
if result, err := importSpec(ctx, f, file, pkg, pos); result != nil || err != nil {
|
||||
if result, err := importSpec(ctx, view, f, file, pkg, pos); result != nil || err != nil {
|
||||
return result, err
|
||||
}
|
||||
path, _ := astutil.PathEnclosingInterval(file, pos, pos)
|
||||
@ -115,9 +113,11 @@ func identifier(ctx context.Context, f GoFile, pkg Package, file *ast.File, pos
|
||||
}
|
||||
}
|
||||
result.Name = result.ident.Name
|
||||
result.Range = span.NewRange(f.FileSet(), result.ident.Pos(), result.ident.End())
|
||||
result.decl.obj = pkg.GetTypesInfo().ObjectOf(result.ident)
|
||||
if result.decl.obj == nil {
|
||||
if result.mappedRange, err = posToRange(ctx, view, result.ident.Pos(), result.ident.End()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Declaration.obj = pkg.GetTypesInfo().ObjectOf(result.ident)
|
||||
if result.Declaration.obj == nil {
|
||||
// If there was no types.Object for the declaration, there might be an implicit local variable
|
||||
// declaration in a type switch.
|
||||
if objs := typeSwitchVar(pkg.GetTypesInfo(), path); len(objs) > 0 {
|
||||
@ -125,8 +125,8 @@ func identifier(ctx context.Context, f GoFile, pkg Package, file *ast.File, pos
|
||||
// but all of the types.Objects associated with the usages of this variable can be
|
||||
// used to connect it back to the declaration.
|
||||
// Preserve the first of these objects and treat it as if it were the declaring object.
|
||||
result.decl.obj = objs[0]
|
||||
result.decl.wasImplicit = true
|
||||
result.Declaration.obj = objs[0]
|
||||
result.Declaration.wasImplicit = true
|
||||
} else {
|
||||
// Probably a type error.
|
||||
return nil, errors.Errorf("no object for ident %v", result.Name)
|
||||
@ -134,13 +134,13 @@ func identifier(ctx context.Context, f GoFile, pkg Package, file *ast.File, pos
|
||||
}
|
||||
|
||||
// Handle builtins separately.
|
||||
if result.decl.obj.Parent() == types.Universe {
|
||||
if result.Declaration.obj.Parent() == types.Universe {
|
||||
decl, ok := lookupBuiltinDecl(f.View(), result.Name).(ast.Node)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("no declaration for %s", result.Name)
|
||||
}
|
||||
result.decl.node = decl
|
||||
if result.decl.rng, err = posToRange(ctx, f.FileSet(), result.Name, decl.Pos()); err != nil {
|
||||
result.Declaration.node = decl
|
||||
if result.Declaration.mappedRange, err = nameToRange(ctx, view, decl.Pos(), result.Name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
@ -149,26 +149,26 @@ func identifier(ctx context.Context, f GoFile, pkg Package, file *ast.File, pos
|
||||
if result.wasEmbeddedField {
|
||||
// The original position was on the embedded field declaration, so we
|
||||
// try to dig out the type and jump to that instead.
|
||||
if v, ok := result.decl.obj.(*types.Var); ok {
|
||||
if v, ok := result.Declaration.obj.(*types.Var); ok {
|
||||
if typObj := typeToObject(v.Type()); typObj != nil {
|
||||
result.decl.obj = typObj
|
||||
result.Declaration.obj = typObj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, obj := range pkg.GetTypesInfo().Implicits {
|
||||
if obj.Pos() == result.decl.obj.Pos() {
|
||||
if obj.Pos() == result.Declaration.obj.Pos() {
|
||||
// Mark this declaration as implicit, since it will not
|
||||
// appear in a (*types.Info).Defs map.
|
||||
result.decl.wasImplicit = true
|
||||
result.Declaration.wasImplicit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if result.decl.rng, err = objToRange(ctx, f.FileSet(), result.decl.obj); err != nil {
|
||||
if result.Declaration.mappedRange, err = objToRange(ctx, view, result.Declaration.obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result.decl.node, err = objToNode(ctx, f.View(), pkg.GetTypes(), result.decl.obj, result.decl.rng); err != nil {
|
||||
if result.Declaration.node, err = objToNode(ctx, f.View(), pkg.GetTypes(), result.Declaration.obj, result.Declaration.mappedRange.spanRange); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typ := pkg.GetTypesInfo().TypeOf(result.ident)
|
||||
@ -182,7 +182,7 @@ func identifier(ctx context.Context, f GoFile, pkg Package, file *ast.File, pos
|
||||
if hasErrorType(result.Type.Object) {
|
||||
return result, nil
|
||||
}
|
||||
if result.Type.Range, err = objToRange(ctx, f.FileSet(), result.Type.Object); err != nil {
|
||||
if result.Type.mappedRange, err = objToRange(ctx, view, result.Type.Object); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -204,7 +204,7 @@ func hasErrorType(obj types.Object) bool {
|
||||
return types.IsInterface(obj.Type()) && obj.Pkg() == nil && obj.Name() == "error"
|
||||
}
|
||||
|
||||
func objToRange(ctx context.Context, fset *token.FileSet, obj types.Object) (span.Range, error) {
|
||||
func objToRange(ctx context.Context, view View, obj types.Object) (mappedRange, error) {
|
||||
if pkgName, ok := obj.(*types.PkgName); ok {
|
||||
// An imported Go package has a package-local, unqualified name.
|
||||
// When the name matches the imported package name, there is no
|
||||
@ -217,17 +217,32 @@ func objToRange(ctx context.Context, fset *token.FileSet, obj types.Object) (spa
|
||||
// When the identifier does not appear in the source, have the range
|
||||
// of the object be the point at the beginning of the declaration.
|
||||
if pkgName.Imported().Name() == pkgName.Name() {
|
||||
return posToRange(ctx, fset, "", obj.Pos())
|
||||
return nameToRange(ctx, view, obj.Pos(), "")
|
||||
}
|
||||
}
|
||||
return posToRange(ctx, fset, obj.Name(), obj.Pos())
|
||||
return nameToRange(ctx, view, obj.Pos(), obj.Name())
|
||||
}
|
||||
|
||||
func posToRange(ctx context.Context, fset *token.FileSet, name string, pos token.Pos) (span.Range, error) {
|
||||
if !pos.IsValid() {
|
||||
return span.Range{}, errors.Errorf("invalid position for %v", name)
|
||||
func nameToRange(ctx context.Context, view View, pos token.Pos, name string) (mappedRange, error) {
|
||||
return posToRange(ctx, view, pos, pos+token.Pos(len(name)))
|
||||
}
|
||||
return span.NewRange(fset, pos, pos+token.Pos(len(name))), nil
|
||||
|
||||
func posToRange(ctx context.Context, view View, pos, end token.Pos) (mappedRange, error) {
|
||||
if !pos.IsValid() {
|
||||
return mappedRange{}, errors.Errorf("invalid position for %v", pos)
|
||||
}
|
||||
if !end.IsValid() {
|
||||
return mappedRange{}, errors.Errorf("invalid position for %v", end)
|
||||
}
|
||||
posn := view.Session().Cache().FileSet().Position(pos)
|
||||
_, m, err := cachedFileToMapper(ctx, view, span.FileURI(posn.Filename))
|
||||
if err != nil {
|
||||
return mappedRange{}, err
|
||||
}
|
||||
return mappedRange{
|
||||
m: m,
|
||||
spanRange: span.NewRange(view.Session().Cache().FileSet(), pos, end),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func objToNode(ctx context.Context, view View, originPkg *types.Package, obj types.Object, rng span.Range) (ast.Decl, error) {
|
||||
@ -279,7 +294,7 @@ func objToNode(ctx context.Context, view View, originPkg *types.Package, obj typ
|
||||
}
|
||||
|
||||
// importSpec handles positions inside of an *ast.ImportSpec.
|
||||
func importSpec(ctx context.Context, f GoFile, fAST *ast.File, pkg Package, pos token.Pos) (*IdentifierInfo, error) {
|
||||
func importSpec(ctx context.Context, view View, f GoFile, fAST *ast.File, pkg Package, pos token.Pos) (*IdentifierInfo, error) {
|
||||
var imp *ast.ImportSpec
|
||||
for _, spec := range fAST.Imports {
|
||||
if spec.Path.Pos() <= pos && pos < spec.Path.End() {
|
||||
@ -296,9 +311,11 @@ func importSpec(ctx context.Context, f GoFile, fAST *ast.File, pkg Package, pos
|
||||
result := &IdentifierInfo{
|
||||
File: f,
|
||||
Name: importPath,
|
||||
Range: span.NewRange(f.FileSet(), imp.Pos(), imp.End()),
|
||||
pkg: pkg,
|
||||
}
|
||||
if result.mappedRange, err = posToRange(ctx, view, imp.Pos(), imp.End()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Consider the "declaration" of an import spec to be the imported package.
|
||||
importedPkg, err := pkg.GetImport(ctx, importPath)
|
||||
if err != nil {
|
||||
@ -317,8 +334,10 @@ func importSpec(ctx context.Context, f GoFile, fAST *ast.File, pkg Package, pos
|
||||
if dest == nil {
|
||||
return nil, errors.Errorf("package %q has no files", importPath)
|
||||
}
|
||||
result.decl.rng = span.NewRange(f.FileSet(), dest.Name.Pos(), dest.Name.End())
|
||||
result.decl.node = imp
|
||||
if result.Declaration.mappedRange, err = posToRange(ctx, view, dest.Pos(), dest.End()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result.Declaration.node = imp
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/span"
|
||||
"golang.org/x/tools/internal/telemetry/trace"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
@ -17,7 +16,7 @@ import (
|
||||
// ReferenceInfo holds information about reference to an identifier in Go source.
|
||||
type ReferenceInfo struct {
|
||||
Name string
|
||||
Range span.Range
|
||||
mappedRange
|
||||
ident *ast.Ident
|
||||
obj types.Object
|
||||
pkg Package
|
||||
@ -26,13 +25,13 @@ type ReferenceInfo struct {
|
||||
|
||||
// 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) {
|
||||
func (i *IdentifierInfo) References(ctx context.Context, view View) ([]*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.decl.obj == nil {
|
||||
if i.Declaration.obj == nil {
|
||||
return nil, errors.Errorf("no references for an import spec")
|
||||
}
|
||||
|
||||
@ -46,43 +45,49 @@ func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, erro
|
||||
return nil, errors.Errorf("package %s has no types info", pkg.PkgPath())
|
||||
}
|
||||
|
||||
if i.decl.wasImplicit {
|
||||
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.decl.obj.Name(),
|
||||
Range: i.decl.rng,
|
||||
obj: i.decl.obj,
|
||||
Name: i.Declaration.obj.Name(),
|
||||
mappedRange: i.Declaration.mappedRange,
|
||||
obj: i.Declaration.obj,
|
||||
pkg: pkg,
|
||||
isDeclaration: true,
|
||||
})
|
||||
}
|
||||
for ident, obj := range info.Defs {
|
||||
if obj == nil || !sameObj(obj, i.decl.obj) {
|
||||
if obj == nil || !sameObj(obj, i.Declaration.obj) {
|
||||
continue
|
||||
}
|
||||
// Add the declarations at the beginning of the references list.
|
||||
references = append([]*ReferenceInfo{&ReferenceInfo{
|
||||
reference := &ReferenceInfo{
|
||||
Name: ident.Name,
|
||||
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()),
|
||||
ident: ident,
|
||||
obj: obj,
|
||||
pkg: pkg,
|
||||
isDeclaration: true,
|
||||
}}, references...)
|
||||
}
|
||||
if reference.mappedRange, err = posToRange(ctx, view, ident.Pos(), ident.End()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Add the declarations at the beginning of the references list.
|
||||
references = append([]*ReferenceInfo{reference}, references...)
|
||||
}
|
||||
for ident, obj := range info.Uses {
|
||||
if obj == nil || !sameObj(obj, i.decl.obj) {
|
||||
if obj == nil || !sameObj(obj, i.Declaration.obj) {
|
||||
continue
|
||||
}
|
||||
references = append(references, &ReferenceInfo{
|
||||
reference := &ReferenceInfo{
|
||||
Name: ident.Name,
|
||||
Range: span.NewRange(i.File.FileSet(), ident.Pos(), ident.End()),
|
||||
ident: ident,
|
||||
pkg: pkg,
|
||||
obj: obj,
|
||||
})
|
||||
}
|
||||
if reference.mappedRange, err = posToRange(ctx, view, ident.Pos(), ident.End()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
references = append(references, reference)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -36,19 +36,19 @@ type renamer struct {
|
||||
}
|
||||
|
||||
// Rename returns a map of TextEdits for each file modified when renaming a given identifier within a package.
|
||||
func (i *IdentifierInfo) Rename(ctx context.Context, newName string) (map[span.URI][]diff.TextEdit, error) {
|
||||
func (i *IdentifierInfo) Rename(ctx context.Context, view View, newName string) (map[span.URI][]diff.TextEdit, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "source.Rename")
|
||||
defer done()
|
||||
|
||||
// If the object declaration is nil, assume it is an import spec.
|
||||
if i.decl.obj == nil {
|
||||
if i.Declaration.obj == nil {
|
||||
// Find the corresponding package name for this import spec
|
||||
// and rename that instead.
|
||||
ident, err := i.getPkgName(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ident.Rename(ctx, newName)
|
||||
return ident.Rename(ctx, view, newName)
|
||||
}
|
||||
if i.Name == newName {
|
||||
return nil, errors.Errorf("old and new names are the same: %s", newName)
|
||||
@ -57,18 +57,18 @@ func (i *IdentifierInfo) Rename(ctx context.Context, newName string) (map[span.U
|
||||
return nil, errors.Errorf("invalid identifier to rename: %q", i.Name)
|
||||
}
|
||||
// Do not rename builtin identifiers.
|
||||
if i.decl.obj.Parent() == types.Universe {
|
||||
if i.Declaration.obj.Parent() == types.Universe {
|
||||
return nil, errors.Errorf("cannot rename builtin %q", i.Name)
|
||||
}
|
||||
if i.pkg == nil || i.pkg.IsIllTyped() {
|
||||
return nil, errors.Errorf("package for %s is ill typed", i.File.URI())
|
||||
}
|
||||
// Do not rename identifiers declared in another package.
|
||||
if i.pkg.GetTypes() != i.decl.obj.Pkg() {
|
||||
return nil, errors.Errorf("failed to rename because %q is declared in package %q", i.Name, i.decl.obj.Pkg().Name())
|
||||
if i.pkg.GetTypes() != i.Declaration.obj.Pkg() {
|
||||
return nil, errors.Errorf("failed to rename because %q is declared in package %q", i.Name, i.Declaration.obj.Pkg().Name())
|
||||
}
|
||||
|
||||
refs, err := i.References(ctx)
|
||||
refs, err := i.References(ctx, view)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -112,8 +112,8 @@ func (i *IdentifierInfo) Rename(ctx context.Context, newName string) (map[span.U
|
||||
// getPkgName gets the pkg name associated with an identifer representing
|
||||
// the import path in an import spec.
|
||||
func (i *IdentifierInfo) getPkgName(ctx context.Context) (*IdentifierInfo, error) {
|
||||
file := i.File.FileSet().File(i.Range.Start)
|
||||
pkgLine := file.Line(i.Range.Start)
|
||||
file := i.File.FileSet().File(i.mappedRange.spanRange.Start)
|
||||
pkgLine := file.Line(i.mappedRange.spanRange.Start)
|
||||
|
||||
for _, obj := range i.pkg.GetTypesInfo().Defs {
|
||||
pkgName, ok := obj.(*types.PkgName)
|
||||
@ -133,22 +133,22 @@ func (i *IdentifierInfo) getPkgName(ctx context.Context) (*IdentifierInfo, error
|
||||
// getPkgNameIdentifier returns an IdentifierInfo representing pkgName.
|
||||
// pkgName must be in the same package and file as ident.
|
||||
func getPkgNameIdentifier(ctx context.Context, ident *IdentifierInfo, pkgName *types.PkgName) (*IdentifierInfo, error) {
|
||||
decl := declaration{
|
||||
decl := Declaration{
|
||||
obj: pkgName,
|
||||
wasImplicit: true,
|
||||
}
|
||||
var err error
|
||||
if decl.rng, err = objToRange(ctx, ident.File.FileSet(), decl.obj); err != nil {
|
||||
if decl.mappedRange, err = objToRange(ctx, ident.File.View(), decl.obj); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if decl.node, err = objToNode(ctx, ident.File.View(), ident.pkg.GetTypes(), decl.obj, decl.rng); err != nil {
|
||||
if decl.node, err = objToNode(ctx, ident.File.View(), ident.pkg.GetTypes(), decl.obj, decl.mappedRange.spanRange); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &IdentifierInfo{
|
||||
Name: pkgName.Name(),
|
||||
Range: decl.rng,
|
||||
mappedRange: decl.mappedRange,
|
||||
File: ident.File,
|
||||
decl: decl,
|
||||
Declaration: decl,
|
||||
pkg: ident.pkg,
|
||||
wasEmbeddedField: false,
|
||||
qf: ident.qf,
|
||||
@ -165,7 +165,7 @@ func (r *renamer) update() (map[span.URI][]diff.TextEdit, error) {
|
||||
return nil, err
|
||||
}
|
||||
for _, ref := range r.refs {
|
||||
refSpan, err := ref.Range.Span()
|
||||
refSpan, err := ref.spanRange.Span()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/ast/astutil"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/telemetry/trace"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
@ -26,21 +27,25 @@ type ParameterInformation struct {
|
||||
Label string
|
||||
}
|
||||
|
||||
func SignatureHelp(ctx context.Context, f GoFile, pos token.Pos) (*SignatureInformation, error) {
|
||||
func SignatureHelp(ctx context.Context, view View, f GoFile, pos protocol.Position) (*SignatureInformation, error) {
|
||||
ctx, done := trace.StartSpan(ctx, "source.SignatureHelp")
|
||||
defer done()
|
||||
|
||||
file, err := f.GetAST(ctx, ParseFull)
|
||||
if file == nil {
|
||||
file, pkg, m, err := fileToMapper(ctx, view, f.URI())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkg, err := f.GetPackage(ctx)
|
||||
spn, err := m.PointSpan(pos)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rng, err := spn.Range(m.Converter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Find a call expression surrounding the query position.
|
||||
var callExpr *ast.CallExpr
|
||||
path, _ := astutil.PathEnclosingInterval(file, pos, pos)
|
||||
path, _ := astutil.PathEnclosingInterval(file, rng.Start, rng.Start)
|
||||
if path == nil {
|
||||
return nil, errors.Errorf("cannot find node enclosing position")
|
||||
}
|
||||
@ -48,7 +53,7 @@ FindCall:
|
||||
for _, node := range path {
|
||||
switch node := node.(type) {
|
||||
case *ast.CallExpr:
|
||||
if pos >= node.Lparen && pos <= node.Rparen {
|
||||
if rng.Start >= node.Lparen && rng.Start <= node.Rparen {
|
||||
callExpr = node
|
||||
break FindCall
|
||||
}
|
||||
@ -76,7 +81,7 @@ FindCall:
|
||||
|
||||
// Handle builtin functions separately.
|
||||
if obj, ok := obj.(*types.Builtin); ok {
|
||||
return builtinSignature(ctx, f.View(), callExpr, obj.Name(), pos)
|
||||
return builtinSignature(ctx, f.View(), callExpr, obj.Name(), rng.Start)
|
||||
}
|
||||
|
||||
// Get the type information for the function being called.
|
||||
@ -93,24 +98,24 @@ FindCall:
|
||||
qf := qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo())
|
||||
params := formatParams(sig.Params(), sig.Variadic(), qf)
|
||||
results, writeResultParens := formatResults(sig.Results(), qf)
|
||||
activeParam := activeParameter(callExpr, sig.Params().Len(), sig.Variadic(), pos)
|
||||
activeParam := activeParameter(callExpr, sig.Params().Len(), sig.Variadic(), rng.Start)
|
||||
|
||||
var (
|
||||
name string
|
||||
comment *ast.CommentGroup
|
||||
)
|
||||
if obj != nil {
|
||||
rng, err := objToRange(ctx, f.FileSet(), obj)
|
||||
rng, err := objToRange(ctx, view, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
node, err := objToNode(ctx, f.View(), pkg.GetTypes(), obj, rng)
|
||||
node, err := objToNode(ctx, f.View(), pkg.GetTypes(), obj, rng.spanRange)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decl := &declaration{
|
||||
decl := &Declaration{
|
||||
obj: obj,
|
||||
rng: rng,
|
||||
mappedRange: rng,
|
||||
node: node,
|
||||
}
|
||||
d, err := decl.hover(ctx)
|
||||
|
@ -346,12 +346,11 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", d.Src, err)
|
||||
}
|
||||
tok, err := f.(source.GoFile).GetToken(ctx)
|
||||
srcRng, err := spanToRange(r.data, d.Src)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get token for %s: %v", d.Src.URI(), err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
pos := tok.Pos(d.Src.Start().Offset())
|
||||
ident, err := source.Identifier(ctx, f.(source.GoFile), pos)
|
||||
ident, err := source.Identifier(ctx, r.view, f.(source.GoFile), srcRng.Start)
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", d.Src, err)
|
||||
}
|
||||
@ -364,9 +363,15 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
||||
hover += h.Synopsis + "\n"
|
||||
}
|
||||
hover += h.Signature
|
||||
rng := ident.DeclarationRange()
|
||||
rng, err := ident.Range()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if d.IsType {
|
||||
rng = ident.Type.Range
|
||||
rng, err = ident.Type.Range()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hover = ""
|
||||
}
|
||||
if hover != "" {
|
||||
@ -378,10 +383,10 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) {
|
||||
t.Errorf("for %v got %q want %q", d.Src, hover, expectHover)
|
||||
}
|
||||
} else if !d.OnlyHover {
|
||||
if def, err := rng.Span(); err != nil {
|
||||
t.Fatalf("failed for %v: %v", rng, err)
|
||||
} else if def != d.Def {
|
||||
t.Errorf("for %v got %v want %v", d.Src, def, d.Def)
|
||||
if defRng, err := spanToRange(r.data, d.Def); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if rng != defRng {
|
||||
t.Errorf("for %v got %v want %v", d.Src, rng, d.Def)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("no tests ran for %s", d.Src.URI())
|
||||
@ -424,12 +429,11 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", src, err)
|
||||
}
|
||||
tok, err := f.(source.GoFile).GetToken(ctx)
|
||||
srcRng, err := spanToRange(r.data, src)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get token for %s: %v", src.URI(), err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
pos := tok.Pos(src.Start().Offset())
|
||||
ident, err := source.Identifier(ctx, f.(source.GoFile), pos)
|
||||
ident, err := source.Identifier(ctx, r.view, f.(source.GoFile), srcRng.Start)
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", src, err)
|
||||
}
|
||||
@ -439,16 +443,16 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
|
||||
want[pos] = true
|
||||
}
|
||||
|
||||
refs, err := ident.References(ctx)
|
||||
refs, err := ident.References(ctx, r.view)
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", src, err)
|
||||
}
|
||||
|
||||
got := make(map[span.Span]bool)
|
||||
for _, refInfo := range refs {
|
||||
refSpan, err := refInfo.Range.Span()
|
||||
refSpan, err := refInfo.Span()
|
||||
if err != nil {
|
||||
t.Errorf("failed for %v item %v: %v", src, refInfo.Name, err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
got[refSpan] = true
|
||||
}
|
||||
@ -474,17 +478,16 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", spn, err)
|
||||
}
|
||||
tok, err := f.(source.GoFile).GetToken(ctx)
|
||||
srcRng, err := spanToRange(r.data, spn)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get token for %s: %v", spn.URI(), err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
pos := tok.Pos(spn.Start().Offset())
|
||||
ident, err := source.Identifier(r.ctx, f.(source.GoFile), pos)
|
||||
ident, err := source.Identifier(r.ctx, r.view, f.(source.GoFile), srcRng.Start)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
changes, err := ident.Rename(r.ctx, newText)
|
||||
changes, err := ident.Rename(r.ctx, r.view, newText)
|
||||
if err != nil {
|
||||
renamed := string(r.data.Golden(tag, spn.URI().Filename(), func() ([]byte, error) {
|
||||
return []byte(err.Error()), nil
|
||||
@ -619,12 +622,11 @@ func (r *runner) SignatureHelp(t *testing.T, data tests.Signatures) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed for %v: %v", spn, err)
|
||||
}
|
||||
tok, err := f.(source.GoFile).GetToken(ctx)
|
||||
rng, err := spanToRange(r.data, spn)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get token for %s: %v", spn.URI(), err)
|
||||
t.Fatal(err)
|
||||
}
|
||||
pos := tok.Pos(spn.Start().Offset())
|
||||
gotSignature, err := source.SignatureHelp(ctx, f.(source.GoFile), pos)
|
||||
gotSignature, err := source.SignatureHelp(ctx, r.view, f.(source.GoFile), rng.Start)
|
||||
if err != nil {
|
||||
// Only fail if we got an error we did not expect.
|
||||
if expectedSignature != nil {
|
||||
@ -667,3 +669,16 @@ func diffSignatures(spn span.Span, want *source.SignatureInformation, got *sourc
|
||||
func (r *runner) Link(t *testing.T, data tests.Links) {
|
||||
// This is a pure LSP feature, no source level functionality to be tested.
|
||||
}
|
||||
|
||||
func spanToRange(data *tests.Data, span span.Span) (protocol.Range, error) {
|
||||
contents, err := data.Exported.FileContents(span.URI().Filename())
|
||||
if err != nil {
|
||||
return protocol.Range{}, err
|
||||
}
|
||||
m := protocol.NewColumnMapper(span.URI(), span.URI().Filename(), data.Exported.ExpectFileSet, nil, contents)
|
||||
srcRng, err := m.Range(span)
|
||||
if err != nil {
|
||||
return protocol.Range{}, err
|
||||
}
|
||||
return srcRng, nil
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/span"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
type mappedRange struct {
|
||||
@ -42,10 +43,94 @@ func (s mappedRange) Range() (protocol.Range, error) {
|
||||
return *s.protocolRange, nil
|
||||
}
|
||||
|
||||
func (s mappedRange) Span() (span.Span, error) {
|
||||
return s.spanRange.Span()
|
||||
}
|
||||
|
||||
func (s mappedRange) URI() span.URI {
|
||||
return s.m.URI
|
||||
}
|
||||
|
||||
func fileToMapper(ctx context.Context, view View, uri span.URI) (*ast.File, Package, *protocol.ColumnMapper, error) {
|
||||
f, err := view.GetFile(ctx, uri)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
gof, ok := f.(GoFile)
|
||||
if !ok {
|
||||
return nil, nil, nil, errors.Errorf("%s is not a Go file", f.URI())
|
||||
}
|
||||
pkg, err := gof.GetPackage(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
file, m, err := pkgToMapper(ctx, view, pkg, uri)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
return file, pkg, m, nil
|
||||
}
|
||||
|
||||
func cachedFileToMapper(ctx context.Context, view View, uri span.URI) (*ast.File, *protocol.ColumnMapper, error) {
|
||||
f, err := view.GetFile(ctx, uri)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
gof, ok := f.(GoFile)
|
||||
if !ok {
|
||||
return nil, nil, errors.Errorf("%s is not a Go file", f.URI())
|
||||
}
|
||||
if file, ok := gof.Builtin(); ok {
|
||||
return builtinFileToMapper(ctx, view, gof, file)
|
||||
}
|
||||
pkg, err := gof.GetCachedPackage(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
file, m, err := pkgToMapper(ctx, view, pkg, uri)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return file, m, nil
|
||||
}
|
||||
|
||||
func pkgToMapper(ctx context.Context, view View, pkg Package, uri span.URI) (*ast.File, *protocol.ColumnMapper, error) {
|
||||
var ph ParseGoHandle
|
||||
for _, h := range pkg.GetHandles() {
|
||||
if h.File().Identity().URI == uri {
|
||||
ph = h
|
||||
}
|
||||
}
|
||||
file, err := ph.Cached(ctx)
|
||||
if file == nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
data, _, err := ph.File().Read(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fset := view.Session().Cache().FileSet()
|
||||
tok := fset.File(file.Pos())
|
||||
if tok == nil {
|
||||
return nil, nil, errors.Errorf("no token.File for %s", uri)
|
||||
}
|
||||
return file, protocol.NewColumnMapper(uri, uri.Filename(), fset, tok, data), nil
|
||||
}
|
||||
|
||||
func builtinFileToMapper(ctx context.Context, view View, f GoFile, file *ast.File) (*ast.File, *protocol.ColumnMapper, error) {
|
||||
fh := f.Handle(ctx)
|
||||
data, _, err := fh.Read(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
fset := view.Session().Cache().FileSet()
|
||||
tok := fset.File(file.Pos())
|
||||
if tok == nil {
|
||||
return nil, nil, errors.Errorf("no token.File for %s", f.URI())
|
||||
}
|
||||
return nil, protocol.NewColumnMapper(f.URI(), f.URI().Filename(), fset, tok, data), nil
|
||||
}
|
||||
|
||||
func IsGenerated(ctx context.Context, view View, uri span.URI) bool {
|
||||
f, err := view.GetFile(ctx, uri)
|
||||
if err != nil {
|
||||
|
@ -258,6 +258,8 @@ type File interface {
|
||||
type GoFile interface {
|
||||
File
|
||||
|
||||
Builtin() (*ast.File, bool)
|
||||
|
||||
// GetAST returns the AST for the file, at or above the given mode.
|
||||
GetAST(ctx context.Context, mode ParseMode) (*ast.File, error)
|
||||
|
||||
|
@ -108,10 +108,9 @@ type Tests interface {
|
||||
|
||||
type Definition struct {
|
||||
Name string
|
||||
Src span.Span
|
||||
IsType bool
|
||||
OnlyHover bool
|
||||
Def span.Span
|
||||
Src, Def span.Span
|
||||
}
|
||||
|
||||
type CompletionSnippet struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user