1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package cache 6 7import ( 8 "context" 9 "fmt" 10 "go/token" 11 12 "golang.org/x/tools/internal/lsp/source" 13 "golang.org/x/tools/internal/memoize" 14) 15 16type tokenKey struct { 17 file source.FileIdentity 18} 19 20type tokenHandle struct { 21 handle *memoize.Handle 22 file source.FileHandle 23} 24 25type tokenData struct { 26 memoize.NoCopy 27 28 tok *token.File 29 err error 30} 31 32func (c *cache) TokenHandle(fh source.FileHandle) source.TokenHandle { 33 key := tokenKey{ 34 file: fh.Identity(), 35 } 36 h := c.store.Bind(key, func(ctx context.Context) interface{} { 37 data := &tokenData{} 38 data.tok, data.err = tokenFile(ctx, c, fh) 39 return data 40 }) 41 return &tokenHandle{ 42 handle: h, 43 file: fh, 44 } 45} 46 47func (h *tokenHandle) File() source.FileHandle { 48 return h.file 49} 50 51func (h *tokenHandle) Token(ctx context.Context) (*token.File, error) { 52 v := h.handle.Get(ctx) 53 if v == nil { 54 return nil, ctx.Err() 55 } 56 data := v.(*tokenData) 57 return data.tok, data.err 58} 59 60func tokenFile(ctx context.Context, c *cache, fh source.FileHandle) (*token.File, error) { 61 // First, check if we already have a parsed AST for this file's handle. 62 for _, mode := range []source.ParseMode{ 63 source.ParseHeader, 64 source.ParseExported, 65 source.ParseFull, 66 } { 67 pk := parseKey{ 68 file: fh.Identity(), 69 mode: mode, 70 } 71 pd, ok := c.store.Cached(pk).(*parseGoData) 72 if !ok { 73 continue 74 } 75 if pd.ast == nil { 76 continue 77 } 78 if !pd.ast.Pos().IsValid() { 79 continue 80 } 81 return c.FileSet().File(pd.ast.Pos()), nil 82 } 83 // We have not yet parsed this file. 84 buf, _, err := fh.Read(ctx) 85 if err != nil { 86 return nil, err 87 } 88 tok := c.FileSet().AddFile(fh.Identity().URI.Filename(), -1, len(buf)) 89 if tok == nil { 90 return nil, fmt.Errorf("no token.File for %s", fh.Identity().URI) 91 } 92 tok.SetLinesForContent(buf) 93 return tok, nil 94} 95