1
0
mirror of https://github.com/golang/go synced 2024-10-01 09:38:36 -06:00
go/internal/lsp/cache/token.go
Rebecca Stambler 61e0f78580 internal/lsp: use the memoize package to get *token.Files
This change does not actually use the token handle for GetToken right
now, but implements the approach for memoizing *token.Files.

Change-Id: I75919f4e97abd6893b202c021adecd2c9dbfc2be
Reviewed-on: https://go-review.googlesource.com/c/tools/+/182277
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
2019-06-14 19:20:18 +00:00

89 lines
1.7 KiB
Go

package cache
import (
"context"
"fmt"
"go/token"
"golang.org/x/tools/internal/lsp/source"
"golang.org/x/tools/internal/memoize"
)
type tokenKey struct {
file source.FileIdentity
}
type tokenHandle struct {
handle *memoize.Handle
file source.FileHandle
}
type tokenData struct {
memoize.NoCopy
tok *token.File
err error
}
func (c *cache) TokenHandle(fh source.FileHandle) source.TokenHandle {
key := tokenKey{
file: fh.Identity(),
}
h := c.store.Bind(key, func(ctx context.Context) interface{} {
data := &tokenData{}
data.tok, data.err = tokenFile(ctx, c, fh)
return data
})
return &tokenHandle{
handle: h,
}
}
func (h *tokenHandle) File() source.FileHandle {
return h.file
}
func (h *tokenHandle) Token(ctx context.Context) (*token.File, error) {
v := h.handle.Get(ctx)
if v == nil {
return nil, ctx.Err()
}
data := v.(*tokenData)
return data.tok, data.err
}
func tokenFile(ctx context.Context, c *cache, fh source.FileHandle) (*token.File, error) {
// First, check if we already have a parsed AST for this file's handle.
for _, mode := range []source.ParseMode{
source.ParseHeader,
source.ParseExported,
source.ParseFull,
} {
pk := parseKey{
file: fh.Identity(),
mode: mode,
}
pd, ok := c.store.Cached(pk).(*parseGoData)
if !ok {
continue
}
if pd.ast == nil {
continue
}
if !pd.ast.Pos().IsValid() {
continue
}
return c.FileSet().File(pd.ast.Pos()), nil
}
// We have not yet parsed this file.
buf, _, err := fh.Read(ctx)
if err != nil {
return nil, err
}
tok := c.FileSet().AddFile(fh.Identity().URI.Filename(), -1, len(buf))
if tok == nil {
return nil, fmt.Errorf("no token.File for %s", fh.Identity().URI)
}
return tok, nil
}