internal/lsp: use cached AST when parsing files, if available

Change-Id: Ie5c9f77d973b8f9d8f7732d62b54e0a99e6b4659
Reviewed-on: https://go-review.googlesource.com/c/162890
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-02-15 12:21:27 -06:00
Родитель f7b6a898a4
Коммит 58344e5403
1 изменённых файлов: 38 добавлений и 22 удалений

60
internal/lsp/cache/view.go поставляемый
Просмотреть файл

@ -127,6 +127,7 @@ func (v *View) parse(uri source.URI) error {
if err != nil {
return err
}
// TODO(rstambler): Enforce here that LoadMode is LoadImports?
pkgs, err := packages.Load(&v.Config, fmt.Sprintf("file=%s", path))
if len(pkgs) == 0 {
if err == nil {
@ -314,36 +315,51 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
n := len(filenames)
parsed := make([]*ast.File, n)
errors := make([]error, n)
for i, file := range filenames {
if imp.v.Config.Context != nil {
if imp.v.Config.Context.Err() != nil {
parsed[i] = nil
errors[i] = imp.v.Config.Context.Err()
continue
}
for i, filename := range filenames {
if imp.v.Config.Context.Err() != nil {
parsed[i] = nil
errors[i] = imp.v.Config.Context.Err()
continue
}
// First, check if we have already cached an AST for this file.
f := imp.v.files[source.ToURI(filename)]
var fAST *ast.File
if f != nil {
fAST = f.ast
}
wg.Add(1)
go func(i int, filename string) {
ioLimit <- true // wait
// ParseFile may return both an AST and an error.
var src []byte
for f, contents := range imp.v.Config.Overlay {
if sameFile(f, filename) {
src = contents
if fAST != nil {
parsed[i], errors[i] = fAST, nil
} else {
// We don't have a cached AST for this file.
var src []byte
// Check for an available overlay.
for f, contents := range imp.v.Config.Overlay {
if sameFile(f, filename) {
src = contents
}
}
var err error
// We don't have an overlay, so we must read the file's contents.
if src == nil {
src, err = ioutil.ReadFile(filename)
}
if err != nil {
parsed[i], errors[i] = nil, err
} else {
// ParseFile may return both an AST and an error.
parsed[i], errors[i] = imp.v.Config.ParseFile(imp.v.Config.Fset, filename, src)
}
}
var err error
if src == nil {
src, err = ioutil.ReadFile(filename)
}
if err != nil {
parsed[i], errors[i] = nil, err
} else {
parsed[i], errors[i] = imp.v.Config.ParseFile(imp.v.Config.Fset, filename, src)
}
<-ioLimit // signal
wg.Done()
}(i, file)
}(i, filename)
}
wg.Wait()