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:
parent
0ec5c269d4
commit
24738cbdc1
|
@ -150,7 +150,7 @@ func (v *View) link(pkgPath string, pkg *packages.Package, parent *metadata) *me
|
||||||
m.name = pkg.Name
|
m.name = pkg.Name
|
||||||
m.files = pkg.CompiledGoFiles
|
m.files = pkg.CompiledGoFiles
|
||||||
for _, filename := range m.files {
|
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
|
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.
|
// 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
|
var fAST *ast.File
|
||||||
if f != nil {
|
if f != nil {
|
||||||
fAST = f.ast
|
fAST = f.ast
|
||||||
|
|
|
@ -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
|
// All of the files in the package may also be holding a pointer to the
|
||||||
// invalidated package.
|
// invalidated package.
|
||||||
for _, filename := range m.files {
|
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
|
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.
|
// getFile is the unlocked internal implementation of GetFile.
|
||||||
func (v *View) getFile(uri span.URI) (*File, error) {
|
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
|
return f, nil
|
||||||
}
|
}
|
||||||
filename, err := uri.Filename()
|
filename, err := uri.Filename()
|
||||||
|
@ -228,34 +230,41 @@ func (v *View) getFile(uri span.URI) (*File, error) {
|
||||||
return f, nil
|
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 {
|
if f := v.filesByURI[uri]; f != nil {
|
||||||
// a perfect match
|
// a perfect match
|
||||||
return f
|
return f, nil
|
||||||
}
|
}
|
||||||
// no exact match stored, time to do some real work
|
// no exact match stored, time to do some real work
|
||||||
// check for any files with the same basename
|
// check for any files with the same basename
|
||||||
fname, err := uri.Filename()
|
fname, err := uri.Filename()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
basename := basename(fname)
|
basename := basename(fname)
|
||||||
if candidates := v.filesByBase[basename]; candidates != nil {
|
if candidates := v.filesByBase[basename]; candidates != nil {
|
||||||
pathStat, err := os.Stat(fname)
|
pathStat, err := os.Stat(fname)
|
||||||
if err != nil {
|
if os.IsNotExist(err) {
|
||||||
return nil
|
return nil, err
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, nil // the file may exist, return without an error
|
||||||
}
|
}
|
||||||
for _, c := range candidates {
|
for _, c := range candidates {
|
||||||
if cStat, err := os.Stat(c.filename); err == nil {
|
if cStat, err := os.Stat(c.filename); err == nil {
|
||||||
if os.SameFile(pathStat, cStat) {
|
if os.SameFile(pathStat, cStat) {
|
||||||
// same file, map it
|
// same file, map it
|
||||||
v.mapFile(uri, c)
|
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) {
|
func (v *View) mapFile(uri span.URI, f *File) {
|
||||||
|
|
|
@ -54,18 +54,11 @@ const (
|
||||||
func Diagnostics(ctx context.Context, v View, uri span.URI) (map[span.URI][]Diagnostic, error) {
|
func Diagnostics(ctx context.Context, v View, uri span.URI) (map[span.URI][]Diagnostic, error) {
|
||||||
f, err := v.GetFile(ctx, uri)
|
f, err := v.GetFile(ctx, uri)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return singleDiagnostic(uri, "no file found for %s", uri), nil
|
||||||
}
|
}
|
||||||
pkg := f.GetPackage(ctx)
|
pkg := f.GetPackage(ctx)
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
return map[span.URI][]Diagnostic{
|
return singleDiagnostic(uri, "%s is not part of a package", uri), nil
|
||||||
uri: []Diagnostic{{
|
|
||||||
Source: "LSP",
|
|
||||||
Span: span.New(uri, span.Point{}, span.Point{}),
|
|
||||||
Message: fmt.Sprintf("not part of a package"),
|
|
||||||
Severity: SeverityError,
|
|
||||||
}},
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
// Prepare the reports we will send for this package.
|
// Prepare the reports we will send for this package.
|
||||||
reports := make(map[span.URI][]Diagnostic)
|
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
|
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 {
|
func runAnalyses(ctx context.Context, v View, pkg Package, report func(a *analysis.Analyzer, diag analysis.Diagnostic)) error {
|
||||||
// the traditional vet suite:
|
// the traditional vet suite:
|
||||||
analyzers := []*analysis.Analyzer{
|
analyzers := []*analysis.Analyzer{
|
||||||
|
|
Loading…
Reference in New Issue