mirror of https://github.com/golang/go.git
internal/lsp: add parse errors as diagnostics even when parsing fails
When a package consists of files that only fail to parse, we fail to associate parse errors with the package, and therefore return no diagnostics. To address this, we need to associate the errors with the package. This involves adding a *token.File to the parseGoData so that error messages and positions can be properly extracted, even when there is no associated AST. Fixes golang/go#39763 Change-Id: I5620821b9bcbeb499c498f9061dcf487d159bed5 Reviewed-on: https://go-review.googlesource.com/c/tools/+/243579 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Heschi Kreinick <heschi@google.com>
This commit is contained in:
parent
7017fd6b13
commit
b5fc9d354d
|
|
@ -331,6 +331,19 @@ func typeCheck(ctx context.Context, fset *token.FileSet, m *metadata, mode sourc
|
|||
// race to Unsafe.completed.
|
||||
return pkg, nil
|
||||
} else if len(files) == 0 { // not the unsafe package, no parsed files
|
||||
// Try to attach errors messages to the file as much as possible.
|
||||
var found bool
|
||||
for _, e := range rawErrors {
|
||||
srcErr, err := sourceError(ctx, fset, pkg, e)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
pkg.errors = append(pkg.errors, srcErr)
|
||||
}
|
||||
if found {
|
||||
return pkg, nil
|
||||
}
|
||||
return nil, errors.Errorf("no parsed files for package %s, expected: %s, errors: %v, list errors: %v", pkg.pkgPath, pkg.compiledGoFiles, actualErrors, rawErrors)
|
||||
} else {
|
||||
pkg.types = types.NewPackage(string(m.pkgPath), string(m.name))
|
||||
|
|
|
|||
|
|
@ -208,30 +208,29 @@ func typeErrorRange(ctx context.Context, fset *token.FileSet, pkg *pkg, pos toke
|
|||
}
|
||||
|
||||
func scannerErrorRange(fset *token.FileSet, pkg *pkg, posn token.Position) (span.Span, error) {
|
||||
ph, _, err := source.FindFileInPackage(pkg, span.URIFromPath(posn.Filename))
|
||||
pgh, _, err := source.FindFileInPackage(pkg, span.URIFromPath(posn.Filename))
|
||||
if err != nil {
|
||||
return span.Span{}, err
|
||||
}
|
||||
file, _, _, _, err := ph.Cached()
|
||||
if err != nil {
|
||||
return span.Span{}, err
|
||||
data, err := pgh.(*parseGoHandle).cached()
|
||||
if data.tok == nil {
|
||||
if err != nil {
|
||||
return span.Span{}, err
|
||||
}
|
||||
return span.Span{}, errors.Errorf("no token.File for %s: %v", pgh.File().URI(), data.err)
|
||||
}
|
||||
tok := fset.File(file.Pos())
|
||||
if tok == nil {
|
||||
return span.Span{}, errors.Errorf("no token.File for %s", ph.File().URI())
|
||||
}
|
||||
pos := tok.Pos(posn.Offset)
|
||||
pos := data.tok.Pos(posn.Offset)
|
||||
return span.NewRange(fset, pos, pos).Span()
|
||||
}
|
||||
|
||||
// spanToRange converts a span.Span to a protocol.Range,
|
||||
// assuming that the span belongs to the package whose diagnostics are being computed.
|
||||
func spanToRange(pkg *pkg, spn span.Span) (protocol.Range, error) {
|
||||
ph, _, err := source.FindFileInPackage(pkg, spn.URI())
|
||||
pgh, _, err := source.FindFileInPackage(pkg, spn.URI())
|
||||
if err != nil {
|
||||
return protocol.Range{}, err
|
||||
}
|
||||
_, _, m, _, err := ph.Cached()
|
||||
_, _, m, _, err := pgh.Cached()
|
||||
if err != nil {
|
||||
return protocol.Range{}, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ type parseGoData struct {
|
|||
memoize.NoCopy
|
||||
|
||||
ast *ast.File
|
||||
tok *token.File
|
||||
mapper *protocol.ColumnMapper
|
||||
|
||||
// Source code used to build the AST. It may be different from the
|
||||
|
|
@ -112,12 +113,20 @@ func (pgh *parseGoHandle) parse(ctx context.Context) (*parseGoData, error) {
|
|||
}
|
||||
|
||||
func (pgh *parseGoHandle) Cached() (*ast.File, []byte, *protocol.ColumnMapper, error, error) {
|
||||
data, err := pgh.cached()
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
return data.ast, data.src, data.mapper, data.parseError, data.err
|
||||
}
|
||||
|
||||
func (pgh *parseGoHandle) cached() (*parseGoData, error) {
|
||||
v := pgh.handle.Cached()
|
||||
if v == nil {
|
||||
return nil, nil, nil, nil, errors.Errorf("no cached AST for %s", pgh.file.URI())
|
||||
return nil, errors.Errorf("no cached AST for %s", pgh.file.URI())
|
||||
}
|
||||
data := v.(*parseGoData)
|
||||
return data.ast, data.src, data.mapper, data.parseError, data.err
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (pgh *parseGoHandle) PosToDecl(ctx context.Context) (map[token.Pos]ast.Decl, error) {
|
||||
|
|
@ -278,7 +287,19 @@ func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mod
|
|||
if file != nil {
|
||||
tok = fset.File(file.Pos())
|
||||
if tok == nil {
|
||||
return &parseGoData{err: errors.Errorf("successfully parsed but no token.File for %s (%v)", fh.URI(), parseError)}
|
||||
tok = fset.AddFile(fh.URI().Filename(), -1, len(buf))
|
||||
tok.SetLinesForContent(buf)
|
||||
return &parseGoData{
|
||||
ast: file,
|
||||
src: buf,
|
||||
tok: tok,
|
||||
mapper: &protocol.ColumnMapper{
|
||||
URI: fh.URI(),
|
||||
Content: buf,
|
||||
Converter: span.NewTokenConverter(fset, tok),
|
||||
},
|
||||
parseError: parseError,
|
||||
}
|
||||
}
|
||||
|
||||
// Fix any badly parsed parts of the AST.
|
||||
|
|
@ -319,6 +340,7 @@ func parseGo(ctx context.Context, fset *token.FileSet, fh source.FileHandle, mod
|
|||
return &parseGoData{
|
||||
src: buf,
|
||||
ast: file,
|
||||
tok: tok,
|
||||
mapper: m,
|
||||
parseError: parseError,
|
||||
fixed: fixed,
|
||||
|
|
|
|||
|
|
@ -1098,3 +1098,23 @@ func main() {
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
// Reproduces golang/go#39763.
|
||||
func TestInvalidPackageName(t *testing.T) {
|
||||
testenv.NeedsGo1Point(t, 15)
|
||||
|
||||
const pkgDefault = `
|
||||
-- go.mod --
|
||||
module mod.com
|
||||
-- main.go --
|
||||
package default
|
||||
|
||||
func main() {}
|
||||
`
|
||||
runner.Run(t, pkgDefault, func(t *testing.T, env *Env) {
|
||||
env.OpenFile("main.go")
|
||||
env.Await(
|
||||
env.DiagnosticAtRegexp("main.go", "default"),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue