internal/lsp: add an error result to findFile
This change allows us to return diagnostics in the case of a file that
doesn't exist.
Change-Id: I6275c0dc9103a3f44070919937afe27c64545828
Reviewed-on: https://go-review.googlesource.com/c/tools/+/170009
Reviewed-by: Ian Cottrell <iancottrell@google.com>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/cache/check.go b/internal/lsp/cache/check.go
index 707730a..c70fec9 100644
--- a/internal/lsp/cache/check.go
+++ b/internal/lsp/cache/check.go
@@ -150,7 +150,7 @@
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 @@
}
// 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 3f3675c..d0936f2 100644
--- a/internal/lsp/cache/view.go
+++ b/internal/lsp/cache/view.go
@@ -191,7 +191,7 @@
// 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 @@
// 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 @@
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 f6f3906..a20175f 100644
--- a/internal/lsp/source/diagnostics.go
+++ b/internal/lsp/source/diagnostics.go
@@ -54,18 +54,11 @@
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 @@
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{