gopls/internal/lsp: consolidate the FileHandle API
Clean up several aspects of the FileHandle APIs.
- Eliminate the VersionedFileHandle. There is no need for this
specialization, when we already had the closedFile wrapper to make an
on-disk file satisfy the Versioning interface.
- Remove the VersionedFileIdentity concept. This was an artifact of an
earlier time when we stored files across sessions, views, and
snapshots. In all remaining uses, a snapshot is implied.
- Clean up now-unnecessary APIs accordingly.
- Rename cache.fileHandle and cache.overlay to cache.DiskFile and
cache.Overlay. There was some convenience to exporting Overlay, and
DiskFile was exported for symmetry.
- Remove a bunch of unnecessary test boilerplate.
- Remove the link from Overlay to Session, as it was only necessary for
debug templates.
Change-Id: I3cbf599c260d8e53c8ace913bbf92b2c6f054d3a
Reviewed-on: https://go-review.googlesource.com/c/tools/+/462818
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
diff --git a/gopls/internal/lsp/cache/cache.go b/gopls/internal/lsp/cache/cache.go
index 88d1b43..ef56b12 100644
--- a/gopls/internal/lsp/cache/cache.go
+++ b/gopls/internal/lsp/cache/cache.go
@@ -50,7 +50,7 @@
id: strconv.FormatInt(index, 10),
fset: fset,
store: store,
- fileContent: map[span.URI]*fileHandle{},
+ fileContent: map[span.URI]*DiskFile{},
}
return c
}
@@ -62,30 +62,40 @@
store *memoize.Store
fileMu sync.Mutex
- fileContent map[span.URI]*fileHandle
+ fileContent map[span.URI]*DiskFile
}
-type fileHandle struct {
- modTime time.Time
+// A DiskFile is a file on the filesystem, or a failure to read one.
+// It implements the source.FileHandle interface.
+type DiskFile struct {
uri span.URI
+ modTime time.Time
content []byte
hash source.Hash
err error
}
-func (h *fileHandle) Saved() bool {
- return true
+func (h *DiskFile) URI() span.URI { return h.uri }
+
+func (h *DiskFile) FileIdentity() source.FileIdentity {
+ return source.FileIdentity{
+ URI: h.uri,
+ Hash: h.hash,
+ }
+}
+
+func (h *DiskFile) Saved() bool { return true }
+func (h *DiskFile) Version() int32 { return 0 }
+
+func (h *DiskFile) Read() ([]byte, error) {
+ return h.content, h.err
}
// GetFile stats and (maybe) reads the file, updates the cache, and returns it.
func (c *Cache) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
- return c.getFile(ctx, uri)
-}
-
-func (c *Cache) getFile(ctx context.Context, uri span.URI) (*fileHandle, error) {
fi, statErr := os.Stat(uri.Filename())
if statErr != nil {
- return &fileHandle{
+ return &DiskFile{
err: statErr,
uri: uri,
}, nil
@@ -127,7 +137,7 @@
// ioLimit limits the number of parallel file reads per process.
var ioLimit = make(chan struct{}, 128)
-func readFile(ctx context.Context, uri span.URI, fi os.FileInfo) (*fileHandle, error) {
+func readFile(ctx context.Context, uri span.URI, fi os.FileInfo) (*DiskFile, error) {
select {
case ioLimit <- struct{}{}:
case <-ctx.Done():
@@ -143,7 +153,7 @@
if err != nil {
content = nil // just in case
}
- return &fileHandle{
+ return &DiskFile{
modTime: fi.ModTime(),
uri: uri,
content: content,
@@ -166,27 +176,12 @@
cache: c,
gocmdRunner: &gocommand.Runner{},
options: options,
- overlays: make(map[span.URI]*overlay),
+ overlays: make(map[span.URI]*Overlay),
}
event.Log(ctx, "New session", KeyCreateSession.Of(s))
return s
}
-func (h *fileHandle) URI() span.URI {
- return h.uri
-}
-
-func (h *fileHandle) FileIdentity() source.FileIdentity {
- return source.FileIdentity{
- URI: h.uri,
- Hash: h.hash,
- }
-}
-
-func (h *fileHandle) Read() ([]byte, error) {
- return h.content, h.err
-}
-
var cacheIndex, sessionIndex, viewIndex int64
func (c *Cache) ID() string { return c.id }
diff --git a/gopls/internal/lsp/cache/load.go b/gopls/internal/lsp/cache/load.go
index c4e0296..1d69504 100644
--- a/gopls/internal/lsp/cache/load.go
+++ b/gopls/internal/lsp/cache/load.go
@@ -335,7 +335,7 @@
rootMod = uri.Filename()
}
rootDir := filepath.Dir(rootMod)
- nestedModules := make(map[string][]source.VersionedFileHandle)
+ nestedModules := make(map[string][]source.FileHandle)
for _, fh := range openFiles {
mod, err := findRootPattern(ctx, filepath.Dir(fh.URI().Filename()), "go.mod", s)
if err != nil {
@@ -375,7 +375,7 @@
return nil, nil
}
-func (s *snapshot) applyCriticalErrorToFiles(ctx context.Context, msg string, files []source.VersionedFileHandle) []*source.Diagnostic {
+func (s *snapshot) applyCriticalErrorToFiles(ctx context.Context, msg string, files []source.FileHandle) []*source.Diagnostic {
var srcDiags []*source.Diagnostic
for _, fh := range files {
// Place the diagnostics on the package or module declarations.
diff --git a/gopls/internal/lsp/cache/maps.go b/gopls/internal/lsp/cache/maps.go
index 5cbcaf7..baa0deb 100644
--- a/gopls/internal/lsp/cache/maps.go
+++ b/gopls/internal/lsp/cache/maps.go
@@ -39,21 +39,21 @@
m.impl.Destroy()
}
-func (m filesMap) Get(key span.URI) (source.VersionedFileHandle, bool) {
+func (m filesMap) Get(key span.URI) (source.FileHandle, bool) {
value, ok := m.impl.Get(key)
if !ok {
return nil, false
}
- return value.(source.VersionedFileHandle), true
+ return value.(source.FileHandle), true
}
-func (m filesMap) Range(do func(key span.URI, value source.VersionedFileHandle)) {
+func (m filesMap) Range(do func(key span.URI, value source.FileHandle)) {
m.impl.Range(func(key, value interface{}) {
- do(key.(span.URI), value.(source.VersionedFileHandle))
+ do(key.(span.URI), value.(source.FileHandle))
})
}
-func (m filesMap) Set(key span.URI, value source.VersionedFileHandle) {
+func (m filesMap) Set(key span.URI, value source.FileHandle) {
m.impl.Set(key, value, nil)
}
diff --git a/gopls/internal/lsp/cache/mod.go b/gopls/internal/lsp/cache/mod.go
index b198dff..50f557d 100644
--- a/gopls/internal/lsp/cache/mod.go
+++ b/gopls/internal/lsp/cache/mod.go
@@ -188,7 +188,7 @@
var sumFH source.FileHandle = s.FindFile(sumURI)
if sumFH == nil {
var err error
- sumFH, err = s.view.cache.getFile(ctx, sumURI)
+ sumFH, err = s.view.cache.GetFile(ctx, sumURI)
if err != nil {
return nil
}
diff --git a/gopls/internal/lsp/cache/mod_tidy.go b/gopls/internal/lsp/cache/mod_tidy.go
index 385b014..def10d5 100644
--- a/gopls/internal/lsp/cache/mod_tidy.go
+++ b/gopls/internal/lsp/cache/mod_tidy.go
@@ -51,7 +51,7 @@
if err != nil {
return nil, err
}
- if _, ok := fh.(*overlay); ok {
+ if _, ok := fh.(*Overlay); ok {
if info, _ := os.Stat(uri.Filename()); info == nil {
return nil, source.ErrNoModOnDisk
}
diff --git a/gopls/internal/lsp/cache/mod_vuln.go b/gopls/internal/lsp/cache/mod_vuln.go
index b16c8c5..88d1a1c 100644
--- a/gopls/internal/lsp/cache/mod_vuln.go
+++ b/gopls/internal/lsp/cache/mod_vuln.go
@@ -37,7 +37,7 @@
if err != nil {
return nil, err
}
- if _, ok := fh.(*overlay); ok {
+ if _, ok := fh.(*Overlay); ok {
if info, _ := os.Stat(modURI.Filename()); info == nil {
return nil, source.ErrNoModOnDisk
}
diff --git a/gopls/internal/lsp/cache/session.go b/gopls/internal/lsp/cache/session.go
index 8293873..ab42d29 100644
--- a/gopls/internal/lsp/cache/session.go
+++ b/gopls/internal/lsp/cache/session.go
@@ -39,11 +39,12 @@
viewMap map[span.URI]*View // map of URI->best view
overlayMu sync.Mutex
- overlays map[span.URI]*overlay
+ overlays map[span.URI]*Overlay
}
-type overlay struct {
- session *Session
+// An Overlay is a file open in the editor.
+// It implements the source.FileSource interface.
+type Overlay struct {
uri span.URI
text []byte
hash source.Hash
@@ -55,69 +56,19 @@
saved bool
}
-func (o *overlay) Read() ([]byte, error) {
- return o.text, nil
-}
+func (o *Overlay) URI() span.URI { return o.uri }
-func (o *overlay) FileIdentity() source.FileIdentity {
+func (o *Overlay) FileIdentity() source.FileIdentity {
return source.FileIdentity{
URI: o.uri,
Hash: o.hash,
}
}
-func (o *overlay) VersionedFileIdentity() source.VersionedFileIdentity {
- return source.VersionedFileIdentity{
- URI: o.uri,
- SessionID: o.session.id,
- Version: o.version,
- }
-}
-
-func (o *overlay) Kind() source.FileKind {
- return o.kind
-}
-
-func (o *overlay) URI() span.URI {
- return o.uri
-}
-
-func (o *overlay) Version() int32 {
- return o.version
-}
-
-func (o *overlay) Session() string {
- return o.session.id
-}
-
-func (o *overlay) Saved() bool {
- return o.saved
-}
-
-// closedFile implements LSPFile for a file that the editor hasn't told us about.
-type closedFile struct {
- source.FileHandle
-}
-
-func (c *closedFile) VersionedFileIdentity() source.VersionedFileIdentity {
- return source.VersionedFileIdentity{
- URI: c.FileHandle.URI(),
- SessionID: "",
- Version: 0,
- }
-}
-
-func (c *closedFile) Saved() bool {
- return true
-}
-
-func (c *closedFile) Session() string {
- return ""
-}
-
-func (c *closedFile) Version() int32 {
- return 0
-}
+func (o *Overlay) Read() ([]byte, error) { return o.text, nil }
+func (o *Overlay) Version() int32 { return o.version }
+func (o *Overlay) Saved() bool { return o.saved }
+func (o *Overlay) Kind() source.FileKind { return o.kind }
// ID returns the unique identifier for this session on this server.
func (s *Session) ID() string { return s.id }
@@ -442,7 +393,7 @@
type fileChange struct {
content []byte
exists bool
- fileHandle source.VersionedFileHandle
+ fileHandle source.FileHandle
// isUnchanged indicates whether the file action is one that does not
// change the actual contents of the file. Opens and closes should not
@@ -579,16 +530,19 @@
isUnchanged: isUnchanged,
}
} else {
- fsFile, err := s.cache.getFile(ctx, c.URI)
+ fsFile, err := s.cache.GetFile(ctx, c.URI)
if err != nil {
return nil, nil, err
}
content, err := fsFile.Read()
- fh := &closedFile{fsFile}
+ if err != nil {
+ // Ignore the error: the file may be deleted.
+ content = nil
+ }
views[view][c.URI] = &fileChange{
content: content,
exists: err == nil,
- fileHandle: fh,
+ fileHandle: fsFile,
isUnchanged: isUnchanged,
}
}
@@ -701,7 +655,7 @@
}
// Precondition: caller holds s.viewMu lock.
-func (s *Session) updateOverlays(ctx context.Context, changes []source.FileModification) (map[span.URI]*overlay, error) {
+func (s *Session) updateOverlays(ctx context.Context, changes []source.FileModification) (map[span.URI]*Overlay, error) {
s.overlayMu.Lock()
defer s.overlayMu.Unlock()
@@ -768,15 +722,14 @@
}
sameContentOnDisk = true
default:
- fh, err := s.cache.getFile(ctx, c.URI)
+ fh, err := s.cache.GetFile(ctx, c.URI)
if err != nil {
return nil, err
}
_, readErr := fh.Read()
sameContentOnDisk = (readErr == nil && fh.FileIdentity().Hash == hash)
}
- o = &overlay{
- session: s,
+ o = &Overlay{
uri: c.URI,
version: version,
text: text,
@@ -801,7 +754,7 @@
// Get the overlays for each change while the session's overlay map is
// locked.
- overlays := make(map[span.URI]*overlay)
+ overlays := make(map[span.URI]*Overlay)
for _, c := range changes {
if o, ok := s.overlays[c.URI]; ok {
overlays[c.URI] = o
@@ -812,29 +765,22 @@
// GetFile returns a handle for the specified file.
func (s *Session) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
- if overlay := s.readOverlay(uri); overlay != nil {
+ s.overlayMu.Lock()
+ overlay, ok := s.overlays[uri]
+ s.overlayMu.Unlock()
+ if ok {
return overlay, nil
}
- // Fall back to the cache-level file system.
- return s.cache.getFile(ctx, uri)
-}
-func (s *Session) readOverlay(uri span.URI) *overlay {
- s.overlayMu.Lock()
- defer s.overlayMu.Unlock()
-
- if overlay, ok := s.overlays[uri]; ok {
- return overlay
- }
- return nil
+ return s.cache.GetFile(ctx, uri)
}
// Overlays returns a slice of file overlays for the session.
-func (s *Session) Overlays() []source.Overlay {
+func (s *Session) Overlays() []*Overlay {
s.overlayMu.Lock()
defer s.overlayMu.Unlock()
- overlays := make([]source.Overlay, 0, len(s.overlays))
+ overlays := make([]*Overlay, 0, len(s.overlays))
for _, overlay := range s.overlays {
overlays = append(overlays, overlay)
}
diff --git a/gopls/internal/lsp/cache/snapshot.go b/gopls/internal/lsp/cache/snapshot.go
index b78962e..0eef84e 100644
--- a/gopls/internal/lsp/cache/snapshot.go
+++ b/gopls/internal/lsp/cache/snapshot.go
@@ -268,12 +268,12 @@
return s.view.effectiveGOWORK()
}
-func (s *snapshot) Templates() map[span.URI]source.VersionedFileHandle {
+func (s *snapshot) Templates() map[span.URI]source.FileHandle {
s.mu.Lock()
defer s.mu.Unlock()
- tmpls := map[span.URI]source.VersionedFileHandle{}
- s.files.Range(func(k span.URI, fh source.VersionedFileHandle) {
+ tmpls := map[span.URI]source.FileHandle{}
+ s.files.Range(func(k span.URI, fh source.FileHandle) {
if s.view.FileKind(fh) == source.Tmpl {
tmpls[k] = fh
}
@@ -602,8 +602,8 @@
defer s.mu.Unlock()
overlays := make(map[string][]byte)
- s.files.Range(func(uri span.URI, fh source.VersionedFileHandle) {
- overlay, ok := fh.(*overlay)
+ s.files.Range(func(uri span.URI, fh source.FileHandle) {
+ overlay, ok := fh.(*Overlay)
if !ok {
return
}
@@ -879,7 +879,7 @@
s.knownSubdirs.Destroy()
s.knownSubdirs = newKnownDirsSet()
s.knownSubdirsPatternCache = ""
- s.files.Range(func(uri span.URI, fh source.VersionedFileHandle) {
+ s.files.Range(func(uri span.URI, fh source.FileHandle) {
s.addKnownSubdirLocked(uri, dirs)
})
}
@@ -963,7 +963,7 @@
s.mu.Lock()
defer s.mu.Unlock()
- s.files.Range(func(uri span.URI, fh source.VersionedFileHandle) {
+ s.files.Range(func(uri span.URI, fh source.FileHandle) {
if source.InDir(dir.Filename(), uri.Filename()) {
files = append(files, uri)
}
@@ -995,9 +995,9 @@
// Symbols extracts and returns the symbols for each file in all the snapshot's views.
func (s *snapshot) Symbols(ctx context.Context) map[span.URI][]source.Symbol {
// Read the set of Go files out of the snapshot.
- var goFiles []source.VersionedFileHandle
+ var goFiles []source.FileHandle
s.mu.Lock()
- s.files.Range(func(uri span.URI, f source.VersionedFileHandle) {
+ s.files.Range(func(uri span.URI, f source.FileHandle) {
if s.View().FileKind(f) == source.Go {
goFiles = append(goFiles, f)
}
@@ -1153,7 +1153,7 @@
return ok
}
-func (s *snapshot) FindFile(uri span.URI) source.VersionedFileHandle {
+func (s *snapshot) FindFile(uri span.URI) source.FileHandle {
uri, _ = s.view.canonicalURI(uri, true)
s.mu.Lock()
@@ -1163,12 +1163,12 @@
return result
}
-// GetVersionedFile returns a File for the given URI. If the file is unknown it
-// is added to the managed set.
+// GetFile returns a File for the given URI. If the file is unknown it is added
+// to the managed set.
//
-// GetVersionedFile succeeds even if the file does not exist. A non-nil error return
+// GetFile succeeds even if the file does not exist. A non-nil error return
// indicates some type of internal error, for example if ctx is cancelled.
-func (s *snapshot) GetVersionedFile(ctx context.Context, uri span.URI) (source.VersionedFileHandle, error) {
+func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
uri, _ = s.view.canonicalURI(uri, true)
s.mu.Lock()
@@ -1178,18 +1178,12 @@
return fh, nil
}
- fh, err := s.view.cache.getFile(ctx, uri) // read the file
+ fh, err := s.view.cache.GetFile(ctx, uri) // read the file
if err != nil {
return nil, err
}
- closed := &closedFile{fh}
- s.files.Set(uri, closed)
- return closed, nil
-}
-
-// GetFile implements the fileSource interface by wrapping GetVersionedFile.
-func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
- return s.GetVersionedFile(ctx, uri)
+ s.files.Set(uri, fh)
+ return fh, nil
}
func (s *snapshot) IsOpen(uri span.URI) bool {
@@ -1199,12 +1193,12 @@
}
-func (s *snapshot) openFiles() []source.VersionedFileHandle {
+func (s *snapshot) openFiles() []source.FileHandle {
s.mu.Lock()
defer s.mu.Unlock()
- var open []source.VersionedFileHandle
- s.files.Range(func(uri span.URI, fh source.VersionedFileHandle) {
+ var open []source.FileHandle
+ s.files.Range(func(uri span.URI, fh source.FileHandle) {
if isFileOpen(fh) {
open = append(open, fh)
}
@@ -1217,8 +1211,8 @@
return isFileOpen(fh)
}
-func isFileOpen(fh source.VersionedFileHandle) bool {
- _, open := fh.(*overlay)
+func isFileOpen(fh source.FileHandle) bool {
+ _, open := fh.(*Overlay)
return open
}
@@ -1479,14 +1473,14 @@
return nil
}
-func (s *snapshot) orphanedOpenFiles() []source.VersionedFileHandle {
+func (s *snapshot) orphanedOpenFiles() []source.FileHandle {
s.mu.Lock()
defer s.mu.Unlock()
- var files []source.VersionedFileHandle
- s.files.Range(func(uri span.URI, fh source.VersionedFileHandle) {
+ var files []source.FileHandle
+ s.files.Range(func(uri span.URI, fh source.FileHandle) {
// Only consider open files, which will be represented as overlays.
- if _, isOverlay := fh.(*overlay); !isOverlay {
+ if _, isOverlay := fh.(*Overlay); !isOverlay {
return
}
// Don't try to reload metadata for go.mod files.
@@ -1716,8 +1710,8 @@
// The original FileHandle for this URI is cached on the snapshot.
originalFH, _ := s.files.Get(uri)
var originalOpen, newOpen bool
- _, originalOpen = originalFH.(*overlay)
- _, newOpen = change.fileHandle.(*overlay)
+ _, originalOpen = originalFH.(*Overlay)
+ _, newOpen = change.fileHandle.(*Overlay)
anyFileOpenedOrClosed = anyFileOpenedOrClosed || (originalOpen != newOpen)
anyFileAdded = anyFileAdded || (originalFH == nil && change.fileHandle != nil)
@@ -1999,11 +1993,11 @@
// are both overlays, and if the current FileHandle is saved while the original
// FileHandle was not saved.
func fileWasSaved(originalFH, currentFH source.FileHandle) bool {
- c, ok := currentFH.(*overlay)
+ c, ok := currentFH.(*Overlay)
if !ok || c == nil {
return true
}
- o, ok := originalFH.(*overlay)
+ o, ok := originalFH.(*Overlay)
if !ok || o == nil {
return c.saved
}
diff --git a/gopls/internal/lsp/cache/view.go b/gopls/internal/lsp/cache/view.go
index a4c87c3..ea9016e 100644
--- a/gopls/internal/lsp/cache/view.go
+++ b/gopls/internal/lsp/cache/view.go
@@ -331,9 +331,9 @@
// The kind of an unsaved buffer comes from the
// TextDocumentItem.LanguageID field in the didChange event,
// not from the file name. They may differ.
- if o, ok := fh.(source.Overlay); ok {
- if o.Kind() != source.UnknownKind {
- return o.Kind()
+ if o, ok := fh.(*Overlay); ok {
+ if o.kind != source.UnknownKind {
+ return o.kind
}
}
diff --git a/gopls/internal/lsp/cache/view_test.go b/gopls/internal/lsp/cache/view_test.go
index 8adfbfa..4b45681 100644
--- a/gopls/internal/lsp/cache/view_test.go
+++ b/gopls/internal/lsp/cache/view_test.go
@@ -96,7 +96,7 @@
rel := fake.RelativeTo(dir)
folderURI := span.URIFromPath(rel.AbsPath(test.folder))
excludeNothing := func(string) bool { return false }
- got, err := findWorkspaceModFile(ctx, folderURI, &osFileSource{}, excludeNothing)
+ got, err := findWorkspaceModFile(ctx, folderURI, New(nil, nil), excludeNothing)
if err != nil {
t.Fatal(err)
}
diff --git a/gopls/internal/lsp/cache/workspace_test.go b/gopls/internal/lsp/cache/workspace_test.go
deleted file mode 100644
index 5f1e13e..0000000
--- a/gopls/internal/lsp/cache/workspace_test.go
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2020 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 (
- "context"
- "os"
-
- "golang.org/x/tools/gopls/internal/lsp/source"
- "golang.org/x/tools/gopls/internal/span"
-)
-
-// osFileSource is a fileSource that just reads from the operating system.
-type osFileSource struct {
- overlays map[span.URI]fakeOverlay
-}
-
-type fakeOverlay struct {
- source.VersionedFileHandle
- uri span.URI
- content string
- err error
- saved bool
-}
-
-func (o fakeOverlay) Saved() bool { return o.saved }
-
-func (o fakeOverlay) Read() ([]byte, error) {
- if o.err != nil {
- return nil, o.err
- }
- return []byte(o.content), nil
-}
-
-func (o fakeOverlay) URI() span.URI {
- return o.uri
-}
-
-// change updates the file source with the given file content. For convenience,
-// empty content signals a deletion. If saved is true, these changes are
-// persisted to disk.
-func (s *osFileSource) change(ctx context.Context, uri span.URI, content string, saved bool) (*fileChange, error) {
- if content == "" {
- delete(s.overlays, uri)
- if saved {
- if err := os.Remove(uri.Filename()); err != nil {
- return nil, err
- }
- }
- fh, err := s.GetFile(ctx, uri)
- if err != nil {
- return nil, err
- }
- data, err := fh.Read()
- return &fileChange{exists: err == nil, content: data, fileHandle: &closedFile{fh}}, nil
- }
- if s.overlays == nil {
- s.overlays = map[span.URI]fakeOverlay{}
- }
- s.overlays[uri] = fakeOverlay{uri: uri, content: content, saved: saved}
- return &fileChange{
- exists: content != "",
- content: []byte(content),
- fileHandle: s.overlays[uri],
- }, nil
-}
-
-func (s *osFileSource) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
- if overlay, ok := s.overlays[uri]; ok {
- return overlay, nil
- }
- fi, statErr := os.Stat(uri.Filename())
- if statErr != nil {
- return &fileHandle{
- err: statErr,
- uri: uri,
- }, nil
- }
- fh, err := readFile(ctx, uri, fi)
- if err != nil {
- return nil, err
- }
- return fh, nil
-}
diff --git a/gopls/internal/lsp/code_action.go b/gopls/internal/lsp/code_action.go
index 8f39ea9..ec918b7 100644
--- a/gopls/internal/lsp/code_action.go
+++ b/gopls/internal/lsp/code_action.go
@@ -366,7 +366,7 @@
return actions, nil
}
-func documentChanges(fh source.VersionedFileHandle, edits []protocol.TextEdit) []protocol.DocumentChanges {
+func documentChanges(fh source.FileHandle, edits []protocol.TextEdit) []protocol.DocumentChanges {
return []protocol.DocumentChanges{
{
TextDocumentEdit: &protocol.TextDocumentEdit{
@@ -410,7 +410,7 @@
for _, fix := range sd.SuggestedFixes {
var changes []protocol.DocumentChanges
for uri, edits := range fix.Edits {
- fh, err := snapshot.GetVersionedFile(ctx, uri)
+ fh, err := snapshot.GetFile(ctx, uri)
if err != nil {
return nil, err
}
diff --git a/gopls/internal/lsp/command.go b/gopls/internal/lsp/command.go
index b9e1fe6..a1ff862 100644
--- a/gopls/internal/lsp/command.go
+++ b/gopls/internal/lsp/command.go
@@ -70,9 +70,9 @@
// be populated, depending on which configuration is set. See comments in-line
// for details.
type commandDeps struct {
- snapshot source.Snapshot // present if cfg.forURI was set
- fh source.VersionedFileHandle // present if cfg.forURI was set
- work *progress.WorkDone // present cfg.progress was set
+ snapshot source.Snapshot // present if cfg.forURI was set
+ fh source.FileHandle // present if cfg.forURI was set
+ work *progress.WorkDone // present cfg.progress was set
}
type commandFunc func(context.Context, commandDeps) error
@@ -606,7 +606,7 @@
}
func applyFileEdits(ctx context.Context, snapshot source.Snapshot, uri span.URI, newContent []byte) ([]protocol.TextDocumentEdit, error) {
- fh, err := snapshot.GetVersionedFile(ctx, uri)
+ fh, err := snapshot.GetFile(ctx, uri)
if err != nil {
return nil, err
}
diff --git a/gopls/internal/lsp/debug/serve.go b/gopls/internal/lsp/debug/serve.go
index 6934adf..3e6a905 100644
--- a/gopls/internal/lsp/debug/serve.go
+++ b/gopls/internal/lsp/debug/serve.go
@@ -727,7 +727,6 @@
{{define "serverlink"}}<a href="/server/{{.}}">Server {{.}}</a>{{end}}
{{define "sessionlink"}}<a href="/session/{{.}}">Session {{.}}</a>{{end}}
{{define "viewlink"}}<a href="/view/{{.}}">View {{.}}</a>{{end}}
-{{define "filelink"}}<a href="/file/{{.Session}}/{{.FileIdentity.Hash}}">{{.FileIdentity.URI}}</a>{{end}}
`)).Funcs(template.FuncMap{
"fuint64": fuint64,
"fuint32": fuint32,
@@ -876,7 +875,11 @@
<h2>Views</h2>
<ul>{{range .Views}}<li>{{.Name}} is {{template "viewlink" .ID}} in {{.Folder}}</li>{{end}}</ul>
<h2>Overlays</h2>
-<ul>{{range .Overlays}}<li>{{template "filelink" .}}</li>{{end}}</ul>
+{{$session := .}}
+<ul>{{range .Overlays}}
+<li>
+<a href="/file/{{$session.ID}}/{{.FileIdentity.Hash}}">{{.FileIdentity.URI}}</a>
+</li>{{end}}</ul>
<h2>Options</h2>
{{range options .}}
<p><b>{{.Name}}</b> {{.Type}}</p>
@@ -900,7 +903,6 @@
{{define "title"}}Overlay {{.FileIdentity.Hash}}{{end}}
{{define "body"}}
{{with .}}
- From: <b>{{template "sessionlink" .Session}}</b><br>
URI: <b>{{.URI}}</b><br>
Identifier: <b>{{.FileIdentity.Hash}}</b><br>
Version: <b>{{.Version}}</b><br>
diff --git a/gopls/internal/lsp/diagnostics.go b/gopls/internal/lsp/diagnostics.go
index e7b290d..ef30b6f 100644
--- a/gopls/internal/lsp/diagnostics.go
+++ b/gopls/internal/lsp/diagnostics.go
@@ -247,16 +247,16 @@
}()
// common code for dispatching diagnostics
- store := func(dsource diagnosticSource, operation string, diagsByFileID map[source.VersionedFileIdentity][]*source.Diagnostic, err error, merge bool) {
+ store := func(dsource diagnosticSource, operation string, diagsByFile map[span.URI][]*source.Diagnostic, err error, merge bool) {
if err != nil {
event.Error(ctx, "warning: while "+operation, err, source.SnapshotLabels(snapshot)...)
}
- for id, diags := range diagsByFileID {
- if id.URI == "" {
+ for uri, diags := range diagsByFile {
+ if uri == "" {
event.Error(ctx, "missing URI while "+operation, fmt.Errorf("empty URI"), tag.Directory.Of(snapshot.View().Folder().Filename()))
continue
}
- s.storeDiagnostics(snapshot, id.URI, dsource, diags, merge)
+ s.storeDiagnostics(snapshot, uri, dsource, diags, merge)
}
}
@@ -425,14 +425,14 @@
// results. This ensures that the toggling of GC details and clearing of
// diagnostics does not race with storing the results here.
if enableGCDetails {
- for id, diags := range gcReports {
- fh := snapshot.FindFile(id.URI)
+ for uri, diags := range gcReports {
+ fh := snapshot.FindFile(uri)
// Don't publish gc details for unsaved buffers, since the underlying
// logic operates on the file on disk.
if fh == nil || !fh.Saved() {
continue
}
- s.storeDiagnostics(snapshot, id.URI, gcDetailsSource, diags, true)
+ s.storeDiagnostics(snapshot, uri, gcDetailsSource, diags, true)
}
}
s.gcOptimizationDetailsMu.Unlock()
@@ -543,7 +543,7 @@
// checkForOrphanedFile checks that the given URIs can be mapped to packages.
// If they cannot and the workspace is not otherwise unloaded, it also surfaces
// a warning, suggesting that the user check the file for build tags.
-func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snapshot, fh source.VersionedFileHandle) *source.Diagnostic {
+func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle) *source.Diagnostic {
// TODO(rfindley): this function may fail to produce a diagnostic for a
// variety of reasons, some of which should probably not be ignored. For
// example, should this function be tolerant of the case where fh does not
diff --git a/gopls/internal/lsp/general.go b/gopls/internal/lsp/general.go
index 1d7135e..87a86f4 100644
--- a/gopls/internal/lsp/general.go
+++ b/gopls/internal/lsp/general.go
@@ -549,7 +549,7 @@
// We don't want to return errors for benign conditions like wrong file type,
// so callers should do if !ok { return err } rather than if err != nil.
// The returned cleanup function is non-nil even in case of false/error result.
-func (s *Server) beginFileRequest(ctx context.Context, pURI protocol.DocumentURI, expectKind source.FileKind) (source.Snapshot, source.VersionedFileHandle, bool, func(), error) {
+func (s *Server) beginFileRequest(ctx context.Context, pURI protocol.DocumentURI, expectKind source.FileKind) (source.Snapshot, source.FileHandle, bool, func(), error) {
uri := pURI.SpanURI()
if !uri.IsFile() {
// Not a file URI. Stop processing the request, but don't return an error.
@@ -560,7 +560,7 @@
return nil, nil, false, func() {}, err
}
snapshot, release := view.Snapshot(ctx)
- fh, err := snapshot.GetVersionedFile(ctx, uri)
+ fh, err := snapshot.GetFile(ctx, uri)
if err != nil {
release()
return nil, nil, false, func() {}, err
diff --git a/gopls/internal/lsp/mod/diagnostics.go b/gopls/internal/lsp/mod/diagnostics.go
index 65b3786..3cbe352 100644
--- a/gopls/internal/lsp/mod/diagnostics.go
+++ b/gopls/internal/lsp/mod/diagnostics.go
@@ -26,7 +26,7 @@
// Diagnostics returns diagnostics for the modules in the workspace.
//
// It waits for completion of type-checking of all active packages.
-func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.VersionedFileIdentity][]*source.Diagnostic, error) {
+func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) {
ctx, done := event.Start(ctx, "mod.Diagnostics", source.SnapshotLabels(snapshot)...)
defer done()
@@ -35,7 +35,7 @@
// UpgradeDiagnostics returns upgrade diagnostics for the modules in the
// workspace with known upgrades.
-func UpgradeDiagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.VersionedFileIdentity][]*source.Diagnostic, error) {
+func UpgradeDiagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) {
ctx, done := event.Start(ctx, "mod.UpgradeDiagnostics", source.SnapshotLabels(snapshot)...)
defer done()
@@ -44,31 +44,31 @@
// VulnerabilityDiagnostics returns vulnerability diagnostics for the active modules in the
// workspace with known vulnerabilites.
-func VulnerabilityDiagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.VersionedFileIdentity][]*source.Diagnostic, error) {
+func VulnerabilityDiagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) {
ctx, done := event.Start(ctx, "mod.VulnerabilityDiagnostics", source.SnapshotLabels(snapshot)...)
defer done()
return collectDiagnostics(ctx, snapshot, ModVulnerabilityDiagnostics)
}
-func collectDiagnostics(ctx context.Context, snapshot source.Snapshot, diagFn func(context.Context, source.Snapshot, source.FileHandle) ([]*source.Diagnostic, error)) (map[source.VersionedFileIdentity][]*source.Diagnostic, error) {
- reports := make(map[source.VersionedFileIdentity][]*source.Diagnostic)
+func collectDiagnostics(ctx context.Context, snapshot source.Snapshot, diagFn func(context.Context, source.Snapshot, source.FileHandle) ([]*source.Diagnostic, error)) (map[span.URI][]*source.Diagnostic, error) {
+ reports := make(map[span.URI][]*source.Diagnostic)
for _, uri := range snapshot.ModFiles() {
- fh, err := snapshot.GetVersionedFile(ctx, uri)
+ fh, err := snapshot.GetFile(ctx, uri)
if err != nil {
return nil, err
}
- reports[fh.VersionedFileIdentity()] = []*source.Diagnostic{}
+ reports[fh.URI()] = []*source.Diagnostic{}
diagnostics, err := diagFn(ctx, snapshot, fh)
if err != nil {
return nil, err
}
for _, d := range diagnostics {
- fh, err := snapshot.GetVersionedFile(ctx, d.URI)
+ fh, err := snapshot.GetFile(ctx, d.URI)
if err != nil {
return nil, err
}
- reports[fh.VersionedFileIdentity()] = append(reports[fh.VersionedFileIdentity()], d)
+ reports[fh.URI()] = append(reports[fh.URI()], d)
}
}
return reports, nil
diff --git a/gopls/internal/lsp/rename.go b/gopls/internal/lsp/rename.go
index e9bb2d4..359d9ac 100644
--- a/gopls/internal/lsp/rename.go
+++ b/gopls/internal/lsp/rename.go
@@ -29,7 +29,7 @@
var docChanges []protocol.DocumentChanges
for uri, e := range edits {
- fh, err := snapshot.GetVersionedFile(ctx, uri)
+ fh, err := snapshot.GetFile(ctx, uri)
if err != nil {
return nil, err
}
diff --git a/gopls/internal/lsp/server.go b/gopls/internal/lsp/server.go
index 82d90dc..3d42df1 100644
--- a/gopls/internal/lsp/server.go
+++ b/gopls/internal/lsp/server.go
@@ -136,7 +136,7 @@
if err := s.client.PublishDiagnostics(ctx, &protocol.PublishDiagnosticsParams{
URI: protocol.URIFromSpanURI(fh.URI()),
Diagnostics: toProtocolDiagnostics(diagnostics),
- Version: fileID.Version,
+ Version: fileID.Version(),
}); err != nil {
return nil, err
}
diff --git a/gopls/internal/lsp/source/add_import.go b/gopls/internal/lsp/source/add_import.go
index c50c155..cd8ec7a 100644
--- a/gopls/internal/lsp/source/add_import.go
+++ b/gopls/internal/lsp/source/add_import.go
@@ -12,7 +12,7 @@
)
// AddImport adds a single import statement to the given file
-func AddImport(ctx context.Context, snapshot Snapshot, fh VersionedFileHandle, importPath string) ([]protocol.TextEdit, error) {
+func AddImport(ctx context.Context, snapshot Snapshot, fh FileHandle, importPath string) ([]protocol.TextEdit, error) {
pgf, err := snapshot.ParseGo(ctx, fh, ParseFull)
if err != nil {
return nil, err
diff --git a/gopls/internal/lsp/source/diagnostics.go b/gopls/internal/lsp/source/diagnostics.go
index b8fab6a..a7350b0 100644
--- a/gopls/internal/lsp/source/diagnostics.go
+++ b/gopls/internal/lsp/source/diagnostics.go
@@ -73,22 +73,22 @@
// "gopls/diagnoseFiles" nonstandard request handler. It would be more
// efficient to compute the set of packages and TypeCheck and
// Analyze them all at once.
-func FileDiagnostics(ctx context.Context, snapshot Snapshot, uri span.URI) (VersionedFileIdentity, []*Diagnostic, error) {
- fh, err := snapshot.GetVersionedFile(ctx, uri)
+func FileDiagnostics(ctx context.Context, snapshot Snapshot, uri span.URI) (FileHandle, []*Diagnostic, error) {
+ fh, err := snapshot.GetFile(ctx, uri)
if err != nil {
- return VersionedFileIdentity{}, nil, err
+ return nil, nil, err
}
pkg, _, err := PackageForFile(ctx, snapshot, uri, TypecheckFull, NarrowestPackage)
if err != nil {
- return VersionedFileIdentity{}, nil, err
+ return nil, nil, err
}
adiags, err := Analyze(ctx, snapshot, pkg.ID(), false)
if err != nil {
- return VersionedFileIdentity{}, nil, err
+ return nil, nil, err
}
var fileDiags []*Diagnostic // combine load/parse/type + analysis diagnostics
CombineDiagnostics(pkg, fh.URI(), adiags, &fileDiags, &fileDiags)
- return fh.VersionedFileIdentity(), fileDiags, nil
+ return fh, fileDiags, nil
}
// CombineDiagnostics combines and filters list/parse/type diagnostics
diff --git a/gopls/internal/lsp/source/fix.go b/gopls/internal/lsp/source/fix.go
index 50f1cb0..68e5f8e 100644
--- a/gopls/internal/lsp/source/fix.go
+++ b/gopls/internal/lsp/source/fix.go
@@ -27,7 +27,7 @@
// suggested fixes with their diagnostics, so we have to compute them
// separately. Such analyzers should provide a function with a signature of
// SuggestedFixFunc.
- SuggestedFixFunc func(ctx context.Context, snapshot Snapshot, fh VersionedFileHandle, pRng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error)
+ SuggestedFixFunc func(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error)
singleFileFixFunc func(fset *token.FileSet, rng safetoken.Range, src []byte, file *ast.File, pkg *types.Package, info *types.Info) (*analysis.SuggestedFix, error)
)
@@ -52,7 +52,7 @@
// singleFile calls analyzers that expect inputs for a single file
func singleFile(sf singleFileFixFunc) SuggestedFixFunc {
- return func(ctx context.Context, snapshot Snapshot, fh VersionedFileHandle, pRng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) {
+ return func(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) {
fset, rng, src, file, pkg, info, err := getAllSuggestedFixInputs(ctx, snapshot, fh, pRng)
if err != nil {
return nil, nil, err
@@ -72,7 +72,7 @@
// ApplyFix applies the command's suggested fix to the given file and
// range, returning the resulting edits.
-func ApplyFix(ctx context.Context, fix string, snapshot Snapshot, fh VersionedFileHandle, pRng protocol.Range) ([]protocol.TextDocumentEdit, error) {
+func ApplyFix(ctx context.Context, fix string, snapshot Snapshot, fh FileHandle, pRng protocol.Range) ([]protocol.TextDocumentEdit, error) {
handler, ok := suggestedFixes[fix]
if !ok {
return nil, fmt.Errorf("no suggested fix function for %s", fix)
@@ -94,7 +94,7 @@
if !end.IsValid() {
end = edit.Pos
}
- fh, err := snapshot.GetVersionedFile(ctx, span.URIFromPath(tokFile.Name()))
+ fh, err := snapshot.GetFile(ctx, span.URIFromPath(tokFile.Name()))
if err != nil {
return nil, err
}
diff --git a/gopls/internal/lsp/source/gc_annotations.go b/gopls/internal/lsp/source/gc_annotations.go
index d5245c8..72159e6 100644
--- a/gopls/internal/lsp/source/gc_annotations.go
+++ b/gopls/internal/lsp/source/gc_annotations.go
@@ -35,7 +35,7 @@
Bounds Annotation = "bounds"
)
-func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, m *Metadata) (map[VersionedFileIdentity][]*Diagnostic, error) {
+func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, m *Metadata) (map[span.URI][]*Diagnostic, error) {
if len(m.CompiledGoFiles) == 0 {
return nil, nil
}
@@ -74,7 +74,7 @@
if err != nil {
return nil, err
}
- reports := make(map[VersionedFileIdentity][]*Diagnostic)
+ reports := make(map[span.URI][]*Diagnostic)
opts := snapshot.View().Options()
var parseError error
for _, fn := range files {
@@ -93,7 +93,7 @@
// outside the package can never be taken back.
continue
}
- reports[fh.VersionedFileIdentity()] = diagnostics
+ reports[fh.URI()] = diagnostics
}
return reports, parseError
}
diff --git a/gopls/internal/lsp/source/known_packages.go b/gopls/internal/lsp/source/known_packages.go
index d84febe..07b4c30 100644
--- a/gopls/internal/lsp/source/known_packages.go
+++ b/gopls/internal/lsp/source/known_packages.go
@@ -24,7 +24,7 @@
// all dot-free paths (standard packages) appear before dotful ones.
//
// It is part of the gopls.list_known_packages command.
-func KnownPackagePaths(ctx context.Context, snapshot Snapshot, fh VersionedFileHandle) ([]PackagePath, error) {
+func KnownPackagePaths(ctx context.Context, snapshot Snapshot, fh FileHandle) ([]PackagePath, error) {
// This algorithm is expressed in terms of Metadata, not Packages,
// so it doesn't cause or wait for type checking.
diff --git a/gopls/internal/lsp/source/stub.go b/gopls/internal/lsp/source/stub.go
index c2edf08..cf360dd 100644
--- a/gopls/internal/lsp/source/stub.go
+++ b/gopls/internal/lsp/source/stub.go
@@ -25,7 +25,7 @@
"golang.org/x/tools/internal/typeparams"
)
-func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh VersionedFileHandle, rng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) {
+func stubSuggestedFixFunc(ctx context.Context, snapshot Snapshot, fh FileHandle, rng protocol.Range) (*token.FileSet, *analysis.SuggestedFix, error) {
pkg, pgf, err := PackageForFile(ctx, snapshot, fh.URI(), TypecheckWorkspace, NarrowestPackage)
if err != nil {
return nil, nil, fmt.Errorf("GetTypedFile: %w", err)
diff --git a/gopls/internal/lsp/source/view.go b/gopls/internal/lsp/source/view.go
index 0a96eb3..4b6fd13 100644
--- a/gopls/internal/lsp/source/view.go
+++ b/gopls/internal/lsp/source/view.go
@@ -78,11 +78,7 @@
// FindFile returns the FileHandle for the given URI, if it is already
// in the given snapshot.
- FindFile(uri span.URI) VersionedFileHandle
-
- // GetVersionedFile returns the VersionedFileHandle for a given URI,
- // initializing it if it is not already part of the snapshot.
- GetVersionedFile(ctx context.Context, uri span.URI) (VersionedFileHandle, error)
+ FindFile(uri span.URI) FileHandle
// GetFile returns the FileHandle for a given URI, initializing it if it is
// not already part of the snapshot.
@@ -99,7 +95,7 @@
IgnoredFile(uri span.URI) bool
// Templates returns the .tmpl files
- Templates() map[span.URI]VersionedFileHandle
+ Templates() map[span.URI]FileHandle
// ParseGo returns the parsed AST for the file.
// If the file is not available, returns nil and an error.
@@ -513,12 +509,6 @@
var ErrViewExists = errors.New("view already exists for session")
-// Overlay is the type for a file held in memory on a session.
-type Overlay interface {
- Kind() FileKind
- VersionedFileHandle
-}
-
// FileModification represents a modification to a file.
type FileModification struct {
URI span.URI
@@ -613,38 +603,26 @@
TypecheckWorkspace
)
-type VersionedFileHandle interface {
- FileHandle
- Version() int32
- Session() string
-
- // LSPIdentity returns the version identity of a file.
- VersionedFileIdentity() VersionedFileIdentity
-}
-
-type VersionedFileIdentity struct {
- URI span.URI
-
- // SessionID is the ID of the LSP session.
- SessionID string
-
- // Version is the version of the file, as specified by the client. It should
- // only be set in combination with SessionID.
- Version int32
-}
-
-// FileHandle represents a handle to a specific version of a single file.
+// A FileHandle is an interface to files tracked by the LSP session, which may
+// be either files read from disk, or open in the editor session (overlays).
type FileHandle interface {
+ // URI is the URI for this file handle.
+ // TODO(rfindley): this is not actually well-defined. In some cases, there
+ // may be more than one URI that resolve to the same FileHandle. Which one is
+ // this?
URI() span.URI
-
// FileIdentity returns a FileIdentity for the file, even if there was an
// error reading it.
FileIdentity() FileIdentity
+ // Saved reports whether the file has the same content on disk.
+ // For on-disk files, this is trivially true.
+ Saved() bool
+ // Version returns the file version, as defined by the LSP client.
+ // For on-disk file handles, Version returns 0.
+ Version() int32
// Read reads the contents of a file.
// If the file is not available, returns a nil slice and an error.
Read() ([]byte, error)
- // Saved reports whether the file has the same content on disk.
- Saved() bool
}
// A Hash is a cryptographic digest of the contents of a file.
diff --git a/gopls/internal/lsp/template/completion.go b/gopls/internal/lsp/template/completion.go
index 140c674..292563a 100644
--- a/gopls/internal/lsp/template/completion.go
+++ b/gopls/internal/lsp/template/completion.go
@@ -25,7 +25,7 @@
syms map[string]symbol
}
-func Completion(ctx context.Context, snapshot source.Snapshot, fh source.VersionedFileHandle, pos protocol.Position, context protocol.CompletionContext) (*protocol.CompletionList, error) {
+func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, pos protocol.Position, context protocol.CompletionContext) (*protocol.CompletionList, error) {
all := New(snapshot.Templates())
var start int // the beginning of the Token (completed or not)
syms := make(map[string]symbol)
diff --git a/gopls/internal/lsp/template/implementations.go b/gopls/internal/lsp/template/implementations.go
index 6c90b68..ed9b986 100644
--- a/gopls/internal/lsp/template/implementations.go
+++ b/gopls/internal/lsp/template/implementations.go
@@ -22,7 +22,7 @@
// Diagnose returns parse errors. There is only one.
// The errors are not always helpful. For instance { {end}}
// will likely point to the end of the file.
-func Diagnose(f source.VersionedFileHandle) []*source.Diagnostic {
+func Diagnose(f source.FileHandle) []*source.Diagnostic {
// no need for skipTemplate check, as Diagnose is called on the
// snapshot's template files
buf, err := f.Read()
@@ -73,7 +73,7 @@
// does not understand scoping (if any) in templates. This code is
// for definitions, type definitions, and implementations.
// Results only for variables and templates.
-func Definition(snapshot source.Snapshot, fh source.VersionedFileHandle, loc protocol.Position) ([]protocol.Location, error) {
+func Definition(snapshot source.Snapshot, fh source.FileHandle, loc protocol.Position) ([]protocol.Location, error) {
x, _, err := symAtPosition(fh, loc)
if err != nil {
return nil, err
diff --git a/gopls/internal/lsp/template/parse.go b/gopls/internal/lsp/template/parse.go
index eb644c0..a6befdc 100644
--- a/gopls/internal/lsp/template/parse.go
+++ b/gopls/internal/lsp/template/parse.go
@@ -70,7 +70,7 @@
// New returns the Parses of the snapshot's tmpl files
// (maybe cache these, but then avoiding import cycles needs code rearrangements)
-func New(tmpls map[span.URI]source.VersionedFileHandle) *All {
+func New(tmpls map[span.URI]source.FileHandle) *All {
all := make(map[span.URI]*Parsed)
for k, v := range tmpls {
buf, err := v.Read()
diff --git a/gopls/internal/lsp/work/completion.go b/gopls/internal/lsp/work/completion.go
index 223f022..bcdc2d1 100644
--- a/gopls/internal/lsp/work/completion.go
+++ b/gopls/internal/lsp/work/completion.go
@@ -18,7 +18,7 @@
"golang.org/x/tools/internal/event"
)
-func Completion(ctx context.Context, snapshot source.Snapshot, fh source.VersionedFileHandle, position protocol.Position) (*protocol.CompletionList, error) {
+func Completion(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, position protocol.Position) (*protocol.CompletionList, error) {
ctx, done := event.Start(ctx, "work.Completion")
defer done()
diff --git a/gopls/internal/lsp/work/diagnostics.go b/gopls/internal/lsp/work/diagnostics.go
index c64027c..cbcc850 100644
--- a/gopls/internal/lsp/work/diagnostics.go
+++ b/gopls/internal/lsp/work/diagnostics.go
@@ -17,30 +17,30 @@
"golang.org/x/tools/internal/event"
)
-func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.VersionedFileIdentity][]*source.Diagnostic, error) {
+func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[span.URI][]*source.Diagnostic, error) {
ctx, done := event.Start(ctx, "work.Diagnostics", source.SnapshotLabels(snapshot)...)
defer done()
- reports := map[source.VersionedFileIdentity][]*source.Diagnostic{}
+ reports := map[span.URI][]*source.Diagnostic{}
uri := snapshot.WorkFile()
if uri == "" {
return nil, nil
}
- fh, err := snapshot.GetVersionedFile(ctx, uri)
+ fh, err := snapshot.GetFile(ctx, uri)
if err != nil {
return nil, err
}
- reports[fh.VersionedFileIdentity()] = []*source.Diagnostic{}
+ reports[fh.URI()] = []*source.Diagnostic{}
diagnostics, err := DiagnosticsForWork(ctx, snapshot, fh)
if err != nil {
return nil, err
}
for _, d := range diagnostics {
- fh, err := snapshot.GetVersionedFile(ctx, d.URI)
+ fh, err := snapshot.GetFile(ctx, d.URI)
if err != nil {
return nil, err
}
- reports[fh.VersionedFileIdentity()] = append(reports[fh.VersionedFileIdentity()], d)
+ reports[fh.URI()] = append(reports[fh.URI()], d)
}
return reports, nil
diff --git a/gopls/test/debug/debug_test.go b/gopls/test/debug/debug_test.go
index 9d5d6f0..9bd8928 100644
--- a/gopls/test/debug/debug_test.go
+++ b/gopls/test/debug/debug_test.go
@@ -13,7 +13,6 @@
import (
"go/ast"
"html/template"
- "log"
"runtime"
"sort"
"strings"
@@ -23,16 +22,12 @@
"golang.org/x/tools/go/packages"
"golang.org/x/tools/gopls/internal/lsp/cache"
"golang.org/x/tools/gopls/internal/lsp/debug"
- "golang.org/x/tools/gopls/internal/lsp/source"
- "golang.org/x/tools/gopls/internal/span"
)
-type tdata struct {
+var templates = map[string]struct {
tmpl *template.Template
data interface{} // a value of the needed type
-}
-
-var templates = map[string]tdata{
+}{
"MainTmpl": {debug.MainTmpl, &debug.Instance{}},
"DebugTmpl": {debug.DebugTmpl, nil},
"RPCTmpl": {debug.RPCTmpl, &debug.Rpcs{}},
@@ -42,45 +37,9 @@
"ViewTmpl": {debug.ViewTmpl, &cache.View{}},
"ClientTmpl": {debug.ClientTmpl, &debug.Client{}},
"ServerTmpl": {debug.ServerTmpl, &debug.Server{}},
- //"FileTmpl": {FileTmpl, source.Overlay{}}, // need to construct a source.Overlay in init
- "InfoTmpl": {debug.InfoTmpl, "something"},
- "MemoryTmpl": {debug.MemoryTmpl, runtime.MemStats{}},
-}
-
-// construct a source.Overlay for fileTmpl
-type fakeOverlay struct{}
-
-func (fakeOverlay) Version() int32 {
- return 0
-}
-func (fakeOverlay) Session() string {
- return ""
-}
-func (fakeOverlay) VersionedFileIdentity() source.VersionedFileIdentity {
- return source.VersionedFileIdentity{}
-}
-func (fakeOverlay) FileIdentity() source.FileIdentity {
- return source.FileIdentity{}
-}
-func (fakeOverlay) Kind() source.FileKind {
- return 0
-}
-func (fakeOverlay) Read() ([]byte, error) {
- return nil, nil
-}
-func (fakeOverlay) Saved() bool {
- return true
-}
-func (fakeOverlay) URI() span.URI {
- return ""
-}
-
-var _ source.Overlay = fakeOverlay{}
-
-func init() {
- log.SetFlags(log.Lshortfile)
- var v fakeOverlay
- templates["FileTmpl"] = tdata{debug.FileTmpl, v}
+ "FileTmpl": {debug.FileTmpl, &cache.Overlay{}},
+ "InfoTmpl": {debug.InfoTmpl, "something"},
+ "MemoryTmpl": {debug.MemoryTmpl, runtime.MemStats{}},
}
func TestTemplates(t *testing.T) {
@@ -169,6 +128,7 @@
ast.Inspect(tree, f)
return ans
}
+
func treeOf(p *packages.Package, fname string) *ast.File {
for _, tree := range p.Syntax {
loc := tree.Package