mirror of
https://github.com/golang/go
synced 2024-11-18 13:44:48 -07:00
internal/lsp: separate LSP files from FS files
FileHandle currently includes LSP-level information about Version and Session. That's dangerous, because the cache operates in terms of URIs and content only -- we explicitly want to share results across sessions and versions if they happen to be the same. Split the LSP information into separate types, VersionedFileHandle and VersionedFileIdentity. Change-Id: I158646b783375b58245468599301e2a29c657e71 Reviewed-on: https://go-review.googlesource.com/c/tools/+/245058 Run-TryBot: Heschi Kreinick <heschi@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
39fdd541e6
commit
c9619e8fac
12
internal/lsp/cache/cache.go
vendored
12
internal/lsp/cache/cache.go
vendored
@ -139,15 +139,15 @@ func (h *fileHandle) Kind() source.FileKind {
|
||||
return source.DetectLanguage("", h.uri.Filename())
|
||||
}
|
||||
|
||||
func (h *fileHandle) Version() float64 {
|
||||
return 0
|
||||
func (h *fileHandle) Hash() string {
|
||||
return h.hash
|
||||
}
|
||||
|
||||
func (h *fileHandle) Identity() source.FileIdentity {
|
||||
func (h *fileHandle) FileIdentity() source.FileIdentity {
|
||||
return source.FileIdentity{
|
||||
URI: h.uri,
|
||||
Identifier: h.hash,
|
||||
Kind: h.Kind(),
|
||||
URI: h.uri,
|
||||
Hash: h.hash,
|
||||
Kind: h.Kind(),
|
||||
}
|
||||
}
|
||||
|
||||
|
3
internal/lsp/cache/check.go
vendored
3
internal/lsp/cache/check.go
vendored
@ -174,7 +174,8 @@ func checkPackageKey(ctx context.Context, id packageID, pghs []*parseGoHandle, c
|
||||
b.WriteString(string(dep))
|
||||
}
|
||||
for _, cgf := range pghs {
|
||||
b.WriteString(cgf.file.Identity().String())
|
||||
b.WriteString(string(cgf.file.URI()))
|
||||
b.WriteString(cgf.file.FileIdentity().Hash)
|
||||
}
|
||||
return packageHandleKey(hashContents(b.Bytes()))
|
||||
}
|
||||
|
13
internal/lsp/cache/mod.go
vendored
13
internal/lsp/cache/mod.go
vendored
@ -54,7 +54,7 @@ func (s *snapshot) ParseMod(ctx context.Context, modFH source.FileHandle) (*sour
|
||||
return handle.parse(ctx, s)
|
||||
}
|
||||
|
||||
h := s.view.session.cache.store.Bind(modFH.Identity().String(), func(ctx context.Context, _ memoize.Arg) interface{} {
|
||||
h := s.view.session.cache.store.Bind(modFH.FileIdentity(), func(ctx context.Context, _ memoize.Arg) interface{} {
|
||||
_, done := event.Start(ctx, "cache.ParseModHandle", tag.URI.Of(modFH.URI()))
|
||||
defer done()
|
||||
|
||||
@ -96,7 +96,7 @@ func (s *snapshot) sumFH(ctx context.Context, modFH source.FileHandle) (source.F
|
||||
// cache. Avoid (*snapshot).GetFile here, as we don't want to add
|
||||
// nonexistent file handles to the snapshot if the file does not exist.
|
||||
sumURI := span.URIFromPath(sumFilename(modFH.URI()))
|
||||
sumFH := s.FindFile(sumURI)
|
||||
var sumFH source.FileHandle = s.FindFile(sumURI)
|
||||
if sumFH == nil {
|
||||
var err error
|
||||
sumFH, err = s.view.session.cache.getFile(ctx, sumURI)
|
||||
@ -158,8 +158,9 @@ func extractModParseErrors(uri span.URI, m *protocol.ColumnMapper, parseErr erro
|
||||
// modKey is uniquely identifies cached data for `go mod why` or dependencies
|
||||
// to upgrade.
|
||||
type modKey struct {
|
||||
sessionID, cfg, mod, view string
|
||||
verb modAction
|
||||
sessionID, cfg, view string
|
||||
mod source.FileIdentity
|
||||
verb modAction
|
||||
}
|
||||
|
||||
type modAction int
|
||||
@ -201,7 +202,7 @@ func (s *snapshot) ModWhy(ctx context.Context) (map[string]string, error) {
|
||||
key := modKey{
|
||||
sessionID: s.view.session.id,
|
||||
cfg: hashConfig(s.config(ctx)),
|
||||
mod: fh.Identity().String(),
|
||||
mod: fh.FileIdentity(),
|
||||
view: s.view.root.Filename(),
|
||||
verb: why,
|
||||
}
|
||||
@ -281,7 +282,7 @@ func (s *snapshot) ModUpgrade(ctx context.Context) (map[string]string, error) {
|
||||
key := modKey{
|
||||
sessionID: s.view.session.id,
|
||||
cfg: hashConfig(cfg),
|
||||
mod: fh.Identity().String(),
|
||||
mod: fh.FileIdentity(),
|
||||
view: s.view.root.Filename(),
|
||||
verb: upgrade,
|
||||
}
|
||||
|
4
internal/lsp/cache/mod_tidy.go
vendored
4
internal/lsp/cache/mod_tidy.go
vendored
@ -25,7 +25,7 @@ import (
|
||||
type modTidyKey struct {
|
||||
sessionID string
|
||||
cfg string
|
||||
gomod string
|
||||
gomod source.FileIdentity
|
||||
imports string
|
||||
unsavedOverlays string
|
||||
view string
|
||||
@ -85,7 +85,7 @@ func (s *snapshot) ModTidy(ctx context.Context) (*source.TidiedModule, error) {
|
||||
view: s.view.root.Filename(),
|
||||
imports: importHash,
|
||||
unsavedOverlays: overlayHash,
|
||||
gomod: modFH.Identity().String(),
|
||||
gomod: modFH.FileIdentity(),
|
||||
cfg: hashConfig(cfg),
|
||||
}
|
||||
h := s.view.session.cache.store.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
|
||||
|
4
internal/lsp/cache/parse.go
vendored
4
internal/lsp/cache/parse.go
vendored
@ -25,7 +25,7 @@ import (
|
||||
|
||||
// parseKey uniquely identifies a parsed Go file.
|
||||
type parseKey struct {
|
||||
file string // FileIdentity.String()
|
||||
file source.FileIdentity
|
||||
mode source.ParseMode
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ type parseGoData struct {
|
||||
|
||||
func (c *Cache) parseGoHandle(ctx context.Context, fh source.FileHandle, mode source.ParseMode) *parseGoHandle {
|
||||
key := parseKey{
|
||||
file: fh.Identity().String(),
|
||||
file: fh.FileIdentity(),
|
||||
mode: mode,
|
||||
}
|
||||
parseHandle := c.store.Bind(key, func(ctx context.Context, arg memoize.Arg) interface{} {
|
||||
|
67
internal/lsp/cache/session.go
vendored
67
internal/lsp/cache/session.go
vendored
@ -46,7 +46,7 @@ type overlay struct {
|
||||
version float64
|
||||
kind source.FileKind
|
||||
|
||||
// saved is true if a file has been saved on disk,
|
||||
// saved is true if a file matches the state on disk,
|
||||
// and therefore does not need to be part of the overlay sent to go/packages.
|
||||
saved bool
|
||||
}
|
||||
@ -55,13 +55,19 @@ func (o *overlay) Read() ([]byte, error) {
|
||||
return o.text, nil
|
||||
}
|
||||
|
||||
func (o *overlay) Identity() source.FileIdentity {
|
||||
func (o *overlay) FileIdentity() source.FileIdentity {
|
||||
return source.FileIdentity{
|
||||
URI: o.uri,
|
||||
Identifier: o.hash,
|
||||
SessionID: o.session.id,
|
||||
Version: o.version,
|
||||
Kind: o.kind,
|
||||
URI: o.uri,
|
||||
Hash: o.hash,
|
||||
Kind: o.kind,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *overlay) VersionedFileIdentity() source.VersionedFileIdentity {
|
||||
return source.VersionedFileIdentity{
|
||||
URI: o.uri,
|
||||
SessionID: o.session.id,
|
||||
Version: o.version,
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,9 +83,34 @@ func (o *overlay) Version() float64 {
|
||||
return o.version
|
||||
}
|
||||
|
||||
func (o *overlay) Session() source.Session { return o.session }
|
||||
func (o *overlay) Saved() bool { return o.saved }
|
||||
func (o *overlay) Data() []byte { return o.text }
|
||||
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) Session() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c *closedFile) Version() float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *Session) ID() string { return s.id }
|
||||
func (s *Session) String() string { return s.id }
|
||||
@ -146,7 +177,7 @@ func (s *Session) createView(ctx context.Context, name string, folder span.URI,
|
||||
packages: make(map[packageKey]*packageHandle),
|
||||
ids: make(map[span.URI][]packageID),
|
||||
metadata: make(map[packageID]*metadata),
|
||||
files: make(map[span.URI]source.FileHandle),
|
||||
files: make(map[span.URI]source.VersionedFileHandle),
|
||||
importedBy: make(map[packageID][]packageID),
|
||||
actions: make(map[actionKey]*actionHandle),
|
||||
workspacePackages: make(map[packageID]packagePath),
|
||||
@ -332,7 +363,7 @@ func (s *Session) ModifyFiles(ctx context.Context, changes []source.FileModifica
|
||||
}
|
||||
|
||||
func (s *Session) DidModifyFiles(ctx context.Context, changes []source.FileModification) ([]source.Snapshot, []func(), []span.URI, error) {
|
||||
views := make(map[*View]map[span.URI]source.FileHandle)
|
||||
views := make(map[*View]map[span.URI]source.VersionedFileHandle)
|
||||
|
||||
// Keep track of deleted files so that we can clear their diagnostics.
|
||||
// A file might be re-created after deletion, so only mark files that
|
||||
@ -362,21 +393,21 @@ func (s *Session) DidModifyFiles(ctx context.Context, changes []source.FileModif
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
if _, ok := views[view]; !ok {
|
||||
views[view] = make(map[span.URI]source.FileHandle)
|
||||
views[view] = make(map[span.URI]source.VersionedFileHandle)
|
||||
}
|
||||
var (
|
||||
fh source.FileHandle
|
||||
ok bool
|
||||
err error
|
||||
fh source.VersionedFileHandle
|
||||
ok bool
|
||||
)
|
||||
if fh, ok = overlays[c.URI]; ok {
|
||||
views[view][c.URI] = fh
|
||||
delete(deletions, c.URI)
|
||||
} else {
|
||||
fh, err = s.cache.getFile(ctx, c.URI)
|
||||
fsFile, err := s.cache.getFile(ctx, c.URI)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
fh = &closedFile{fsFile}
|
||||
views[view][c.URI] = fh
|
||||
if _, err := fh.Read(); err != nil {
|
||||
deletions[c.URI] = struct{}{}
|
||||
@ -488,7 +519,7 @@ func (s *Session) updateOverlays(ctx context.Context, changes []source.FileModif
|
||||
return nil, err
|
||||
}
|
||||
_, readErr := fh.Read()
|
||||
sameContentOnDisk = (readErr == nil && fh.Identity().Identifier == hash)
|
||||
sameContentOnDisk = (readErr == nil && fh.FileIdentity().Hash == hash)
|
||||
}
|
||||
o = &overlay{
|
||||
session: s,
|
||||
|
21
internal/lsp/cache/snapshot.go
vendored
21
internal/lsp/cache/snapshot.go
vendored
@ -58,7 +58,7 @@ type snapshot struct {
|
||||
|
||||
// files maps file URIs to their corresponding FileHandles.
|
||||
// It may invalidated when a file's content changes.
|
||||
files map[span.URI]source.FileHandle
|
||||
files map[span.URI]source.VersionedFileHandle
|
||||
|
||||
// packages maps a packageKey to a set of packageHandles to which that file belongs.
|
||||
// It may be invalidated when a file's content changes.
|
||||
@ -224,7 +224,7 @@ func (s *snapshot) buildOverlay() map[string][]byte {
|
||||
return overlays
|
||||
}
|
||||
|
||||
func hashUnsavedOverlays(files map[span.URI]source.FileHandle) string {
|
||||
func hashUnsavedOverlays(files map[span.URI]source.VersionedFileHandle) string {
|
||||
var unsaved []string
|
||||
for uri, fh := range files {
|
||||
if overlay, ok := fh.(*overlay); ok && !overlay.saved {
|
||||
@ -574,7 +574,7 @@ func (s *snapshot) isWorkspacePackage(id packageID) (packagePath, bool) {
|
||||
return scope, ok
|
||||
}
|
||||
|
||||
func (s *snapshot) FindFile(uri span.URI) source.FileHandle {
|
||||
func (s *snapshot) FindFile(uri span.URI) source.VersionedFileHandle {
|
||||
f, err := s.view.getFile(uri)
|
||||
if err != nil {
|
||||
return nil
|
||||
@ -588,7 +588,7 @@ func (s *snapshot) FindFile(uri span.URI) source.FileHandle {
|
||||
|
||||
// GetFile returns a File for the given URI. It will always succeed because it
|
||||
// adds the file to the managed set if needed.
|
||||
func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle, error) {
|
||||
func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.VersionedFileHandle, error) {
|
||||
f, err := s.view.getFile(uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -605,8 +605,9 @@ func (s *snapshot) GetFile(ctx context.Context, uri span.URI) (source.FileHandle
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.files[f.URI()] = fh
|
||||
return fh, nil
|
||||
closed := &closedFile{fh}
|
||||
s.files[f.URI()] = closed
|
||||
return closed, nil
|
||||
}
|
||||
|
||||
func (s *snapshot) IsOpen(uri span.URI) bool {
|
||||
@ -748,7 +749,7 @@ func contains(views []*View, view *View) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.FileHandle, forceReloadMetadata bool) *snapshot {
|
||||
func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.VersionedFileHandle, forceReloadMetadata bool) *snapshot {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
@ -761,7 +762,7 @@ func (s *snapshot) clone(ctx context.Context, withoutURIs map[span.URI]source.Fi
|
||||
metadata: make(map[packageID]*metadata),
|
||||
packages: make(map[packageKey]*packageHandle),
|
||||
actions: make(map[actionKey]*actionHandle),
|
||||
files: make(map[span.URI]source.FileHandle),
|
||||
files: make(map[span.URI]source.VersionedFileHandle),
|
||||
workspacePackages: make(map[packageID]packagePath),
|
||||
unloadableFiles: make(map[span.URI]struct{}),
|
||||
parseModHandles: make(map[span.URI]*parseModHandle),
|
||||
@ -955,7 +956,7 @@ func (s *snapshot) shouldInvalidateMetadata(ctx context.Context, originalFH, cur
|
||||
return currentFH.Kind() == source.Go
|
||||
}
|
||||
// If the file hasn't changed, there's no need to reload.
|
||||
if originalFH.Identity().String() == currentFH.Identity().String() {
|
||||
if originalFH.FileIdentity() == currentFH.FileIdentity() {
|
||||
return false
|
||||
}
|
||||
// If a go.mod file's contents have changed, always invalidate metadata.
|
||||
@ -1017,7 +1018,7 @@ func (s *snapshot) buildBuiltinPackage(ctx context.Context, goFiles []string) er
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := s.view.session.cache.store.Bind(fh.Identity(), func(ctx context.Context, arg memoize.Arg) interface{} {
|
||||
h := s.view.session.cache.store.Bind(fh.FileIdentity(), func(ctx context.Context, arg memoize.Arg) interface{} {
|
||||
snapshot := arg.(*snapshot)
|
||||
|
||||
pgh := snapshot.view.session.cache.parseGoHandle(ctx, fh, source.ParseFull)
|
||||
|
4
internal/lsp/cache/view.go
vendored
4
internal/lsp/cache/view.go
vendored
@ -326,7 +326,7 @@ func (v *View) RunProcessEnvFunc(ctx context.Context, fn func(*imports.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
modFileIdentifier = modFH.Identity().Identifier
|
||||
modFileIdentifier = modFH.FileIdentity().Hash
|
||||
}
|
||||
if v.sumURI != "" {
|
||||
sumFH, err = v.session.cache.getFile(ctx, v.sumURI)
|
||||
@ -695,7 +695,7 @@ func (v *View) awaitInitialized(ctx context.Context) {
|
||||
// invalidateContent invalidates the content of a Go file,
|
||||
// including any position and type information that depends on it.
|
||||
// It returns true if we were already tracking the given file, false otherwise.
|
||||
func (v *View) invalidateContent(ctx context.Context, uris map[span.URI]source.FileHandle, forceReloadMetadata bool) (source.Snapshot, func()) {
|
||||
func (v *View) invalidateContent(ctx context.Context, uris map[span.URI]source.VersionedFileHandle, forceReloadMetadata bool) (source.Snapshot, func()) {
|
||||
// Detach the context so that content invalidation cannot be canceled.
|
||||
ctx = xcontext.Detach(ctx)
|
||||
|
||||
|
@ -440,7 +440,7 @@ func extractionFixes(ctx context.Context, snapshot source.Snapshot, pkg source.P
|
||||
return actions, nil
|
||||
}
|
||||
|
||||
func documentChanges(fh source.FileHandle, edits []protocol.TextEdit) []protocol.TextDocumentEdit {
|
||||
func documentChanges(fh source.VersionedFileHandle, edits []protocol.TextEdit) []protocol.TextDocumentEdit {
|
||||
return []protocol.TextDocumentEdit{
|
||||
{
|
||||
TextDocument: protocol.VersionedTextDocumentIdentifier{
|
||||
|
@ -267,7 +267,7 @@ func (i *Instance) getFile(r *http.Request) interface{} {
|
||||
return nil
|
||||
}
|
||||
for _, o := range s.Overlays() {
|
||||
if o.Identity().Identifier == identifier {
|
||||
if o.FileIdentity().Hash == identifier {
|
||||
return o
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import (
|
||||
// idWithAnalysis is used to track if the diagnostics for a given file were
|
||||
// computed with analyses.
|
||||
type idWithAnalysis struct {
|
||||
id source.FileIdentity
|
||||
id source.VersionedFileIdentity
|
||||
withAnalysis bool
|
||||
}
|
||||
|
||||
@ -226,8 +226,7 @@ func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, r
|
||||
}
|
||||
source.SortDiagnostics(diagnostics)
|
||||
toSend := sentDiagnostics{
|
||||
version: key.id.Version,
|
||||
identifier: key.id.Identifier,
|
||||
id: key.id,
|
||||
sorted: diagnostics,
|
||||
withAnalysis: key.withAnalysis,
|
||||
snapshotID: snapshot.ID(),
|
||||
@ -255,7 +254,7 @@ func (s *Server) publishReports(ctx context.Context, snapshot source.Snapshot, r
|
||||
|
||||
// If we've already delivered diagnostics for this file, at this
|
||||
// snapshot, with analyses, do not send diagnostics without analyses.
|
||||
if delivered.snapshotID == toSend.snapshotID && delivered.version == toSend.version &&
|
||||
if delivered.snapshotID == toSend.snapshotID && delivered.id == toSend.id &&
|
||||
delivered.withAnalysis && !toSend.withAnalysis {
|
||||
// Do not update the delivered map since it already contains better diagnostics.
|
||||
continue
|
||||
@ -366,7 +365,7 @@ See https://github.com/golang/go/issues/39164 for more detail on this issue.`,
|
||||
return false
|
||||
}
|
||||
s.publishReports(ctx, snapshot, map[idWithAnalysis]map[string]*source.Diagnostic{
|
||||
{id: fh.Identity()}: {diagnosticKey(diag): diag},
|
||||
{id: fh.VersionedFileIdentity()}: {diagnosticKey(diag): diag},
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
@ -305,7 +305,7 @@ func (s *Server) fetchConfig(ctx context.Context, name string, folder span.URI,
|
||||
// it to a snapshot.
|
||||
// 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.
|
||||
func (s *Server) beginFileRequest(ctx context.Context, pURI protocol.DocumentURI, expectKind source.FileKind) (source.Snapshot, source.FileHandle, bool, func(), error) {
|
||||
func (s *Server) beginFileRequest(ctx context.Context, pURI protocol.DocumentURI, expectKind source.FileKind) (source.Snapshot, source.VersionedFileHandle, bool, func(), error) {
|
||||
uri := pURI.SpanURI()
|
||||
if !uri.IsFile() {
|
||||
// Not a file URI. Stop processing the request, but don't return an error.
|
||||
|
@ -474,7 +474,7 @@ func (r *runner) SuggestedFix(t *testing.T, spn span.Span, actionKinds []string)
|
||||
}
|
||||
}
|
||||
|
||||
func commandToEdits(ctx context.Context, snapshot source.Snapshot, fh source.FileHandle, rng protocol.Range, cmd string) ([]protocol.TextDocumentEdit, error) {
|
||||
func commandToEdits(ctx context.Context, snapshot source.Snapshot, fh source.VersionedFileHandle, rng protocol.Range, cmd string) ([]protocol.TextDocumentEdit, error) {
|
||||
var command *source.Command
|
||||
for _, c := range source.Commands {
|
||||
if c.Name == cmd {
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
"golang.org/x/tools/internal/span"
|
||||
)
|
||||
|
||||
func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.FileIdentity][]*source.Diagnostic, error) {
|
||||
func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.VersionedFileIdentity][]*source.Diagnostic, error) {
|
||||
uri := snapshot.View().ModFile()
|
||||
if uri == "" {
|
||||
return nil, nil
|
||||
@ -38,8 +38,8 @@ func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.File
|
||||
if err == source.ErrTmpModfileUnsupported {
|
||||
return nil, nil
|
||||
}
|
||||
reports := map[source.FileIdentity][]*source.Diagnostic{
|
||||
fh.Identity(): {},
|
||||
reports := map[source.VersionedFileIdentity][]*source.Diagnostic{
|
||||
fh.VersionedFileIdentity(): {},
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -59,7 +59,7 @@ func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.File
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reports[fh.Identity()] = append(reports[fh.Identity()], diag)
|
||||
reports[fh.VersionedFileIdentity()] = append(reports[fh.VersionedFileIdentity()], diag)
|
||||
}
|
||||
return reports, nil
|
||||
}
|
||||
|
@ -92,8 +92,7 @@ type Server struct {
|
||||
|
||||
// sentDiagnostics is used to cache diagnostics that have been sent for a given file.
|
||||
type sentDiagnostics struct {
|
||||
version float64
|
||||
identifier string
|
||||
id source.VersionedFileIdentity
|
||||
sorted []*source.Diagnostic
|
||||
withAnalysis bool
|
||||
snapshotID uint64
|
||||
|
@ -152,7 +152,7 @@ func (c *Command) IsSuggestedFix() bool {
|
||||
|
||||
// SuggestedFix applies the command's suggested fix to the given file and
|
||||
// range, returning the resulting edits.
|
||||
func (c *Command) SuggestedFix(ctx context.Context, snapshot Snapshot, fh FileHandle, pRng protocol.Range) ([]protocol.TextDocumentEdit, error) {
|
||||
func (c *Command) SuggestedFix(ctx context.Context, snapshot Snapshot, fh VersionedFileHandle, pRng protocol.Range) ([]protocol.TextDocumentEdit, error) {
|
||||
if c.suggestedFixFn == nil {
|
||||
return nil, fmt.Errorf("no suggested fix function for %s", c.Name)
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ type RelatedInformation struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func Diagnostics(ctx context.Context, snapshot Snapshot, pkg Package, withAnalysis bool) (map[FileIdentity][]*Diagnostic, bool, error) {
|
||||
func Diagnostics(ctx context.Context, snapshot Snapshot, pkg Package, withAnalysis bool) (map[VersionedFileIdentity][]*Diagnostic, bool, error) {
|
||||
onlyIgnoredFiles := true
|
||||
for _, pgf := range pkg.CompiledGoFiles() {
|
||||
onlyIgnoredFiles = onlyIgnoredFiles && snapshot.View().IgnoredFile(pgf.URI)
|
||||
@ -60,7 +60,7 @@ func Diagnostics(ctx context.Context, snapshot Snapshot, pkg Package, withAnalys
|
||||
warn = true
|
||||
}
|
||||
// Prepare the reports we will send for the files in this package.
|
||||
reports := make(map[FileIdentity][]*Diagnostic)
|
||||
reports := make(map[VersionedFileIdentity][]*Diagnostic)
|
||||
for _, pgf := range pkg.CompiledGoFiles() {
|
||||
clearReports(ctx, snapshot, reports, pgf.URI)
|
||||
}
|
||||
@ -124,31 +124,31 @@ func pickAnalyzers(snapshot Snapshot, hadTypeErrors bool) map[string]Analyzer {
|
||||
return analyzers
|
||||
}
|
||||
|
||||
func FileDiagnostics(ctx context.Context, snapshot Snapshot, uri span.URI) (FileIdentity, []*Diagnostic, error) {
|
||||
func FileDiagnostics(ctx context.Context, snapshot Snapshot, uri span.URI) (VersionedFileIdentity, []*Diagnostic, error) {
|
||||
fh, err := snapshot.GetFile(ctx, uri)
|
||||
if err != nil {
|
||||
return FileIdentity{}, nil, err
|
||||
return VersionedFileIdentity{}, nil, err
|
||||
}
|
||||
pkg, _, err := getParsedFile(ctx, snapshot, fh, NarrowestPackage)
|
||||
if err != nil {
|
||||
return FileIdentity{}, nil, err
|
||||
return VersionedFileIdentity{}, nil, err
|
||||
}
|
||||
reports, _, err := Diagnostics(ctx, snapshot, pkg, true)
|
||||
if err != nil {
|
||||
return FileIdentity{}, nil, err
|
||||
return VersionedFileIdentity{}, nil, err
|
||||
}
|
||||
diagnostics, ok := reports[fh.Identity()]
|
||||
diagnostics, ok := reports[fh.VersionedFileIdentity()]
|
||||
if !ok {
|
||||
return FileIdentity{}, nil, errors.Errorf("no diagnostics for %s", uri)
|
||||
return VersionedFileIdentity{}, nil, errors.Errorf("no diagnostics for %s", uri)
|
||||
}
|
||||
return fh.Identity(), diagnostics, nil
|
||||
return fh.VersionedFileIdentity(), diagnostics, nil
|
||||
}
|
||||
|
||||
type diagnosticSet struct {
|
||||
listErrors, parseErrors, typeErrors []*Diagnostic
|
||||
}
|
||||
|
||||
func diagnostics(ctx context.Context, snapshot Snapshot, reports map[FileIdentity][]*Diagnostic, pkg Package, hasMissingDeps bool) (bool, bool, error) {
|
||||
func diagnostics(ctx context.Context, snapshot Snapshot, reports map[VersionedFileIdentity][]*Diagnostic, pkg Package, hasMissingDeps bool) (bool, bool, error) {
|
||||
ctx, done := event.Start(ctx, "source.diagnostics", tag.Package.Of(pkg.ID()))
|
||||
_ = ctx // circumvent SA4006
|
||||
defer done()
|
||||
@ -198,7 +198,7 @@ func diagnostics(ctx context.Context, snapshot Snapshot, reports map[FileIdentit
|
||||
return nonEmptyDiagnostics, hasTypeErrors, nil
|
||||
}
|
||||
|
||||
func analyses(ctx context.Context, snapshot Snapshot, reports map[FileIdentity][]*Diagnostic, pkg Package, analyses map[string]Analyzer) error {
|
||||
func analyses(ctx context.Context, snapshot Snapshot, reports map[VersionedFileIdentity][]*Diagnostic, pkg Package, analyses map[string]Analyzer) error {
|
||||
var analyzers []*analysis.Analyzer
|
||||
for _, a := range analyses {
|
||||
if !a.Enabled(snapshot.View()) {
|
||||
@ -241,20 +241,20 @@ func analyses(ctx context.Context, snapshot Snapshot, reports map[FileIdentity][
|
||||
return nil
|
||||
}
|
||||
|
||||
func clearReports(ctx context.Context, snapshot Snapshot, reports map[FileIdentity][]*Diagnostic, uri span.URI) {
|
||||
func clearReports(ctx context.Context, snapshot Snapshot, reports map[VersionedFileIdentity][]*Diagnostic, uri span.URI) {
|
||||
fh := snapshot.FindFile(uri)
|
||||
if fh == nil {
|
||||
return
|
||||
}
|
||||
reports[fh.Identity()] = []*Diagnostic{}
|
||||
reports[fh.VersionedFileIdentity()] = []*Diagnostic{}
|
||||
}
|
||||
|
||||
func addReports(ctx context.Context, snapshot Snapshot, reports map[FileIdentity][]*Diagnostic, uri span.URI, diagnostics ...*Diagnostic) error {
|
||||
func addReports(ctx context.Context, snapshot Snapshot, reports map[VersionedFileIdentity][]*Diagnostic, uri span.URI, diagnostics ...*Diagnostic) error {
|
||||
fh := snapshot.FindFile(uri)
|
||||
if fh == nil {
|
||||
return nil
|
||||
}
|
||||
existingDiagnostics, ok := reports[fh.Identity()]
|
||||
existingDiagnostics, ok := reports[fh.VersionedFileIdentity()]
|
||||
if !ok {
|
||||
return fmt.Errorf("diagnostics for unexpected file %s", uri)
|
||||
}
|
||||
@ -268,12 +268,12 @@ func addReports(ctx context.Context, snapshot Snapshot, reports map[FileIdentity
|
||||
if d1.Message != d2.Message {
|
||||
continue
|
||||
}
|
||||
reports[fh.Identity()][i].Tags = append(reports[fh.Identity()][i].Tags, d1.Tags...)
|
||||
reports[fh.VersionedFileIdentity()][i].Tags = append(reports[fh.VersionedFileIdentity()][i].Tags, d1.Tags...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
reports[fh.Identity()] = append(reports[fh.Identity()], diagnostics...)
|
||||
reports[fh.VersionedFileIdentity()] = append(reports[fh.VersionedFileIdentity()], diagnostics...)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
"golang.org/x/tools/internal/span"
|
||||
)
|
||||
|
||||
func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, pkgDir span.URI) (map[FileIdentity][]*Diagnostic, error) {
|
||||
func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, pkgDir span.URI) (map[VersionedFileIdentity][]*Diagnostic, error) {
|
||||
outDir := filepath.Join(os.TempDir(), fmt.Sprintf("gopls-%d.details", os.Getpid()))
|
||||
if err := os.MkdirAll(outDir, 0700); err != nil {
|
||||
return nil, err
|
||||
@ -32,7 +32,7 @@ func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, pkgDir span.U
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reports := make(map[FileIdentity][]*Diagnostic)
|
||||
reports := make(map[VersionedFileIdentity][]*Diagnostic)
|
||||
var parseError error
|
||||
for _, fn := range files {
|
||||
fname, v, err := parseDetailsFile(fn)
|
||||
@ -48,8 +48,7 @@ func GCOptimizationDetails(ctx context.Context, snapshot Snapshot, pkgDir span.U
|
||||
if x == nil {
|
||||
continue
|
||||
}
|
||||
k := x.Identity()
|
||||
reports[k] = v
|
||||
reports[x.VersionedFileIdentity()] = v
|
||||
}
|
||||
return reports, parseError
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ type Snapshot interface {
|
||||
|
||||
// FindFile returns the FileHandle for the given URI, if it is already
|
||||
// in the given snapshot.
|
||||
FindFile(uri span.URI) FileHandle
|
||||
FindFile(uri span.URI) VersionedFileHandle
|
||||
|
||||
// GetFile returns the FileHandle for a given URI, initializing it
|
||||
// if it is not already part of the snapshot.
|
||||
GetFile(ctx context.Context, uri span.URI) (FileHandle, error)
|
||||
GetFile(ctx context.Context, uri span.URI) (VersionedFileHandle, error)
|
||||
|
||||
// IsOpen returns whether the editor currently has a file open.
|
||||
IsOpen(uri span.URI) bool
|
||||
@ -255,17 +255,10 @@ type Session interface {
|
||||
|
||||
// Overlay is the type for a file held in memory on a session.
|
||||
type Overlay interface {
|
||||
// Session returns the session this overlay belongs to.
|
||||
Session() Session
|
||||
|
||||
// Identity returns the FileIdentity for the overlay.
|
||||
Identity() FileIdentity
|
||||
VersionedFileHandle
|
||||
|
||||
// Saved returns whether this overlay has been saved to disk.
|
||||
Saved() bool
|
||||
|
||||
// Data is the contents of the overlay held in memory.
|
||||
Data() []byte
|
||||
}
|
||||
|
||||
// FileModification represents a modification to a file.
|
||||
@ -357,17 +350,35 @@ const (
|
||||
ParseFull
|
||||
)
|
||||
|
||||
type VersionedFileHandle interface {
|
||||
FileHandle
|
||||
Version() float64
|
||||
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 float64
|
||||
}
|
||||
|
||||
// FileHandle represents a handle to a specific version of a single file.
|
||||
type FileHandle interface {
|
||||
URI() span.URI
|
||||
Kind() FileKind
|
||||
Version() float64
|
||||
|
||||
// Identity returns a FileIdentity for the file, even if there was an error
|
||||
// reading it.
|
||||
// It is a fatal error to call Identity on a file that has not yet been read.
|
||||
Identity() FileIdentity
|
||||
|
||||
FileIdentity() FileIdentity
|
||||
// Read reads the contents of a file.
|
||||
// If the file is not available, returns a nil slice and an error.
|
||||
Read() ([]byte, error)
|
||||
@ -377,27 +388,13 @@ type FileHandle interface {
|
||||
type FileIdentity 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 float64
|
||||
|
||||
// Identifier represents a unique identifier for the file.
|
||||
// It could be a file's modification time or its SHA1 hash if it is not on disk.
|
||||
Identifier string
|
||||
// Identifier represents a unique identifier for the file's content.
|
||||
Hash string
|
||||
|
||||
// Kind is the file's kind.
|
||||
Kind FileKind
|
||||
}
|
||||
|
||||
func (fileID FileIdentity) String() string {
|
||||
// Version is not part of the FileIdentity string,
|
||||
// as it can remain change even if the file does not.
|
||||
return fmt.Sprintf("%s%s%s", fileID.URI, fileID.Identifier, fileID.Kind)
|
||||
}
|
||||
|
||||
// FileKind describes the kind of the file in question.
|
||||
// It can be one of Go, mod, or sum.
|
||||
type FileKind int
|
||||
|
Loading…
Reference in New Issue
Block a user