mirror of https://github.com/golang/go.git
internal/lsp: remove redundant fields/code after source.Error deletion
Collapse Diagnostic.Kind, Source, and Category into just Source. Remove code that converted from Diagnostic to Diagnostic. Notes on the changes I had to make along the way: - We used to use Kind to determine Severity. Set Severity when the Diagnostic is created instead. - Use constants for Source as much as possible -- we still need to use Analyzer.Name for analysis diagnostics. It would be nice to break that dependency so that Source was totally opaque, but that's a separate issue. - Introduce a new Source for gc_details, "optimizer details". It was "go compiler" previously. - Some of the assignments are a little arbitrary. Is inconsistent vendoring really a "go list" error? - GetTypeCheckDiagnostics had code to cope with diagnostics that had no URI associated with them. We now spread such diagnostics to all files when they are generated. - Analyze modifies Diagnostics by adding a Tag to them. That means it has to own them, so I had it clone them. I would like to push that logic down to the diagnostics, per the TODO, but that's another CL. And some observations: - It's obviously tempting to combine DiagnosticSource and diagnosticSource, but they mean very different things. I'm open to a better name for one or the other. Change-Id: If2e861d6fe16bfd2e5ba216cf7e29cf338d0fd25 Reviewed-on: https://go-review.googlesource.com/c/tools/+/288215 Trust: Heschi Kreinick <heschi@google.com> Run-TryBot: Heschi Kreinick <heschi@google.com> gopls-CI: kokoro <noreply+kokoro@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
51ce8377eb
commit
e7dfe0279f
|
|
@ -18,6 +18,7 @@ import (
|
|||
"golang.org/x/tools/internal/analysisinternal"
|
||||
"golang.org/x/tools/internal/event"
|
||||
"golang.org/x/tools/internal/lsp/debug/tag"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
"golang.org/x/tools/internal/memoize"
|
||||
errors "golang.org/x/xerrors"
|
||||
|
|
@ -347,7 +348,7 @@ func runAnalysis(ctx context.Context, snapshot *snapshot, analyzer *analysis.Ana
|
|||
}
|
||||
|
||||
for _, diag := range diagnostics {
|
||||
srcErr, err := sourceDiagnostic(ctx, snapshot, pkg, diag)
|
||||
srcDiags, err := sourceDiagnostics(ctx, snapshot, pkg, protocol.SeverityWarning, diag)
|
||||
if err != nil {
|
||||
event.Error(ctx, "unable to compute analysis error position", err, tag.Category.Of(diag.Category), tag.Package.Of(pkg.ID()))
|
||||
continue
|
||||
|
|
@ -356,7 +357,7 @@ func runAnalysis(ctx context.Context, snapshot *snapshot, analyzer *analysis.Ana
|
|||
data.err = ctx.Err()
|
||||
return data
|
||||
}
|
||||
data.diagnostics = append(data.diagnostics, srcErr)
|
||||
data.diagnostics = append(data.diagnostics, srcDiags...)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import (
|
|||
"golang.org/x/tools/go/packages"
|
||||
"golang.org/x/tools/internal/event"
|
||||
"golang.org/x/tools/internal/lsp/debug/tag"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
"golang.org/x/tools/internal/memoize"
|
||||
"golang.org/x/tools/internal/span"
|
||||
|
|
@ -377,12 +378,12 @@ func typeCheck(ctx context.Context, snapshot *snapshot, m *metadata, mode source
|
|||
// Try to attach errors messages to the file as much as possible.
|
||||
var found bool
|
||||
for _, e := range rawErrors {
|
||||
srcErr, err := sourceDiagnostic(ctx, snapshot, pkg, e)
|
||||
srcDiags, err := sourceDiagnostics(ctx, snapshot, pkg, protocol.SeverityError, e)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
pkg.diagnostics = append(pkg.diagnostics, srcErr)
|
||||
pkg.diagnostics = append(pkg.diagnostics, srcDiags...)
|
||||
}
|
||||
if found {
|
||||
return pkg, nil
|
||||
|
|
@ -439,12 +440,13 @@ func typeCheck(ctx context.Context, snapshot *snapshot, m *metadata, mode source
|
|||
if mode == source.ParseFull {
|
||||
expandErrors(rawErrors)
|
||||
for _, e := range rawErrors {
|
||||
srcErr, err := sourceDiagnostic(ctx, snapshot, pkg, e)
|
||||
srcDiags, err := sourceDiagnostics(ctx, snapshot, pkg, protocol.SeverityError, e)
|
||||
if err != nil {
|
||||
event.Error(ctx, "unable to compute error positions", err, tag.Package.Of(pkg.ID()))
|
||||
continue
|
||||
}
|
||||
pkg.diagnostics = append(pkg.diagnostics, srcErr)
|
||||
pkg.diagnostics = append(pkg.diagnostics, srcDiags...)
|
||||
|
||||
if err, ok := e.(extendedError); ok {
|
||||
pkg.typeErrors = append(pkg.typeErrors, err.primary)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,23 +26,23 @@ import (
|
|||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func sourceDiagnostic(ctx context.Context, snapshot *snapshot, pkg *pkg, e interface{}) (*source.Diagnostic, error) {
|
||||
func sourceDiagnostics(ctx context.Context, snapshot *snapshot, pkg *pkg, severity protocol.DiagnosticSeverity, e interface{}) ([]*source.Diagnostic, error) {
|
||||
fset := snapshot.view.session.cache.fset
|
||||
var (
|
||||
spn span.Span
|
||||
err error
|
||||
msg, category string
|
||||
code typesinternal.ErrorCode
|
||||
kind source.ErrorKind
|
||||
fixes []source.SuggestedFix
|
||||
related []source.RelatedInformation
|
||||
spn span.Span
|
||||
err error
|
||||
msg string
|
||||
code typesinternal.ErrorCode
|
||||
diagSrc source.DiagnosticSource
|
||||
fixes []source.SuggestedFix
|
||||
related []source.RelatedInformation
|
||||
)
|
||||
switch e := e.(type) {
|
||||
case packages.Error:
|
||||
kind = toSourceErrorKind(e.Kind)
|
||||
diagSrc = toDiagnosticSource(e.Kind)
|
||||
var ok bool
|
||||
if msg, spn, ok = parseGoListImportCycleError(ctx, snapshot, e, pkg); ok {
|
||||
kind = source.TypeError
|
||||
diagSrc = source.TypeError
|
||||
break
|
||||
}
|
||||
if e.Pos == "" {
|
||||
|
|
@ -50,18 +50,23 @@ func sourceDiagnostic(ctx context.Context, snapshot *snapshot, pkg *pkg, e inter
|
|||
|
||||
// We may not have been able to parse a valid span.
|
||||
if _, err := spanToRange(snapshot, pkg, spn); err != nil {
|
||||
return &source.Diagnostic{
|
||||
URI: spn.URI(),
|
||||
Message: msg,
|
||||
Kind: kind,
|
||||
}, nil
|
||||
var diags []*source.Diagnostic
|
||||
for _, cgf := range pkg.compiledGoFiles {
|
||||
diags = append(diags, &source.Diagnostic{
|
||||
URI: cgf.URI,
|
||||
Severity: severity,
|
||||
Source: diagSrc,
|
||||
Message: msg,
|
||||
})
|
||||
}
|
||||
return diags, nil
|
||||
}
|
||||
} else {
|
||||
spn = span.Parse(e.Pos)
|
||||
}
|
||||
case *scanner.Error:
|
||||
msg = e.Msg
|
||||
kind = source.ParseError
|
||||
diagSrc = source.ParseError
|
||||
spn, err = scannerErrorRange(snapshot, pkg, e.Pos)
|
||||
if err != nil {
|
||||
if ctx.Err() != nil {
|
||||
|
|
@ -77,7 +82,7 @@ func sourceDiagnostic(ctx context.Context, snapshot *snapshot, pkg *pkg, e inter
|
|||
return nil, errors.Errorf("no errors in %v", e)
|
||||
}
|
||||
msg = e[0].Msg
|
||||
kind = source.ParseError
|
||||
diagSrc = source.ParseError
|
||||
spn, err = scannerErrorRange(snapshot, pkg, e[0].Pos)
|
||||
if err != nil {
|
||||
if ctx.Err() != nil {
|
||||
|
|
@ -88,7 +93,7 @@ func sourceDiagnostic(ctx context.Context, snapshot *snapshot, pkg *pkg, e inter
|
|||
}
|
||||
case types.Error:
|
||||
msg = e.Msg
|
||||
kind = source.TypeError
|
||||
diagSrc = source.TypeError
|
||||
if !e.Pos.IsValid() {
|
||||
return nil, fmt.Errorf("invalid position for type error %v", e)
|
||||
}
|
||||
|
|
@ -99,7 +104,7 @@ func sourceDiagnostic(ctx context.Context, snapshot *snapshot, pkg *pkg, e inter
|
|||
case extendedError:
|
||||
perr := e.primary
|
||||
msg = perr.Msg
|
||||
kind = source.TypeError
|
||||
diagSrc = source.TypeError
|
||||
if !perr.Pos.IsValid() {
|
||||
return nil, fmt.Errorf("invalid position for type error %v", e)
|
||||
}
|
||||
|
|
@ -128,8 +133,7 @@ func sourceDiagnostic(ctx context.Context, snapshot *snapshot, pkg *pkg, e inter
|
|||
return nil, err
|
||||
}
|
||||
msg = e.Message
|
||||
kind = source.Analysis
|
||||
category = e.Category
|
||||
diagSrc = source.AnalyzerErrorKind(e.Category)
|
||||
fixes, err = suggestedAnalysisFixes(snapshot, pkg, e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -148,17 +152,17 @@ func sourceDiagnostic(ctx context.Context, snapshot *snapshot, pkg *pkg, e inter
|
|||
sd := &source.Diagnostic{
|
||||
URI: spn.URI(),
|
||||
Range: rng,
|
||||
Severity: severity,
|
||||
Source: diagSrc,
|
||||
Message: msg,
|
||||
Kind: kind,
|
||||
Category: category,
|
||||
SuggestedFixes: fixes,
|
||||
Related: related,
|
||||
SuggestedFixes: fixes,
|
||||
}
|
||||
if code != 0 {
|
||||
sd.Code = code.String()
|
||||
sd.CodeHref = typesCodeHref(snapshot, code)
|
||||
}
|
||||
return sd, nil
|
||||
return []*source.Diagnostic{sd}, nil
|
||||
}
|
||||
|
||||
func typesCodeHref(snapshot *snapshot, code typesinternal.ErrorCode) string {
|
||||
|
|
@ -212,7 +216,7 @@ func relatedInformation(snapshot *snapshot, pkg *pkg, diag *analysis.Diagnostic)
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func toSourceErrorKind(kind packages.ErrorKind) source.ErrorKind {
|
||||
func toDiagnosticSource(kind packages.ErrorKind) source.DiagnosticSource {
|
||||
switch kind {
|
||||
case packages.ListError:
|
||||
return source.ListError
|
||||
|
|
|
|||
|
|
@ -273,10 +273,11 @@ func (s *snapshot) applyCriticalErrorToFiles(ctx context.Context, msg string, fi
|
|||
}
|
||||
}
|
||||
srcDiags = append(srcDiags, &source.Diagnostic{
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Kind: source.ListError,
|
||||
Message: msg,
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: source.ListError,
|
||||
Message: msg,
|
||||
})
|
||||
}
|
||||
return srcDiags
|
||||
|
|
|
|||
|
|
@ -22,11 +22,6 @@ import (
|
|||
"golang.org/x/tools/internal/span"
|
||||
)
|
||||
|
||||
const (
|
||||
SyntaxError = "syntax"
|
||||
GoCommandError = "go command"
|
||||
)
|
||||
|
||||
type parseModHandle struct {
|
||||
handle *memoize.Handle
|
||||
}
|
||||
|
|
@ -315,10 +310,11 @@ outer:
|
|||
msg = fmt.Sprintf("%v@%v has not been downloaded", innermost.Path, innermost.Version)
|
||||
}
|
||||
return &source.Diagnostic{
|
||||
Message: msg,
|
||||
Kind: source.ListError,
|
||||
Range: rng,
|
||||
URI: fh.URI(),
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityError,
|
||||
Message: msg,
|
||||
Source: source.ListError,
|
||||
SuggestedFixes: []source.SuggestedFix{{
|
||||
Title: fmt.Sprintf("Download %v@%v", innermost.Path, innermost.Version),
|
||||
Command: &protocol.Command{
|
||||
|
|
@ -329,11 +325,16 @@ outer:
|
|||
}},
|
||||
}
|
||||
}
|
||||
diagSource := source.ListError
|
||||
if fh != nil {
|
||||
diagSource = source.ParseError
|
||||
}
|
||||
return &source.Diagnostic{
|
||||
Message: goCmdError,
|
||||
Range: rng,
|
||||
URI: fh.URI(),
|
||||
Kind: source.ListError,
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: diagSource,
|
||||
Message: goCmdError,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -377,14 +378,15 @@ func extractErrorWithPosition(ctx context.Context, goCmdError string, src source
|
|||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
category := GoCommandError
|
||||
diagSource := source.ListError
|
||||
if fh != nil {
|
||||
category = SyntaxError
|
||||
diagSource = source.ParseError
|
||||
}
|
||||
return &source.Diagnostic{
|
||||
Category: category,
|
||||
Message: msg,
|
||||
Range: rng,
|
||||
URI: spn.URI(),
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: diagSource,
|
||||
Message: msg,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,9 +180,10 @@ func (s *snapshot) parseModError(ctx context.Context, fh source.FileHandle, errT
|
|||
switch {
|
||||
case isInconsistentVendor:
|
||||
return &source.Diagnostic{
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Kind: source.ListError,
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: source.ListError,
|
||||
Message: `Inconsistent vendoring detected. Please re-run "go mod vendor".
|
||||
See https://github.com/golang/go/issues/39164 for more detail on this issue.`,
|
||||
SuggestedFixes: []source.SuggestedFix{{
|
||||
|
|
@ -197,10 +198,11 @@ See https://github.com/golang/go/issues/39164 for more detail on this issue.`,
|
|||
|
||||
case isGoSumUpdates:
|
||||
return &source.Diagnostic{
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Kind: source.ListError,
|
||||
Message: `go.sum is out of sync with go.mod. Please update it or run "go mod tidy".`,
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: source.ListError,
|
||||
Message: `go.sum is out of sync with go.mod. Please update it or run "go mod tidy".`,
|
||||
SuggestedFixes: []source.SuggestedFix{
|
||||
{
|
||||
Title: source.CommandTidy.Title,
|
||||
|
|
@ -388,10 +390,11 @@ func unusedDiagnostic(m *protocol.ColumnMapper, req *modfile.Require, onlyDiagno
|
|||
return nil, err
|
||||
}
|
||||
return &source.Diagnostic{
|
||||
Category: source.GoModTidy,
|
||||
Message: fmt.Sprintf("%s is not used in this module", req.Mod.Path),
|
||||
Range: rng,
|
||||
URI: m.URI,
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityWarning,
|
||||
Source: source.ModTidyError,
|
||||
Message: fmt.Sprintf("%s is not used in this module", req.Mod.Path),
|
||||
SuggestedFixes: []source.SuggestedFix{{
|
||||
Title: fmt.Sprintf("Remove dependency: %s", req.Mod.Path),
|
||||
Command: &protocol.Command{
|
||||
|
|
@ -431,10 +434,11 @@ func directnessDiagnostic(m *protocol.ColumnMapper, req *modfile.Require, comput
|
|||
return nil, err
|
||||
}
|
||||
return &source.Diagnostic{
|
||||
Message: fmt.Sprintf("%s should be %s", req.Mod.Path, direction),
|
||||
Range: rng,
|
||||
URI: m.URI,
|
||||
Category: source.GoModTidy,
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityWarning,
|
||||
Source: source.ModTidyError,
|
||||
Message: fmt.Sprintf("%s should be %s", req.Mod.Path, direction),
|
||||
SuggestedFixes: []source.SuggestedFix{{
|
||||
Title: fmt.Sprintf("Change %s to %s", req.Mod.Path, direction),
|
||||
Edits: map[span.URI][]protocol.TextEdit{
|
||||
|
|
@ -462,9 +466,9 @@ func missingModuleDiagnostic(snapshot source.Snapshot, pm *source.ParsedModule,
|
|||
return &source.Diagnostic{
|
||||
URI: pm.Mapper.URI,
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: source.ModTidyError,
|
||||
Message: fmt.Sprintf("%s is not in your go.mod file", req.Mod.Path),
|
||||
Category: source.GoModTidy,
|
||||
Kind: source.ModTidyError,
|
||||
SuggestedFixes: []source.SuggestedFix{{
|
||||
Title: fmt.Sprintf("Add %s to your go.mod file", req.Mod.Path),
|
||||
Command: &protocol.Command{
|
||||
|
|
@ -527,11 +531,11 @@ func missingModuleForImport(snapshot source.Snapshot, m *protocol.ColumnMapper,
|
|||
return nil, err
|
||||
}
|
||||
return &source.Diagnostic{
|
||||
Category: source.GoModTidy,
|
||||
URI: m.URI,
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: source.ModTidyError,
|
||||
Message: fmt.Sprintf("%s is not in your go.mod file", req.Mod.Path),
|
||||
Kind: source.ModTidyError,
|
||||
SuggestedFixes: fixes,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"golang.org/x/tools/internal/event"
|
||||
"golang.org/x/tools/internal/gocommand"
|
||||
"golang.org/x/tools/internal/imports"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
"golang.org/x/tools/internal/memoize"
|
||||
"golang.org/x/tools/internal/span"
|
||||
|
|
@ -543,8 +544,8 @@ func (s *snapshot) initialize(ctx context.Context, firstAttempt bool) {
|
|||
addError := func(uri span.URI, err error) {
|
||||
modDiagnostics = append(modDiagnostics, &source.Diagnostic{
|
||||
URI: uri,
|
||||
Category: "compiler",
|
||||
Kind: source.ListError,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: source.ListError,
|
||||
Message: err.Error(),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ func findDiagnostic(ctx context.Context, snapshot source.Snapshot, pkgID string,
|
|||
if protocol.CompareRange(err.Range, diag.Range) != 0 {
|
||||
continue
|
||||
}
|
||||
if err.Category != analyzer.Analyzer.Name {
|
||||
if string(err.Source) != analyzer.Analyzer.Name {
|
||||
continue
|
||||
}
|
||||
// The error matches.
|
||||
|
|
@ -431,9 +431,9 @@ func convenienceFixes(ctx context.Context, snapshot source.Snapshot, pkg source.
|
|||
func diagnosticToCommandCodeAction(ctx context.Context, snapshot source.Snapshot, sd *source.Diagnostic, pd *protocol.Diagnostic, kind protocol.CodeActionKind) (*protocol.CodeAction, error) {
|
||||
// The fix depends on the category of the analyzer. The diagnostic may be
|
||||
// nil, so use the error's category.
|
||||
analyzer := diagnosticToAnalyzer(snapshot, sd.Category, sd.Message)
|
||||
analyzer := diagnosticToAnalyzer(snapshot, string(sd.Source), sd.Message)
|
||||
if analyzer == nil {
|
||||
return nil, fmt.Errorf("no convenience analyzer for category %s", sd.Category)
|
||||
return nil, fmt.Errorf("no convenience analyzer for source %s", sd.Source)
|
||||
}
|
||||
if analyzer.Command == nil {
|
||||
return nil, fmt.Errorf("no command for convenience analyzer %s", analyzer.Analyzer.Name)
|
||||
|
|
@ -565,7 +565,7 @@ func moduleQuickFixes(ctx context.Context, snapshot source.Snapshot, fh source.V
|
|||
}
|
||||
|
||||
func sameDiagnostic(pd protocol.Diagnostic, sd *source.Diagnostic) bool {
|
||||
return pd.Message == sd.Message && protocol.CompareRange(pd.Range, sd.Range) == 0 && pd.Source == sd.Category
|
||||
return pd.Message == sd.Message && protocol.CompareRange(pd.Range, sd.Range) == 0 && pd.Source == string(sd.Source)
|
||||
}
|
||||
|
||||
func goTest(ctx context.Context, snapshot source.Snapshot, uri span.URI, rng protocol.Range) ([]protocol.CodeAction, error) {
|
||||
|
|
|
|||
|
|
@ -351,7 +351,9 @@ func (s *Server) showCriticalErrorStatus(ctx context.Context, snapshot source.Sn
|
|||
var errMsg string
|
||||
if err != nil {
|
||||
event.Error(ctx, "errors loading workspace", err.MainError, tag.Snapshot.Of(snapshot.ID()), tag.Directory.Of(snapshot.View().Folder()))
|
||||
s.storeErrorDiagnostics(ctx, snapshot, modSource, err.DiagList)
|
||||
for _, d := range err.DiagList {
|
||||
s.storeDiagnostics(snapshot, d.URI, modSource, []*source.Diagnostic{d})
|
||||
}
|
||||
errMsg = strings.Replace(err.MainError.Error(), "\n", " ", -1)
|
||||
}
|
||||
|
||||
|
|
@ -399,28 +401,14 @@ func (s *Server) checkForOrphanedFile(ctx context.Context, snapshot source.Snaps
|
|||
// file and show a more specific error message. For now, put the diagnostic
|
||||
// on the package declaration.
|
||||
return &source.Diagnostic{
|
||||
Range: rng,
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityWarning,
|
||||
Source: source.ListError,
|
||||
Message: fmt.Sprintf(`No packages found for open file %s: %v.
|
||||
If this file contains build tags, try adding "-tags=<build tag>" to your gopls "buildFlag" configuration (see (https://github.com/golang/tools/blob/master/gopls/doc/settings.md#buildflags-string).
|
||||
Otherwise, see the troubleshooting guidelines for help investigating (https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md).
|
||||
`, fh.URI().Filename(), err),
|
||||
Severity: protocol.SeverityWarning,
|
||||
Source: "compiler",
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) storeErrorDiagnostics(ctx context.Context, snapshot source.Snapshot, dsource diagnosticSource, diagnostics []*source.Diagnostic) {
|
||||
for _, d := range diagnostics {
|
||||
diagnostic := &source.Diagnostic{
|
||||
Range: d.Range,
|
||||
Message: d.Message,
|
||||
Related: d.Related,
|
||||
Severity: protocol.SeverityError,
|
||||
Source: d.Category,
|
||||
Code: d.Code,
|
||||
CodeHref: d.CodeHref,
|
||||
}
|
||||
s.storeDiagnostics(snapshot, d.URI, dsource, []*source.Diagnostic{diagnostic})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -523,7 +511,7 @@ func toProtocolDiagnostics(diagnostics []*source.Diagnostic) []protocol.Diagnost
|
|||
Message: strings.TrimSpace(diag.Message),
|
||||
Range: diag.Range,
|
||||
Severity: diag.Severity,
|
||||
Source: diag.Source,
|
||||
Source: string(diag.Source),
|
||||
Tags: diag.Tags,
|
||||
RelatedInformation: related,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1178,19 +1178,10 @@ func (r *runner) collectDiagnostics(view source.View) {
|
|||
// Always run diagnostics with analysis.
|
||||
r.server.diagnose(r.ctx, snapshot, true)
|
||||
for uri, reports := range r.server.diagnostics {
|
||||
var diagnostics []*source.Diagnostic
|
||||
for _, report := range reports.reports {
|
||||
for _, d := range report.diags {
|
||||
diagnostics = append(diagnostics, &source.Diagnostic{
|
||||
Range: d.Range,
|
||||
Message: d.Message,
|
||||
Related: d.Related,
|
||||
Severity: d.Severity,
|
||||
Source: d.Source,
|
||||
Tags: d.Tags,
|
||||
})
|
||||
r.diagnostics[uri] = append(r.diagnostics[uri], d)
|
||||
}
|
||||
r.diagnostics[uri] = diagnostics
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,25 +27,12 @@ func Diagnostics(ctx context.Context, snapshot source.Snapshot) (map[source.Vers
|
|||
return nil, err
|
||||
}
|
||||
reports[fh.VersionedFileIdentity()] = []*source.Diagnostic{}
|
||||
errors, err := DiagnosticsForMod(ctx, snapshot, fh)
|
||||
diagnostics, err := DiagnosticsForMod(ctx, snapshot, fh)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, e := range errors {
|
||||
d := &source.Diagnostic{
|
||||
Message: e.Message,
|
||||
Range: e.Range,
|
||||
Source: e.Category,
|
||||
}
|
||||
switch {
|
||||
case e.Category == "syntax", e.Kind == source.ListError:
|
||||
d.Severity = protocol.SeverityError
|
||||
case e.Kind == source.UpgradeNotification:
|
||||
d.Severity = protocol.SeverityInformation
|
||||
default:
|
||||
d.Severity = protocol.SeverityWarning
|
||||
}
|
||||
fh, err := snapshot.GetVersionedFile(ctx, e.URI)
|
||||
for _, d := range diagnostics {
|
||||
fh, err := snapshot.GetVersionedFile(ctx, d.URI)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -83,10 +70,11 @@ func DiagnosticsForMod(ctx context.Context, snapshot source.Snapshot, fh source.
|
|||
return nil, err
|
||||
}
|
||||
diagnostics = append(diagnostics, &source.Diagnostic{
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Kind: source.UpgradeNotification,
|
||||
Message: fmt.Sprintf("%v can be upgraded", req.Mod.Path),
|
||||
URI: fh.URI(),
|
||||
Range: rng,
|
||||
Severity: protocol.SeverityInformation,
|
||||
Source: source.UpgradeNotification,
|
||||
Message: fmt.Sprintf("%v can be upgraded", req.Mod.Path),
|
||||
SuggestedFixes: []source.SuggestedFix{{
|
||||
Title: fmt.Sprintf("Upgrade to %v", ver),
|
||||
Command: &protocol.Command{
|
||||
|
|
|
|||
|
|
@ -34,22 +34,6 @@ func GetTypeCheckDiagnostics(ctx context.Context, snapshot Snapshot, pkg Package
|
|||
if onlyIgnoredFiles {
|
||||
return TypeCheckDiagnostics{}
|
||||
}
|
||||
|
||||
// Prepare any additional reports for the errors in this package.
|
||||
for _, e := range pkg.GetDiagnostics() {
|
||||
// We only need to handle lower-level errors.
|
||||
if e.Kind != ListError {
|
||||
continue
|
||||
}
|
||||
// If no file is associated with the error, pick an open file from the package.
|
||||
if e.URI.Filename() == "" {
|
||||
for _, pgf := range pkg.CompiledGoFiles() {
|
||||
if snapshot.IsOpen(pgf.URI) {
|
||||
e.URI = pgf.URI
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return typeCheckDiagnostics(ctx, snapshot, pkg)
|
||||
}
|
||||
|
||||
|
|
@ -61,54 +45,60 @@ func Analyze(ctx context.Context, snapshot Snapshot, pkg Package, typeCheckResul
|
|||
}
|
||||
// If we don't have any list or parse errors, run analyses.
|
||||
analyzers := pickAnalyzers(snapshot, typeCheckResult.HasTypeErrors)
|
||||
analysisErrors, err := snapshot.Analyze(ctx, pkg.ID(), analyzers...)
|
||||
analysisDiagnostics, err := snapshot.Analyze(ctx, pkg.ID(), analyzers...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
analysisDiagnostics = cloneDiagnostics(analysisDiagnostics)
|
||||
|
||||
reports := emptyDiagnostics(pkg)
|
||||
// Report diagnostics and errors from root analyzers.
|
||||
for _, e := range analysisErrors {
|
||||
for _, diag := range analysisDiagnostics {
|
||||
// If the diagnostic comes from a "convenience" analyzer, it is not
|
||||
// meant to provide diagnostics, but rather only suggested fixes.
|
||||
// Skip these types of errors in diagnostics; we will use their
|
||||
// suggested fixes when providing code actions.
|
||||
if isConvenienceAnalyzer(e.Category) {
|
||||
if isConvenienceAnalyzer(string(diag.Source)) {
|
||||
continue
|
||||
}
|
||||
// This is a bit of a hack, but clients > 3.15 will be able to grey out unnecessary code.
|
||||
// If we are deleting code as part of all of our suggested fixes, assume that this is dead code.
|
||||
// TODO(golang/go#34508): Return these codes from the diagnostics themselves.
|
||||
var tags []protocol.DiagnosticTag
|
||||
if onlyDeletions(e.SuggestedFixes) {
|
||||
if onlyDeletions(diag.SuggestedFixes) {
|
||||
tags = append(tags, protocol.Unnecessary)
|
||||
}
|
||||
// Type error analyzers only alter the tags for existing type errors.
|
||||
if _, ok := snapshot.View().Options().TypeErrorAnalyzers[e.Category]; ok {
|
||||
existingDiagnostics := typeCheckResult.Diagnostics[e.URI]
|
||||
for _, d := range existingDiagnostics {
|
||||
if r := protocol.CompareRange(e.Range, d.Range); r != 0 {
|
||||
if _, ok := snapshot.View().Options().TypeErrorAnalyzers[string(diag.Source)]; ok {
|
||||
existingDiagnostics := typeCheckResult.Diagnostics[diag.URI]
|
||||
for _, existing := range existingDiagnostics {
|
||||
if r := protocol.CompareRange(diag.Range, existing.Range); r != 0 {
|
||||
continue
|
||||
}
|
||||
if e.Message != d.Message {
|
||||
if diag.Message != existing.Message {
|
||||
continue
|
||||
}
|
||||
d.Tags = append(d.Tags, tags...)
|
||||
existing.Tags = append(existing.Tags, tags...)
|
||||
}
|
||||
} else {
|
||||
reports[e.URI] = append(reports[e.URI], &Diagnostic{
|
||||
Range: e.Range,
|
||||
Message: e.Message,
|
||||
Source: e.Category,
|
||||
Severity: protocol.SeverityWarning,
|
||||
Tags: tags,
|
||||
Related: e.Related,
|
||||
})
|
||||
diag.Tags = append(diag.Tags, tags...)
|
||||
reports[diag.URI] = append(reports[diag.URI], diag)
|
||||
}
|
||||
}
|
||||
return reports, nil
|
||||
}
|
||||
|
||||
// cloneDiagnostics makes a shallow copy of diagnostics so that Analyze
|
||||
// can add tags to them without affecting the cached diagnostics.
|
||||
func cloneDiagnostics(diags []*Diagnostic) []*Diagnostic {
|
||||
result := []*Diagnostic{}
|
||||
for _, d := range diags {
|
||||
clone := *d
|
||||
result = append(result, &clone)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func pickAnalyzers(snapshot Snapshot, hadTypeErrors bool) []*analysis.Analyzer {
|
||||
// Always run convenience analyzers.
|
||||
categories := []map[string]Analyzer{snapshot.View().Options().ConvenienceAnalyzers}
|
||||
|
|
@ -166,28 +156,19 @@ func typeCheckDiagnostics(ctx context.Context, snapshot Snapshot, pkg Package) T
|
|||
defer done()
|
||||
|
||||
diagSets := make(map[span.URI]*diagnosticSet)
|
||||
for _, e := range pkg.GetDiagnostics() {
|
||||
diag := &Diagnostic{
|
||||
Message: e.Message,
|
||||
Range: e.Range,
|
||||
Severity: protocol.SeverityError,
|
||||
Related: e.Related,
|
||||
}
|
||||
set, ok := diagSets[e.URI]
|
||||
for _, diag := range pkg.GetDiagnostics() {
|
||||
set, ok := diagSets[diag.URI]
|
||||
if !ok {
|
||||
set = &diagnosticSet{}
|
||||
diagSets[e.URI] = set
|
||||
diagSets[diag.URI] = set
|
||||
}
|
||||
switch e.Kind {
|
||||
switch diag.Source {
|
||||
case ParseError:
|
||||
set.parseErrors = append(set.parseErrors, diag)
|
||||
diag.Source = "syntax"
|
||||
case TypeError:
|
||||
set.typeErrors = append(set.typeErrors, diag)
|
||||
diag.Source = "compiler"
|
||||
case ListError:
|
||||
set.listErrors = append(set.listErrors, diag)
|
||||
diag.Source = "go list"
|
||||
}
|
||||
}
|
||||
typecheck := TypeCheckDiagnostics{
|
||||
|
|
@ -208,7 +189,7 @@ func typeCheckDiagnostics(ctx context.Context, snapshot Snapshot, pkg Package) T
|
|||
case len(set.typeErrors) > 0:
|
||||
typecheck.HasTypeErrors = true
|
||||
}
|
||||
typecheck.Diagnostics[uri] = diags
|
||||
typecheck.Diagnostics[uri] = cloneDiagnostics(diags)
|
||||
}
|
||||
return typecheck
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,10 +141,11 @@ func parseDetailsFile(filename string, options *Options) (span.URI, []*Diagnosti
|
|||
})
|
||||
}
|
||||
diagnostic := &Diagnostic{
|
||||
URI: uri,
|
||||
Range: zeroIndexedRange(d.Range),
|
||||
Message: msg,
|
||||
Severity: d.Severity,
|
||||
Source: d.Source,
|
||||
Source: OptimizationDetailsError, // d.Source is always "go compiler" as of 1.16, use our own
|
||||
Tags: d.Tags,
|
||||
Related: related,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -571,9 +571,9 @@ type Diagnostic struct {
|
|||
Code string
|
||||
CodeHref string
|
||||
|
||||
Source string
|
||||
Kind ErrorKind
|
||||
Category string // only used by analysis errors so far
|
||||
// Source is a human-readable description of the source of the error.
|
||||
// Diagnostics generated by an analysis.Analyzer set it to Analyzer.Name.
|
||||
Source DiagnosticSource
|
||||
|
||||
Message string
|
||||
|
||||
|
|
@ -585,21 +585,22 @@ type Diagnostic struct {
|
|||
SuggestedFixes []SuggestedFix
|
||||
}
|
||||
|
||||
// GoModTidy is the source for a diagnostic computed by running `go mod tidy`.
|
||||
const GoModTidy = "go mod tidy"
|
||||
|
||||
type ErrorKind int
|
||||
type DiagnosticSource string
|
||||
|
||||
const (
|
||||
UnknownError = ErrorKind(iota)
|
||||
ListError
|
||||
ParseError
|
||||
TypeError
|
||||
ModTidyError
|
||||
Analysis
|
||||
UpgradeNotification
|
||||
UnknownError DiagnosticSource = "<Unknown source>"
|
||||
ListError DiagnosticSource = "go list"
|
||||
ParseError DiagnosticSource = "syntax"
|
||||
TypeError DiagnosticSource = "compiler"
|
||||
ModTidyError DiagnosticSource = "go mod tidy"
|
||||
OptimizationDetailsError DiagnosticSource = "optimizer details"
|
||||
UpgradeNotification DiagnosticSource = "upgrade available"
|
||||
)
|
||||
|
||||
func AnalyzerErrorKind(name string) DiagnosticSource {
|
||||
return DiagnosticSource(name)
|
||||
}
|
||||
|
||||
var (
|
||||
PackagesLoadError = errors.New("packages.Load error")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1004,7 +1004,7 @@ func (data *Data) collectDiagnostics(spn span.Span, msgSource, msg, msgSeverity
|
|||
want := &source.Diagnostic{
|
||||
Range: rng,
|
||||
Severity: severity,
|
||||
Source: msgSource,
|
||||
Source: source.DiagnosticSource(msgSource),
|
||||
Message: msg,
|
||||
}
|
||||
data.Diagnostics[spn.URI()] = append(data.Diagnostics[spn.URI()], want)
|
||||
|
|
|
|||
Loading…
Reference in New Issue