2018-12-05 15:00:36 -07:00
|
|
|
// Copyright 2018 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package cache
|
|
|
|
|
|
|
|
import (
|
2019-03-05 15:30:44 -07:00
|
|
|
"context"
|
2018-12-05 15:00:36 -07:00
|
|
|
"go/token"
|
2019-03-27 07:25:30 -06:00
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
2018-12-05 15:00:36 -07:00
|
|
|
|
|
|
|
"golang.org/x/tools/internal/lsp/source"
|
2019-02-19 19:11:15 -07:00
|
|
|
"golang.org/x/tools/internal/span"
|
2018-12-05 15:00:36 -07:00
|
|
|
)
|
|
|
|
|
2019-05-03 22:04:18 -06:00
|
|
|
// viewFile extends source.File with helper methods for the view package.
|
|
|
|
type viewFile interface {
|
|
|
|
source.File
|
2019-05-23 13:03:11 -06:00
|
|
|
|
2019-05-03 22:04:18 -06:00
|
|
|
filename() string
|
|
|
|
addURI(uri span.URI) int
|
|
|
|
}
|
|
|
|
|
|
|
|
// fileBase holds the common functionality for all files.
|
|
|
|
// It is intended to be embedded in the file implementations
|
|
|
|
type fileBase struct {
|
|
|
|
uris []span.URI
|
|
|
|
fname string
|
2019-03-27 07:25:30 -06:00
|
|
|
|
2019-05-17 10:15:22 -06:00
|
|
|
view *view
|
|
|
|
fc *source.FileContent
|
|
|
|
token *token.File
|
2019-05-03 22:04:18 -06:00
|
|
|
}
|
|
|
|
|
2019-03-27 07:25:30 -06:00
|
|
|
func basename(filename string) string {
|
|
|
|
return strings.ToLower(filepath.Base(filename))
|
|
|
|
}
|
|
|
|
|
2019-05-03 22:04:18 -06:00
|
|
|
func (f *fileBase) URI() span.URI {
|
2019-03-27 07:25:30 -06:00
|
|
|
return f.uris[0]
|
2019-02-19 19:11:15 -07:00
|
|
|
}
|
|
|
|
|
2019-05-03 22:04:18 -06:00
|
|
|
func (f *fileBase) filename() string {
|
|
|
|
return f.fname
|
|
|
|
}
|
|
|
|
|
2019-04-17 16:21:47 -06:00
|
|
|
// View returns the view associated with the file.
|
2019-05-03 22:04:18 -06:00
|
|
|
func (f *fileBase) View() source.View {
|
2019-04-17 16:21:47 -06:00
|
|
|
return f.view
|
|
|
|
}
|
|
|
|
|
2019-05-17 10:15:22 -06:00
|
|
|
// Content returns the contents of the file, reading it from file system if needed.
|
|
|
|
func (f *fileBase) Content(ctx context.Context) *source.FileContent {
|
2018-12-05 15:00:36 -07:00
|
|
|
f.view.mu.Lock()
|
|
|
|
defer f.view.mu.Unlock()
|
2019-05-17 10:15:22 -06:00
|
|
|
f.read(ctx)
|
|
|
|
return f.fc
|
2018-12-05 15:00:36 -07:00
|
|
|
}
|
|
|
|
|
2019-05-17 08:51:19 -06:00
|
|
|
func (f *fileBase) FileSet() *token.FileSet {
|
|
|
|
return f.view.Session().Cache().FileSet()
|
2018-12-05 15:00:36 -07:00
|
|
|
}
|
|
|
|
|
2019-05-23 13:03:11 -06:00
|
|
|
// read is the internal part of GetContent. It assumes that the caller is
|
2019-03-04 16:01:51 -07:00
|
|
|
// holding the mutex of the file's view.
|
2019-05-03 22:04:18 -06:00
|
|
|
func (f *fileBase) read(ctx context.Context) {
|
2019-05-17 10:15:22 -06:00
|
|
|
if err := ctx.Err(); err != nil {
|
|
|
|
f.fc = &source.FileContent{Error: err}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if f.fc != nil {
|
2019-03-05 15:30:44 -07:00
|
|
|
if len(f.view.contentChanges) == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
f.view.mcache.mu.Lock()
|
|
|
|
err := f.view.applyContentChanges(ctx)
|
|
|
|
f.view.mcache.mu.Unlock()
|
|
|
|
|
2019-05-17 10:15:22 -06:00
|
|
|
if err != nil {
|
|
|
|
f.fc = &source.FileContent{Error: err}
|
2019-03-05 15:30:44 -07:00
|
|
|
return
|
|
|
|
}
|
2018-12-05 15:00:36 -07:00
|
|
|
}
|
2019-03-04 16:01:51 -07:00
|
|
|
// We don't know the content yet, so read it.
|
2019-05-17 10:15:22 -06:00
|
|
|
f.fc = f.view.Session().ReadFile(f.URI())
|
2018-12-05 15:00:36 -07:00
|
|
|
}
|
2019-03-05 15:30:44 -07:00
|
|
|
|
|
|
|
// isPopulated returns true if all of the computed fields of the file are set.
|
2019-05-03 22:04:18 -06:00
|
|
|
func (f *goFile) isPopulated() bool {
|
2019-03-05 15:30:44 -07:00
|
|
|
return f.ast != nil && f.token != nil && f.pkg != nil && f.meta != nil && f.imports != nil
|
|
|
|
}
|