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
parent f7b6a898a4
commit 58344e5403
1 changed files with 38 additions and 22 deletions

View File

@ -127,6 +127,7 @@ func (v *View) parse(uri source.URI) error {
if err != nil { if err != nil {
return err return err
} }
// TODO(rstambler): Enforce here that LoadMode is LoadImports?
pkgs, err := packages.Load(&v.Config, fmt.Sprintf("file=%s", path)) pkgs, err := packages.Load(&v.Config, fmt.Sprintf("file=%s", path))
if len(pkgs) == 0 { if len(pkgs) == 0 {
if err == nil { if err == nil {
@ -314,36 +315,51 @@ func (imp *importer) parseFiles(filenames []string) ([]*ast.File, []error) {
n := len(filenames) n := len(filenames)
parsed := make([]*ast.File, n) parsed := make([]*ast.File, n)
errors := make([]error, n) errors := make([]error, n)
for i, file := range filenames { for i, filename := range filenames {
if imp.v.Config.Context != nil { if imp.v.Config.Context.Err() != nil {
if imp.v.Config.Context.Err() != nil { parsed[i] = nil
parsed[i] = nil errors[i] = imp.v.Config.Context.Err()
errors[i] = imp.v.Config.Context.Err() continue
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) wg.Add(1)
go func(i int, filename string) { go func(i int, filename string) {
ioLimit <- true // wait ioLimit <- true // wait
// ParseFile may return both an AST and an error.
var src []byte if fAST != nil {
for f, contents := range imp.v.Config.Overlay { parsed[i], errors[i] = fAST, nil
if sameFile(f, filename) { } else {
src = contents // 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 <-ioLimit // signal
wg.Done() wg.Done()
}(i, file) }(i, filename)
} }
wg.Wait() wg.Wait()