diff --git a/internal/lsp/definition.go b/internal/lsp/definition.go index d90385fdf0..52ae133073 100644 --- a/internal/lsp/definition.go +++ b/internal/lsp/definition.go @@ -27,7 +27,7 @@ func (s *Server) definition(ctx context.Context, params *protocol.TextDocumentPo if err != nil { return nil, err } - ident, err := source.Identifier(ctx, view, f, rng.Start) + ident, err := source.Identifier(ctx, f, rng.Start) if err != nil { return nil, err } @@ -61,7 +61,7 @@ func (s *Server) typeDefinition(ctx context.Context, params *protocol.TextDocume if err != nil { return nil, err } - ident, err := source.Identifier(ctx, view, f, rng.Start) + ident, err := source.Identifier(ctx, f, rng.Start) if err != nil { return nil, err } diff --git a/internal/lsp/hover.go b/internal/lsp/hover.go index 78f6937276..e6147e3791 100644 --- a/internal/lsp/hover.go +++ b/internal/lsp/hover.go @@ -6,6 +6,7 @@ package lsp import ( "context" + "golang.org/x/tools/internal/lsp/protocol" "golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/span" @@ -26,7 +27,7 @@ func (s *Server) hover(ctx context.Context, params *protocol.TextDocumentPositio if err != nil { return nil, err } - ident, err := source.Identifier(ctx, view, f, identRange.Start) + ident, err := source.Identifier(ctx, f, identRange.Start) if err != nil { return nil, nil } diff --git a/internal/lsp/references.go b/internal/lsp/references.go index 6be637566b..b179da931d 100644 --- a/internal/lsp/references.go +++ b/internal/lsp/references.go @@ -30,7 +30,7 @@ func (s *Server) references(ctx context.Context, params *protocol.ReferenceParam return nil, err } // Find all references to the identifier at the position. - ident, err := source.Identifier(ctx, view, f, rng.Start) + ident, err := source.Identifier(ctx, f, rng.Start) if err != nil { return nil, err } diff --git a/internal/lsp/rename.go b/internal/lsp/rename.go index 4d1e9b010c..e2f0ecb78d 100644 --- a/internal/lsp/rename.go +++ b/internal/lsp/rename.go @@ -27,7 +27,7 @@ func (s *Server) rename(ctx context.Context, params *protocol.RenameParams) (*pr if err != nil { return nil, err } - ident, err := source.Identifier(ctx, view, f, rng.Start) + ident, err := source.Identifier(ctx, f, rng.Start) if err != nil { return nil, err } diff --git a/internal/lsp/source/completion_format.go b/internal/lsp/source/completion_format.go index a7550a80b2..a07d8091cb 100644 --- a/internal/lsp/source/completion_format.go +++ b/internal/lsp/source/completion_format.go @@ -118,7 +118,7 @@ func (c *completer) item(cand candidate) (CompletionItem, error) { log.Error(c.ctx, "declaration in a Go file", err, tag.Of("Label", item.Label)) goto Return } - ident, err := Identifier(c.ctx, c.view, gof, declRange.Start) + ident, err := Identifier(c.ctx, gof, declRange.Start) if err != nil { log.Error(c.ctx, "no identifier", err, tag.Of("Name", obj.Name())) goto Return diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go index b3bdb5f053..42bb93bb75 100644 --- a/internal/lsp/source/identifier.go +++ b/internal/lsp/source/identifier.go @@ -47,25 +47,7 @@ func (i *IdentifierInfo) DeclarationRange() span.Range { // Identifier returns identifier information for a position // in a file, accounting for a potentially incomplete selector. -func Identifier(ctx context.Context, view View, f GoFile, pos token.Pos) (*IdentifierInfo, error) { - if result, err := identifier(ctx, view, f, 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, view, f, pos-1) - if result == nil && err == nil { - err = errors.Errorf("no identifier found") - } - return result, err -} - -// identifier checks a single position for a potential identifier. -func identifier(ctx context.Context, view View, f GoFile, pos token.Pos) (*IdentifierInfo, error) { - ctx, done := trace.StartSpan(ctx, "source.identifier") - defer done() - +func Identifier(ctx context.Context, f GoFile, pos token.Pos) (*IdentifierInfo, error) { file, err := f.GetAST(ctx, ParseFull) if file == nil { return nil, err @@ -74,6 +56,30 @@ func identifier(ctx context.Context, view View, f GoFile, pos token.Pos) (*Ident if pkg == nil || pkg.IsIllTyped() { return nil, errors.Errorf("pkg for %s is ill-typed", f.URI()) } + return findIdentifier(ctx, f, pkg, file, pos) +} + +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 { + 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) + if result == nil && err == nil { + err = errors.Errorf("no identifier found") + } + return result, err +} + +// 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) { + 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 { return result, err @@ -157,7 +163,7 @@ func identifier(ctx context.Context, view View, f GoFile, pos token.Pos) (*Ident if result.decl.rng, err = objToRange(ctx, f.FileSet(), result.decl.obj); err != nil { return nil, err } - if result.decl.node, err = objToNode(ctx, view, pkg.GetTypes(), result.decl.obj, result.decl.rng); err != nil { + if result.decl.node, err = objToNode(ctx, f.View(), pkg.GetTypes(), result.decl.obj, result.decl.rng); err != nil { return nil, err } typ := pkg.GetTypesInfo().TypeOf(result.ident) diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go index fee66ee65d..8da36c9852 100644 --- a/internal/lsp/source/source_test.go +++ b/internal/lsp/source/source_test.go @@ -395,7 +395,7 @@ func (r *runner) Definition(t *testing.T, data tests.Definitions) { t.Fatalf("failed to get token for %s: %v", d.Src.URI(), err) } pos := tok.Pos(d.Src.Start().Offset()) - ident, err := source.Identifier(ctx, r.view, f.(source.GoFile), pos) + ident, err := source.Identifier(ctx, f.(source.GoFile), pos) if err != nil { t.Fatalf("failed for %v: %v", d.Src, err) } @@ -468,7 +468,7 @@ func (r *runner) Reference(t *testing.T, data tests.References) { t.Fatalf("failed to get token for %s: %v", src.URI(), err) } pos := tok.Pos(src.Start().Offset()) - ident, err := source.Identifier(ctx, r.view, f.(source.GoFile), pos) + ident, err := source.Identifier(ctx, f.(source.GoFile), pos) if err != nil { t.Fatalf("failed for %v: %v", src, err) } @@ -519,7 +519,7 @@ func (r *runner) Rename(t *testing.T, data tests.Renames) { } pos := tok.Pos(spn.Start().Offset()) - ident, err := source.Identifier(r.ctx, r.view, f.(source.GoFile), pos) + ident, err := source.Identifier(r.ctx, f.(source.GoFile), pos) if err != nil { t.Error(err) continue