diff --git a/internal/lsp/cache/external.go b/internal/lsp/cache/external.go index 3f98b139cf..167cfaa085 100644 --- a/internal/lsp/cache/external.go +++ b/internal/lsp/cache/external.go @@ -13,6 +13,7 @@ import ( "golang.org/x/tools/internal/lsp/telemetry" "golang.org/x/tools/internal/span" "golang.org/x/tools/internal/telemetry/trace" + errors "golang.org/x/xerrors" ) // ioLimit limits the number of parallel file reads per process. @@ -28,17 +29,12 @@ type nativeFileHandle struct { } func (fs *nativeFileSystem) GetFile(uri span.URI) source.FileHandle { - identifier := "DOES NOT EXIST" - if fi, err := os.Stat(uri.Filename()); err == nil { - identifier = fi.ModTime().String() - } - kind := source.DetectLanguage("", uri.Filename()) return &nativeFileHandle{ fs: fs, identity: source.FileIdentity{ URI: uri, - Identifier: identifier, - Kind: kind, + Identifier: identifier(uri.Filename()), + Kind: source.DetectLanguage("", uri.Filename()), }, } } @@ -58,10 +54,20 @@ func (h *nativeFileHandle) Read(ctx context.Context) ([]byte, string, error) { ioLimit <- struct{}{} defer func() { <-ioLimit }() - // TODO: this should fail if the version is not the same as the handle + + if id := identifier(h.identity.URI.Filename()); id != h.identity.Identifier { + return nil, "", errors.Errorf("%s: file has been modified", h.identity.URI.Filename()) + } data, err := ioutil.ReadFile(h.identity.URI.Filename()) if err != nil { return nil, "", err } return data, hashContents(data), nil } + +func identifier(filename string) string { + if fi, err := os.Stat(filename); err == nil { + return fi.ModTime().String() + } + return "DOES NOT EXIST" +}