From 58344e540362b864ba5079e052f28ccf7f947dca Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Fri, 15 Feb 2019 12:21:27 -0600 Subject: [PATCH] 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 TryBot-Result: Gobot Gobot Reviewed-by: Ian Cottrell --- internal/lsp/cache/view.go | 60 ++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go index 902a0d39..22602b13 100644 --- a/internal/lsp/cache/view.go +++ b/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()