diff --git a/internal/lsp/cache/check.go b/internal/lsp/cache/check.go index 707730af..c70fec91 100644 --- a/internal/lsp/cache/check.go +++ b/internal/lsp/cache/check.go @@ -150,7 +150,7 @@ func (v *View) link(pkgPath string, pkg *packages.Package, parent *metadata) *me m.name = pkg.Name m.files = pkg.CompiledGoFiles for _, filename := range m.files { - if f := v.findFile(span.FileURI(filename)); f != nil { + if f, _ := v.findFile(span.FileURI(filename)); f != nil { f.meta = m } } @@ -341,7 +341,10 @@ func (v *View) parseFiles(filenames []string) ([]*ast.File, []error) { } // First, check if we have already cached an AST for this file. - f := v.findFile(span.FileURI(filename)) + f, err := v.findFile(span.FileURI(filename)) + if err != nil { + parsed[i], errors[i] = nil, err + } var fAST *ast.File if f != nil { fAST = f.ast diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go index 3f3675c9..d0936f25 100644 --- a/internal/lsp/cache/view.go +++ b/internal/lsp/cache/view.go @@ -191,7 +191,7 @@ func (v *View) remove(pkgPath string) { // All of the files in the package may also be holding a pointer to the // invalidated package. for _, filename := range m.files { - if f := v.findFile(span.FileURI(filename)); f != nil { + if f, _ := v.findFile(span.FileURI(filename)); f != nil { f.pkg = nil } } @@ -213,7 +213,9 @@ func (v *View) GetFile(ctx context.Context, uri span.URI) (source.File, error) { // getFile is the unlocked internal implementation of GetFile. func (v *View) getFile(uri span.URI) (*File, error) { - if f := v.findFile(uri); f != nil { + if f, err := v.findFile(uri); err != nil { + return nil, err + } else if f != nil { return f, nil } filename, err := uri.Filename() @@ -228,34 +230,41 @@ func (v *View) getFile(uri span.URI) (*File, error) { return f, nil } -func (v *View) findFile(uri span.URI) *File { +// findFile checks the cache for any file matching the given uri. +// +// An error is only returned for an irreparable failure, for example, if the +// filename in question does not exist. +func (v *View) findFile(uri span.URI) (*File, error) { if f := v.filesByURI[uri]; f != nil { // a perfect match - return f + return f, nil } // no exact match stored, time to do some real work // check for any files with the same basename fname, err := uri.Filename() if err != nil { - return nil + return nil, err } basename := basename(fname) if candidates := v.filesByBase[basename]; candidates != nil { pathStat, err := os.Stat(fname) - if err != nil { - return nil + if os.IsNotExist(err) { + return nil, err + } else if err != nil { + return nil, nil // the file may exist, return without an error } for _, c := range candidates { if cStat, err := os.Stat(c.filename); err == nil { if os.SameFile(pathStat, cStat) { // same file, map it v.mapFile(uri, c) - return c + return c, nil } } } } - return nil + // no file with a matching name was found, it wasn't in our cache + return nil, nil } func (v *View) mapFile(uri span.URI, f *File) { diff --git a/internal/lsp/source/diagnostics.go b/internal/lsp/source/diagnostics.go index f6f39064..a20175f5 100644 --- a/internal/lsp/source/diagnostics.go +++ b/internal/lsp/source/diagnostics.go @@ -54,18 +54,11 @@ const ( func Diagnostics(ctx context.Context, v View, uri span.URI) (map[span.URI][]Diagnostic, error) { f, err := v.GetFile(ctx, uri) if err != nil { - return nil, err + return singleDiagnostic(uri, "no file found for %s", uri), nil } pkg := f.GetPackage(ctx) if pkg == nil { - return map[span.URI][]Diagnostic{ - uri: []Diagnostic{{ - Source: "LSP", - Span: span.New(uri, span.Point{}, span.Point{}), - Message: fmt.Sprintf("not part of a package"), - Severity: SeverityError, - }}, - }, nil + return singleDiagnostic(uri, "%s is not part of a package", uri), nil } // Prepare the reports we will send for this package. reports := make(map[span.URI][]Diagnostic) @@ -149,6 +142,17 @@ func Diagnostics(ctx context.Context, v View, uri span.URI) (map[span.URI][]Diag return reports, nil } +func singleDiagnostic(uri span.URI, format string, a ...interface{}) map[span.URI][]Diagnostic { + return map[span.URI][]Diagnostic{ + uri: []Diagnostic{{ + Source: "LSP", + Span: span.New(uri, span.Point{}, span.Point{}), + Message: fmt.Sprintf(format, a...), + Severity: SeverityError, + }}, + } +} + func runAnalyses(ctx context.Context, v View, pkg Package, report func(a *analysis.Analyzer, diag analysis.Diagnostic)) error { // the traditional vet suite: analyzers := []*analysis.Analyzer{