internal/lsp: remove the GetToken and GetAST functions

Change-Id: Iddbdde5f47a31da9baab6539cd2b5bd858e7f811
Reviewed-on: https://go-review.googlesource.com/c/tools/+/194057
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:
Rebecca Stambler 2019-09-06 23:58:07 -04:00
parent 27d1b4e4f3
commit cdebb59945
12 changed files with 84 additions and 73 deletions

View File

@ -7,7 +7,6 @@ package cache
import ( import (
"context" "context"
"go/ast" "go/ast"
"go/token"
"sync" "sync"
"golang.org/x/tools/internal/lsp/source" "golang.org/x/tools/internal/lsp/source"
@ -49,36 +48,6 @@ func (f *goFile) metadata() []*metadata {
return result return result
} }
func (f *goFile) GetToken(ctx context.Context) (*token.File, error) {
file, err := f.GetAST(ctx, source.ParseFull)
if file == nil {
return nil, err
}
tok := f.view.session.cache.fset.File(file.Pos())
if tok == nil {
return nil, errors.Errorf("no token.File for %s", f.URI())
}
return tok, nil
}
func (f *goFile) GetAST(ctx context.Context, mode source.ParseMode) (*ast.File, error) {
ctx = telemetry.File.With(ctx, f.URI())
fh := f.Handle(ctx)
if f.isDirty(ctx, fh) || f.wrongParseMode(ctx, fh, mode) {
if err := f.view.loadParseTypecheck(ctx, f, fh); err != nil {
return nil, err
}
}
// Check for a cached AST first, in case getting a trimmed version would actually cause a re-parse.
cached, err := f.view.session.cache.cachedAST(fh, mode)
if cached != nil || err != nil {
return cached, err
}
ph := f.view.session.cache.ParseGoHandle(fh, mode)
return ph.Parse(ctx)
}
func (cache *cache) cachedAST(fh source.FileHandle, mode source.ParseMode) (*ast.File, error) { func (cache *cache) cachedAST(fh source.FileHandle, mode source.ParseMode) (*ast.File, error) {
for _, m := range []source.ParseMode{ for _, m := range []source.ParseMode{
source.ParseHeader, source.ParseHeader,
@ -175,6 +144,24 @@ func (f *goFile) GetCachedPackage(ctx context.Context) (source.Package, error) {
return cph.Cached(ctx) return cph.Cached(ctx)
} }
func (f *goFile) GetCachedPackages(ctx context.Context) ([]source.Package, error) {
f.mu.Lock()
defer f.mu.Unlock()
var pkgs []source.Package
for _, cph := range f.pkgs {
pkg, err := cph.Cached(ctx)
if err != nil {
return nil, err
}
pkgs = append(pkgs, pkg)
}
if len(pkgs) == 0 {
return nil, errors.Errorf("no CheckPackageHandles for %s", f.URI())
}
return pkgs, nil
}
// bestCheckPackageHandle picks the "narrowest" package for a given file. // bestCheckPackageHandle picks the "narrowest" package for a given file.
// //
// By "narrowest" package, we mean the package with the fewest number of files // By "narrowest" package, we mean the package with the fewest number of files

View File

@ -27,16 +27,17 @@ func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLink
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, _, err := f.Handle(ctx).Read(ctx) fh := f.Handle(ctx)
data, _, err := fh.Read(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
file, err := f.GetAST(ctx, source.ParseFull) file, err := view.Session().Cache().ParseGoHandle(fh, source.ParseFull).Parse(ctx)
if file == nil { if file == nil {
return nil, err return nil, err
} }
tok := view.Session().Cache().FileSet().File(file.Pos()) tok := view.Session().Cache().FileSet().File(file.Pos())
m := protocol.NewColumnMapper(f.URI(), f.URI().Filename(), f.FileSet(), tok, data) m := protocol.NewColumnMapper(f.URI(), f.URI().Filename(), view.Session().Cache().FileSet(), tok, data)
var links []protocol.DocumentLink var links []protocol.DocumentLink
ast.Inspect(file, func(node ast.Node) bool { ast.Inspect(file, func(node ast.Node) bool {

View File

@ -26,7 +26,7 @@ func (s *Server) references(ctx context.Context, params *protocol.ReferenceParam
if err != nil { if err != nil {
return nil, err return nil, err
} }
references, err := ident.References(ctx, view) references, err := ident.References(ctx)
if err != nil { if err != nil {
log.Error(ctx, "no references", err, tag.Of("Identifier", ident.Name)) log.Error(ctx, "no references", err, tag.Of("Identifier", ident.Name))
} }

View File

@ -19,15 +19,16 @@ type FoldingRangeInfo struct {
func FoldingRange(ctx context.Context, view View, f GoFile, lineFoldingOnly bool) (ranges []*FoldingRangeInfo, err error) { func FoldingRange(ctx context.Context, view View, f GoFile, lineFoldingOnly bool) (ranges []*FoldingRangeInfo, err error) {
// TODO(suzmue): consider limiting the number of folding ranges returned, and // TODO(suzmue): consider limiting the number of folding ranges returned, and
// implement a way to prioritize folding ranges in that case. // implement a way to prioritize folding ranges in that case.
fset := f.FileSet() fh := f.Handle(ctx)
file, err := f.GetAST(ctx, ParseFull) file, err := view.Session().Cache().ParseGoHandle(fh, ParseFull).Parse(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, _, err := f.Handle(ctx).Read(ctx) data, _, err := fh.Read(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
fset := view.Session().Cache().FileSet()
m := protocol.NewColumnMapper(f.URI(), f.URI().Filename(), fset, fset.File(file.Pos()), data) m := protocol.NewColumnMapper(f.URI(), f.URI().Filename(), fset, fset.File(file.Pos()), data)
// Get folding ranges for comments separately as they are not walked by ast.Inspect. // Get folding ranges for comments separately as they are not walked by ast.Inspect.

View File

@ -8,6 +8,7 @@ package source
import ( import (
"bytes" "bytes"
"context" "context"
"go/ast"
"go/format" "go/format"
"go/token" "go/token"
@ -29,14 +30,19 @@ func Format(ctx context.Context, view View, f File) ([]protocol.TextEdit, error)
if !ok { if !ok {
return nil, errors.Errorf("formatting is not supported for non-Go files") return nil, errors.Errorf("formatting is not supported for non-Go files")
} }
file, err := gof.GetAST(ctx, ParseFull)
if file == nil {
return nil, err
}
pkg, err := gof.GetPackage(ctx) pkg, err := gof.GetPackage(ctx)
if err != nil { if err != nil {
return nil, err 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 {
return nil, err
}
if hasListErrors(pkg.GetErrors()) || hasParseErrors(pkg, f.URI()) { if hasListErrors(pkg.GetErrors()) || hasParseErrors(pkg, f.URI()) {
// Even if this package has list or parse errors, this file may not // Even if this package has list or parse errors, this file may not
// have any parse errors and can still be formatted. Using format.Node // have any parse errors and can still be formatted. Using format.Node
@ -49,7 +55,7 @@ func Format(ctx context.Context, view View, f File) ([]protocol.TextEdit, error)
return computeTextEdits(ctx, view.Session().Cache().FileSet(), f, string(formatted)) return computeTextEdits(ctx, view.Session().Cache().FileSet(), f, string(formatted))
} }
fset := f.FileSet() fset := view.Session().Cache().FileSet()
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
// format.Node changes slightly from one release to another, so the version // format.Node changes slightly from one release to another, so the version

View File

@ -46,7 +46,7 @@ func (i *IdentifierInfo) Hover(ctx context.Context) (*HoverInformation, error) {
switch x := h.source.(type) { switch x := h.source.(type) {
case ast.Node: case ast.Node:
var b strings.Builder var b strings.Builder
if err := format.Node(&b, i.File.FileSet(), x); err != nil { if err := format.Node(&b, i.View.Session().Cache().FileSet(), x); err != nil {
return nil, err return nil, err
} }
h.Signature = b.String() h.Signature = b.String()

View File

@ -21,8 +21,9 @@ import (
// IdentifierInfo holds information about an identifier in Go source. // IdentifierInfo holds information about an identifier in Go source.
type IdentifierInfo struct { type IdentifierInfo struct {
Name string Name string
mappedRange View View
File GoFile File GoFile
mappedRange
Type struct { Type struct {
mappedRange mappedRange
@ -69,11 +70,11 @@ func findIdentifier(ctx context.Context, view View, f GoFile, pkg Package, file
// If the position is not an identifier but immediately follows // If the position is not an identifier but immediately follows
// an identifier or selector period (as is common when // an identifier or selector period (as is common when
// requesting a completion), use the path to the preceding node. // requesting a completion), use the path to the preceding node.
result, err := identifier(ctx, view, f, pkg, file, pos-1) ident, err := identifier(ctx, view, f, pkg, file, pos-1)
if result == nil && err == nil { if ident == nil && err == nil {
err = errors.Errorf("no identifier found for %s", f.FileSet().Position(pos)) err = errors.New("no identifier found")
} }
return result, err return ident, err
} }
// identifier checks a single position for a potential identifier. // identifier checks a single position for a potential identifier.
@ -92,6 +93,7 @@ func identifier(ctx context.Context, view View, f GoFile, pkg Package, file *ast
return nil, errors.Errorf("can't find node enclosing position") return nil, errors.Errorf("can't find node enclosing position")
} }
result := &IdentifierInfo{ result := &IdentifierInfo{
View: view,
File: f, File: f,
qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()), qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()),
pkg: pkg, pkg: pkg,
@ -168,7 +170,7 @@ func identifier(ctx context.Context, view View, f GoFile, pkg Package, file *ast
if result.Declaration.mappedRange, err = objToMappedRange(ctx, view, result.Declaration.obj); err != nil { if result.Declaration.mappedRange, err = objToMappedRange(ctx, view, result.Declaration.obj); err != nil {
return nil, err return nil, err
} }
if result.Declaration.node, err = objToNode(ctx, f.View(), pkg.GetTypes(), result.Declaration.obj, result.Declaration.mappedRange.spanRange); err != nil { if result.Declaration.node, err = objToNode(ctx, view, pkg.GetTypes(), result.Declaration.obj, result.Declaration.mappedRange.spanRange); err != nil {
return nil, err return nil, err
} }
typ := pkg.GetTypesInfo().TypeOf(result.ident) typ := pkg.GetTypesInfo().TypeOf(result.ident)
@ -268,6 +270,7 @@ func importSpec(ctx context.Context, view View, f GoFile, fAST *ast.File, pkg Pa
return nil, errors.Errorf("import path not quoted: %s (%v)", imp.Path.Value, err) return nil, errors.Errorf("import path not quoted: %s (%v)", imp.Path.Value, err)
} }
result := &IdentifierInfo{ result := &IdentifierInfo{
View: view,
File: f, File: f,
Name: importPath, Name: importPath,
pkg: pkg, pkg: pkg,

View File

@ -25,7 +25,7 @@ type ReferenceInfo struct {
// References returns a list of references for a given identifier within the packages // References returns a list of references for a given identifier within the packages
// containing i.File. Declarations appear first in the result. // containing i.File. Declarations appear first in the result.
func (i *IdentifierInfo) References(ctx context.Context, view View) ([]*ReferenceInfo, error) { func (i *IdentifierInfo) References(ctx context.Context) ([]*ReferenceInfo, error) {
ctx, done := trace.StartSpan(ctx, "source.References") ctx, done := trace.StartSpan(ctx, "source.References")
defer done() defer done()
var references []*ReferenceInfo var references []*ReferenceInfo
@ -34,8 +34,7 @@ func (i *IdentifierInfo) References(ctx context.Context, view View) ([]*Referenc
if i.Declaration.obj == nil { if i.Declaration.obj == nil {
return nil, errors.Errorf("no references for an import spec") return nil, errors.Errorf("no references for an import spec")
} }
pkgs, err := i.File.GetCachedPackages(ctx)
pkgs, err := i.File.GetPackages(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -61,7 +60,7 @@ func (i *IdentifierInfo) References(ctx context.Context, view View) ([]*Referenc
if obj == nil || !sameObj(obj, i.Declaration.obj) { if obj == nil || !sameObj(obj, i.Declaration.obj) {
continue continue
} }
rng, err := posToRange(ctx, view, ident.Pos(), ident.End()) rng, err := posToRange(ctx, i.View, ident.Pos(), ident.End())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -79,7 +78,7 @@ func (i *IdentifierInfo) References(ctx context.Context, view View) ([]*Referenc
if obj == nil || !sameObj(obj, i.Declaration.obj) { if obj == nil || !sameObj(obj, i.Declaration.obj) {
continue continue
} }
rng, err := posToRange(ctx, view, ident.Pos(), ident.End()) rng, err := posToRange(ctx, i.View, ident.Pos(), ident.End())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -110,14 +110,14 @@ func (i *IdentifierInfo) Rename(ctx context.Context, view View, newName string)
return nil, errors.Errorf("failed to rename because %q is declared in package %q", i.Name, i.Declaration.obj.Pkg().Name()) 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, view) refs, err := i.References(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
r := renamer{ r := renamer{
ctx: ctx, ctx: ctx,
fset: i.File.FileSet(), fset: view.Session().Cache().FileSet(),
refs: refs, refs: refs,
objsToUpdate: make(map[types.Object]bool), objsToUpdate: make(map[types.Object]bool),
from: i.Name, from: i.Name,
@ -164,8 +164,16 @@ func (i *IdentifierInfo) Rename(ctx context.Context, view View, newName string)
// getPkgName gets the pkg name associated with an identifer representing // getPkgName gets the pkg name associated with an identifer representing
// the import path in an import spec. // the import path in an import spec.
func (i *IdentifierInfo) getPkgName(ctx context.Context) (*IdentifierInfo, error) { func (i *IdentifierInfo) getPkgName(ctx context.Context) (*IdentifierInfo, error) {
file, err := i.File.GetAST(ctx, ParseHeader) var (
if err != nil { file *ast.File
err error
)
for _, ph := range i.pkg.GetHandles() {
if ph.File().Identity().URI == i.File.URI() {
file, err = ph.Cached(ctx)
}
}
if file == nil {
return nil, err return nil, err
} }
var namePos token.Pos var namePos token.Pos
@ -211,6 +219,7 @@ func getPkgNameIdentifier(ctx context.Context, ident *IdentifierInfo, pkgName *t
} }
return &IdentifierInfo{ return &IdentifierInfo{
Name: pkgName.Name(), Name: pkgName.Name(),
View: ident.View,
mappedRange: decl.mappedRange, mappedRange: decl.mappedRange,
File: ident.File, File: ident.File,
Declaration: decl, Declaration: decl,

View File

@ -461,11 +461,12 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", spn, err) t.Fatalf("failed for %v: %v", spn, err)
} }
tok, err := f.(source.GoFile).GetToken(ctx) fh := f.Handle(ctx)
tok, err := r.view.Session().Cache().TokenHandle(fh).Token(ctx)
if err != nil { if err != nil {
t.Fatalf("failed to get token for %s: %v", spn.URI(), err) t.Fatal(err)
} }
rng, err := spn.Range(span.NewTokenConverter(f.FileSet(), tok)) rng, err := spn.Range(span.NewTokenConverter(r.data.Exported.ExpectFileSet, tok))
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", spn, err) t.Fatalf("failed for %v: %v", spn, err)
} }
@ -476,7 +477,7 @@ func (r *runner) Import(t *testing.T, data tests.Imports) {
} }
continue continue
} }
data, _, err := f.Handle(ctx).Read(ctx) data, _, err := fh.Read(ctx)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
continue continue
@ -596,7 +597,7 @@ func (r *runner) Reference(t *testing.T, data tests.References) {
want[pos] = true want[pos] = true
} }
refs, err := ident.References(ctx, r.view) refs, err := ident.References(ctx)
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", src, err) t.Fatalf("failed for %v: %v", src, err)
} }

View File

@ -18,14 +18,20 @@ func DocumentSymbols(ctx context.Context, view View, f GoFile) ([]protocol.Docum
ctx, done := trace.StartSpan(ctx, "source.DocumentSymbols") ctx, done := trace.StartSpan(ctx, "source.DocumentSymbols")
defer done() defer done()
file, err := f.GetAST(ctx, ParseFull)
if file == nil {
return nil, err
}
pkg, err := f.GetPackage(ctx) pkg, err := f.GetPackage(ctx)
if err != nil { if err != nil {
return nil, err 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 {
return nil, err
}
info := pkg.GetTypesInfo() info := pkg.GetTypesInfo()
q := qualifier(file, pkg.GetTypes(), info) q := qualifier(file, pkg.GetTypes(), info)

View File

@ -259,8 +259,6 @@ type File interface {
URI() span.URI URI() span.URI
View() View View() View
Handle(ctx context.Context) FileHandle Handle(ctx context.Context) FileHandle
FileSet() *token.FileSet
GetToken(ctx context.Context) (*token.File, error)
} }
// GoFile represents a Go source file that has been type-checked. // GoFile represents a Go source file that has been type-checked.
@ -269,12 +267,12 @@ type GoFile interface {
Builtin() (*ast.File, bool) 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)
// GetCachedPackage returns the cached package for the file, if any. // GetCachedPackage returns the cached package for the file, if any.
GetCachedPackage(ctx context.Context) (Package, error) GetCachedPackage(ctx context.Context) (Package, error)
// GetCachedPackage returns the cached package for the file, if any.
GetCachedPackages(ctx context.Context) ([]Package, error)
// GetPackage returns the CheckPackageHandle for the package that this file belongs to. // GetPackage returns the CheckPackageHandle for the package that this file belongs to.
GetCheckPackageHandle(ctx context.Context) (CheckPackageHandle, error) GetCheckPackageHandle(ctx context.Context) (CheckPackageHandle, error)