1
0
mirror of https://github.com/golang/go synced 2024-11-05 14:46:11 -07:00

internal/lsp/cache: add file contents to ParseGoHandle

Currently there is no need for this because the file contents are part
of the file handle. This change is in preparation for an impending
improvement that tweaks the source code during the parse stage to fix
certain kind of terminal parse errors. Any code that wants to use
an *ast.File or *token.File in conjunction with the file contents
needs access to the doctored source code so things line up.

Change-Id: I59d83d3d6150aa1264761aa2c1f6c1269075a2ce
Reviewed-on: https://go-review.googlesource.com/c/tools/+/218979
Run-TryBot: Muir Manders <muir@mnd.rs>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
Muir Manders 2020-02-10 20:10:59 -08:00 committed by Rebecca Stambler
parent cbc0cc175f
commit 49b8ac185c
19 changed files with 50 additions and 48 deletions

View File

@ -295,7 +295,7 @@ func typeCheck(ctx context.Context, fset *token.FileSet, m *metadata, mode sourc
for i, ph := range pkg.compiledGoFiles {
wg.Add(1)
go func(i int, ph source.ParseGoHandle) {
files[i], _, parseErrors[i], actualErrors[i] = ph.Parse(ctx)
files[i], _, _, parseErrors[i], actualErrors[i] = ph.Parse(ctx)
wg.Done()
}(i, ph)
}

View File

@ -181,7 +181,7 @@ func typeErrorRange(ctx context.Context, fset *token.FileSet, pkg *pkg, pos toke
if err != nil {
return span.Span{}, err
}
_, m, _, err := ph.Cached()
_, _, m, _, err := ph.Cached()
if err != nil {
return span.Span{}, err
}
@ -217,7 +217,7 @@ func scannerErrorRange(ctx context.Context, fset *token.FileSet, pkg *pkg, posn
if err != nil {
return span.Span{}, err
}
file, _, _, err := ph.Cached()
file, _, _, _, err := ph.Cached()
if err != nil {
return span.Span{}, err
}
@ -236,7 +236,7 @@ func spanToRange(ctx context.Context, pkg *pkg, spn span.Span) (protocol.Range,
if err != nil {
return protocol.Range{}, err
}
_, m, _, err := ph.Cached()
_, _, m, _, err := ph.Cached()
if err != nil {
return protocol.Range{}, err
}
@ -276,7 +276,7 @@ func parseGoListImportCycleError(ctx context.Context, fset *token.FileSet, e pac
// Imports have quotation marks around them.
circImp := strconv.Quote(importList[1])
for _, ph := range pkg.compiledGoFiles {
fh, _, _, err := ph.Parse(ctx)
fh, _, _, _, err := ph.Parse(ctx)
if err != nil {
continue
}

View File

@ -41,6 +41,7 @@ type parseGoHandle struct {
type parseGoData struct {
memoize.NoCopy
src []byte
ast *ast.File
parseError error // errors associated with parsing the file
mapper *protocol.ColumnMapper
@ -54,9 +55,7 @@ func (c *cache) ParseGoHandle(fh source.FileHandle, mode source.ParseMode) sourc
}
fset := c.fset
h := c.store.Bind(key, func(ctx context.Context) interface{} {
data := &parseGoData{}
data.ast, data.mapper, data.parseError, data.err = parseGo(ctx, fset, fh, mode)
return data
return parseGo(ctx, fset, fh, mode)
})
return &parseGoHandle{
handle: h,
@ -77,22 +76,22 @@ func (pgh *parseGoHandle) Mode() source.ParseMode {
return pgh.mode
}
func (pgh *parseGoHandle) Parse(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error, error) {
func (pgh *parseGoHandle) Parse(ctx context.Context) (*ast.File, []byte, *protocol.ColumnMapper, error, error) {
v := pgh.handle.Get(ctx)
if v == nil {
return nil, nil, nil, errors.Errorf("no parsed file for %s", pgh.File().Identity().URI)
return nil, nil, nil, nil, errors.Errorf("no parsed file for %s", pgh.File().Identity().URI)
}
data := v.(*parseGoData)
return data.ast, data.mapper, data.parseError, data.err
return data.ast, data.src, data.mapper, data.parseError, data.err
}
func (pgh *parseGoHandle) Cached() (*ast.File, *protocol.ColumnMapper, error, error) {
func (pgh *parseGoHandle) Cached() (*ast.File, []byte, *protocol.ColumnMapper, error, error) {
v := pgh.handle.Cached()
if v == nil {
return nil, nil, nil, errors.Errorf("no cached AST for %s", pgh.file.Identity().URI)
return nil, nil, nil, nil, errors.Errorf("no cached AST for %s", pgh.file.Identity().URI)
}
data := v.(*parseGoData)
return data.ast, data.mapper, data.parseError, data.err
return data.ast, data.src, data.mapper, data.parseError, data.err
}
func hashParseKey(ph source.ParseGoHandle) string {
@ -110,16 +109,16 @@ func hashParseKeys(phs []source.ParseGoHandle) string {
return hashContents(b.Bytes())
}
func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mode source.ParseMode) (file *ast.File, mapper *protocol.ColumnMapper, parseError error, err error) {
func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mode source.ParseMode) *parseGoData {
ctx, done := trace.StartSpan(ctx, "cache.parseGo", telemetry.File.Of(fh.Identity().URI.Filename()))
defer done()
if fh.Identity().Kind != source.Go {
return nil, nil, nil, errors.Errorf("cannot parse non-Go file %s", fh.Identity().URI)
return &parseGoData{err: errors.Errorf("cannot parse non-Go file %s", fh.Identity().URI)}
}
buf, _, err := fh.Read(ctx)
if err != nil {
return nil, nil, nil, err
return &parseGoData{err: err}
}
parseLimit <- struct{}{}
defer func() { <-parseLimit }()
@ -127,13 +126,13 @@ func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mod
if mode == source.ParseHeader {
parserMode = parser.ImportsOnly | parser.ParseComments
}
file, parseError = parser.ParseFile(fset, fh.Identity().URI.Filename(), buf, parserMode)
file, parseError := parser.ParseFile(fset, fh.Identity().URI.Filename(), buf, parserMode)
var tok *token.File
if file != nil {
// Fix any badly parsed parts of the AST.
tok = fset.File(file.Pos())
if tok == nil {
return nil, nil, nil, errors.Errorf("successfully parsed but no token.File for %s (%v)", fh.Identity().URI, parseError)
return &parseGoData{err: errors.Errorf("successfully parsed but no token.File for %s (%v)", fh.Identity().URI, parseError)}
}
if mode == source.ParseExported {
trimAST(file)
@ -149,7 +148,7 @@ func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mod
if err == nil {
err = errors.Errorf("no AST for %s", fh.Identity().URI)
}
return nil, nil, parseError, err
return &parseGoData{parseError: parseError, err: err}
}
m := &protocol.ColumnMapper{
URI: fh.Identity().URI,
@ -157,7 +156,12 @@ func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mod
Content: buf,
}
return file, m, parseError, nil
return &parseGoData{
src: buf,
ast: file,
mapper: m,
parseError: parseError,
}
}
// trimAST clears any part of the AST not relevant to type checking

View File

@ -71,7 +71,7 @@ func (p *pkg) File(uri span.URI) (source.ParseGoHandle, error) {
func (p *pkg) GetSyntax() []*ast.File {
var syntax []*ast.File
for _, ph := range p.compiledGoFiles {
file, _, _, err := ph.Cached()
file, _, _, _, err := ph.Cached()
if err == nil {
syntax = append(syntax, file)
}

View File

@ -734,8 +734,8 @@ func (s *snapshot) shouldInvalidateMetadata(ctx context.Context, originalFH, cur
return originalFH.Identity().URI == modfile
}
// Get the original and current parsed files in order to check package name and imports.
original, _, _, originalErr := s.view.session.cache.ParseGoHandle(originalFH, source.ParseHeader).Parse(ctx)
current, _, _, currentErr := s.view.session.cache.ParseGoHandle(currentFH, source.ParseHeader).Parse(ctx)
original, _, _, _, originalErr := s.view.session.cache.ParseGoHandle(originalFH, source.ParseHeader).Parse(ctx)
current, _, _, _, currentErr := s.view.session.cache.ParseGoHandle(currentFH, source.ParseHeader).Parse(ctx)
if originalErr != nil || currentErr != nil {
return (originalErr == nil) != (currentErr == nil)
}

View File

@ -245,7 +245,7 @@ func (v *view) buildBuiltinPackage(ctx context.Context, goFiles []string) error
fset := v.session.cache.fset
h := v.session.cache.store.Bind(pgh.File().Identity(), func(ctx context.Context) interface{} {
data := &builtinPackageData{}
file, _, _, err := pgh.Parse(ctx)
file, _, _, _, err := pgh.Parse(ctx)
if err != nil {
data.err = err
return data

View File

@ -34,7 +34,7 @@ func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLink
if fh.Identity().Kind == source.Mod {
return nil, nil
}
file, m, _, err := view.Session().Cache().ParseGoHandle(fh, source.ParseFull).Parse(ctx)
file, _, m, _, err := view.Session().Cache().ParseGoHandle(fh, source.ParseFull).Parse(ctx)
if err != nil {
return nil, err
}

View File

@ -433,7 +433,7 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, pos proto
if err != nil {
return nil, nil, fmt.Errorf("getting file for Completion: %v", err)
}
file, m, _, err := pgh.Cached()
file, src, m, _, err := pgh.Cached()
if err != nil {
return nil, nil, err
}
@ -500,11 +500,9 @@ func Completion(ctx context.Context, snapshot Snapshot, fh FileHandle, pos proto
// Otherwise, manually extract the prefix if our containing token
// is a keyword. This improves completion after an "accidental
// keyword", e.g. completing to "variance" in "someFunc(var<>)".
if contents, _, err := pgh.File().Read(ctx); err == nil {
id := scanKeyword(c.pos, c.snapshot.View().Session().Cache().FileSet().File(c.pos), contents)
if id != nil {
c.setSurrounding(id)
}
id := scanKeyword(c.pos, c.snapshot.View().Session().Cache().FileSet().File(c.pos), src)
if id != nil {
c.setSurrounding(id)
}
}

View File

@ -223,7 +223,7 @@ func missingModulesDiagnostics(ctx context.Context, snapshot Snapshot, reports m
if err != nil {
return err
}
file, m, _, err := snapshot.View().Session().Cache().ParseGoHandle(fh, ParseHeader).Parse(ctx)
file, _, m, _, err := snapshot.View().Session().Cache().ParseGoHandle(fh, ParseHeader).Parse(ctx)
if err != nil {
log.Error(ctx, "could not parse go file when checking for missing modules", err)
return err

View File

@ -19,7 +19,7 @@ func FoldingRange(ctx context.Context, snapshot Snapshot, fh FileHandle, lineFol
// TODO(suzmue): consider limiting the number of folding ranges returned, and
// implement a way to prioritize folding ranges in that case.
pgh := snapshot.View().Session().Cache().ParseGoHandle(fh, ParseFull)
file, m, _, err := pgh.Parse(ctx)
file, _, m, _, err := pgh.Parse(ctx)
if err != nil {
return nil, err
}

View File

@ -28,7 +28,7 @@ func Format(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]protocol.T
defer done()
pgh := snapshot.View().Session().Cache().ParseGoHandle(fh, ParseFull)
file, m, parseErrors, err := pgh.Parse(ctx)
file, _, m, parseErrors, err := pgh.Parse(ctx)
if err != nil {
return nil, err
}
@ -108,7 +108,7 @@ func computeImportEdits(ctx context.Context, view View, ph ParseGoHandle, option
if err != nil {
return nil, nil, err
}
origAST, origMapper, _, err := ph.Parse(ctx)
origAST, _, origMapper, _, err := ph.Parse(ctx)
if err != nil {
return nil, nil, err
}
@ -144,7 +144,7 @@ func computeOneImportFixEdits(ctx context.Context, view View, ph ParseGoHandle,
if err != nil {
return nil, err
}
origAST, origMapper, _, err := ph.Parse(ctx)
origAST, _, origMapper, _, err := ph.Parse(ctx)
if err != nil {
return nil, err
}

View File

@ -27,7 +27,7 @@ func Highlight(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protoc
if err != nil {
return nil, fmt.Errorf("getting file for Highlight: %v", err)
}
file, m, _, err := pgh.Parse(ctx)
file, _, m, _, err := pgh.Parse(ctx)
if err != nil {
return nil, err
}

View File

@ -56,7 +56,7 @@ func Identifier(ctx context.Context, snapshot Snapshot, fh FileHandle, pos proto
if err != nil {
return nil, fmt.Errorf("getting file for Identifier: %v", err)
}
file, m, _, err := pgh.Cached()
file, _, m, _, err := pgh.Cached()
if err != nil {
return nil, err
}

View File

@ -241,7 +241,7 @@ func getASTFile(pkg Package, f FileHandle, pos protocol.Position) (*ast.File, to
return nil, 0, err
}
file, m, _, err := pgh.Cached()
file, _, m, _, err := pgh.Cached()
if err != nil {
return nil, 0, err
}

View File

@ -26,7 +26,7 @@ func SignatureHelp(ctx context.Context, snapshot Snapshot, fh FileHandle, pos pr
if err != nil {
return nil, 0, fmt.Errorf("getting file for SignatureHelp: %v", err)
}
file, m, _, err := pgh.Cached()
file, _, m, _, err := pgh.Cached()
if err != nil {
return nil, 0, err
}

View File

@ -22,7 +22,7 @@ func DocumentSymbols(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]p
if err != nil {
return nil, fmt.Errorf("getting file for DocumentSymbols: %v", err)
}
file, _, _, err := pgh.Cached()
file, _, _, _, err := pgh.Cached()
if err != nil {
return nil, err
}

View File

@ -147,7 +147,7 @@ func IsGenerated(ctx context.Context, snapshot Snapshot, uri span.URI) bool {
return false
}
ph := snapshot.View().Session().Cache().ParseGoHandle(fh, ParseHeader)
parsed, _, _, err := ph.Parse(ctx)
parsed, _, _, _, err := ph.Parse(ctx)
if err != nil {
return false
}
@ -647,7 +647,7 @@ func findPosInPackage(v View, searchpkg Package, pos token.Pos) (*ast.File, Pack
if err != nil {
return nil, nil, err
}
file, _, _, err := ph.Cached()
file, _, _, _, err := ph.Cached()
if err != nil {
return nil, nil, err
}
@ -671,7 +671,7 @@ func findMapperInPackage(v View, searchpkg Package, uri span.URI) (*protocol.Col
if err != nil {
return nil, err
}
_, m, _, err := ph.Cached()
_, _, m, _, err := ph.Cached()
if err != nil {
return nil, err
}

View File

@ -248,10 +248,10 @@ type ParseGoHandle interface {
// Parse returns the parsed AST for the file.
// If the file is not available, returns nil and an error.
Parse(ctx context.Context) (*ast.File, *protocol.ColumnMapper, error, error)
Parse(ctx context.Context) (file *ast.File, src []byte, m *protocol.ColumnMapper, parseErr error, err error)
// Cached returns the AST for this handle, if it has already been stored.
Cached() (*ast.File, *protocol.ColumnMapper, error, error)
Cached() (file *ast.File, src []byte, m *protocol.ColumnMapper, parseErr error, err error)
}
// ModTidyHandle represents a handle to the modfile for a go.mod.

View File

@ -42,7 +42,7 @@ func WorkspaceSymbols(ctx context.Context, views []View, query string) ([]protoc
}
seen[pkg.PkgPath()] = struct{}{}
for _, fh := range pkg.CompiledGoFiles() {
file, _, _, err := fh.Cached()
file, _, _, _, err := fh.Cached()
if err != nil {
return nil, err
}