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>
This commit is contained in:
Rebecca Stambler 2019-03-29 16:14:24 -04:00
parent 0ec5c269d4
commit 24738cbdc1
3 changed files with 36 additions and 20 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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{