aboutsummaryrefslogtreecommitdiff
path: root/internal/lsp/cache/errors.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/lsp/cache/errors.go')
-rw-r--r--internal/lsp/cache/errors.go411
1 files changed, 0 insertions, 411 deletions
diff --git a/internal/lsp/cache/errors.go b/internal/lsp/cache/errors.go
deleted file mode 100644
index e9a86de35..000000000
--- a/internal/lsp/cache/errors.go
+++ /dev/null
@@ -1,411 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package cache
-
-import (
- "fmt"
- "go/scanner"
- "go/token"
- "go/types"
- "regexp"
- "strconv"
- "strings"
-
- "golang.org/x/tools/go/analysis"
- "golang.org/x/tools/go/packages"
- "golang.org/x/tools/internal/analysisinternal"
- "golang.org/x/tools/internal/lsp/command"
- "golang.org/x/tools/internal/lsp/protocol"
- "golang.org/x/tools/internal/lsp/source"
- "golang.org/x/tools/internal/span"
- "golang.org/x/tools/internal/typesinternal"
- errors "golang.org/x/xerrors"
-)
-
-func goPackagesErrorDiagnostics(snapshot *snapshot, pkg *pkg, e packages.Error) ([]*source.Diagnostic, error) {
- if msg, spn, ok := parseGoListImportCycleError(snapshot, e, pkg); ok {
- rng, err := spanToRange(pkg, spn)
- if err != nil {
- return nil, err
- }
- return []*source.Diagnostic{{
- URI: spn.URI(),
- Range: rng,
- Severity: protocol.SeverityError,
- Source: source.ListError,
- Message: msg,
- }}, nil
- }
-
- var spn span.Span
- if e.Pos == "" {
- spn = parseGoListError(e.Msg, pkg.m.Config.Dir)
- // We may not have been able to parse a valid span. Apply the errors to all files.
- if _, err := spanToRange(pkg, spn); err != nil {
- var diags []*source.Diagnostic
- for _, cgf := range pkg.compiledGoFiles {
- diags = append(diags, &source.Diagnostic{
- URI: cgf.URI,
- Severity: protocol.SeverityError,
- Source: source.ListError,
- Message: e.Msg,
- })
- }
- return diags, nil
- }
- } else {
- spn = span.ParseInDir(e.Pos, pkg.m.Config.Dir)
- }
-
- rng, err := spanToRange(pkg, spn)
- if err != nil {
- return nil, err
- }
- return []*source.Diagnostic{{
- URI: spn.URI(),
- Range: rng,
- Severity: protocol.SeverityError,
- Source: source.ListError,
- Message: e.Msg,
- }}, nil
-}
-
-func parseErrorDiagnostics(snapshot *snapshot, pkg *pkg, errList scanner.ErrorList) ([]*source.Diagnostic, error) {
- // The first parser error is likely the root cause of the problem.
- if errList.Len() <= 0 {
- return nil, errors.Errorf("no errors in %v", errList)
- }
- e := errList[0]
- pgf, err := pkg.File(span.URIFromPath(e.Pos.Filename))
- if err != nil {
- return nil, err
- }
- pos := pgf.Tok.Pos(e.Pos.Offset)
- spn, err := span.NewRange(snapshot.FileSet(), pos, pos).Span()
- if err != nil {
- return nil, err
- }
- rng, err := spanToRange(pkg, spn)
- if err != nil {
- return nil, err
- }
- return []*source.Diagnostic{{
- URI: spn.URI(),
- Range: rng,
- Severity: protocol.SeverityError,
- Source: source.ParseError,
- Message: e.Msg,
- }}, nil
-}
-
-var importErrorRe = regexp.MustCompile(`could not import ([^\s]+)`)
-var unsupportedFeatureRe = regexp.MustCompile(`.*require.* go(\d+\.\d+) or later`)
-
-func typeErrorDiagnostics(snapshot *snapshot, pkg *pkg, e extendedError) ([]*source.Diagnostic, error) {
- code, spn, err := typeErrorData(snapshot.FileSet(), pkg, e.primary)
- if err != nil {
- return nil, err
- }
- rng, err := spanToRange(pkg, spn)
- if err != nil {
- return nil, err
- }
- diag := &source.Diagnostic{
- URI: spn.URI(),
- Range: rng,
- Severity: protocol.SeverityError,
- Source: source.TypeError,
- Message: e.primary.Msg,
- }
- if code != 0 {
- diag.Code = code.String()
- diag.CodeHref = typesCodeHref(snapshot, code)
- }
-
- for _, secondary := range e.secondaries {
- _, secondarySpan, err := typeErrorData(snapshot.FileSet(), pkg, secondary)
- if err != nil {
- return nil, err
- }
- rng, err := spanToRange(pkg, secondarySpan)
- if err != nil {
- return nil, err
- }
- diag.Related = append(diag.Related, source.RelatedInformation{
- URI: secondarySpan.URI(),
- Range: rng,
- Message: secondary.Msg,
- })
- }
-
- if match := importErrorRe.FindStringSubmatch(e.primary.Msg); match != nil {
- diag.SuggestedFixes, err = goGetQuickFixes(snapshot, spn.URI(), match[1])
- if err != nil {
- return nil, err
- }
- }
- if match := unsupportedFeatureRe.FindStringSubmatch(e.primary.Msg); match != nil {
- diag.SuggestedFixes, err = editGoDirectiveQuickFix(snapshot, spn.URI(), match[1])
- if err != nil {
- return nil, err
- }
- }
- return []*source.Diagnostic{diag}, nil
-}
-
-func goGetQuickFixes(snapshot *snapshot, uri span.URI, pkg string) ([]source.SuggestedFix, error) {
- // Go get only supports module mode for now.
- if snapshot.workspaceMode()&moduleMode == 0 {
- return nil, nil
- }
- title := fmt.Sprintf("go get package %v", pkg)
- cmd, err := command.NewGoGetPackageCommand(title, command.GoGetPackageArgs{
- URI: protocol.URIFromSpanURI(uri),
- AddRequire: true,
- Pkg: pkg,
- })
- if err != nil {
- return nil, err
- }
- return []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, nil
-}
-
-func editGoDirectiveQuickFix(snapshot *snapshot, uri span.URI, version string) ([]source.SuggestedFix, error) {
- // Go mod edit only supports module mode.
- if snapshot.workspaceMode()&moduleMode == 0 {
- return nil, nil
- }
- title := fmt.Sprintf("go mod edit -go=%s", version)
- cmd, err := command.NewEditGoDirectiveCommand(title, command.EditGoDirectiveArgs{
- URI: protocol.URIFromSpanURI(uri),
- Version: version,
- })
- if err != nil {
- return nil, err
- }
- return []source.SuggestedFix{source.SuggestedFixFromCommand(cmd, protocol.QuickFix)}, nil
-}
-
-func analysisDiagnosticDiagnostics(snapshot *snapshot, pkg *pkg, a *analysis.Analyzer, e *analysis.Diagnostic) ([]*source.Diagnostic, error) {
- var srcAnalyzer *source.Analyzer
- // Find the analyzer that generated this diagnostic.
- for _, sa := range source.EnabledAnalyzers(snapshot) {
- if a == sa.Analyzer {
- srcAnalyzer = sa
- break
- }
- }
-
- spn, err := span.NewRange(snapshot.FileSet(), e.Pos, e.End).Span()
- if err != nil {
- return nil, err
- }
- rng, err := spanToRange(pkg, spn)
- if err != nil {
- return nil, err
- }
- kinds := srcAnalyzer.ActionKind
- if len(srcAnalyzer.ActionKind) == 0 {
- kinds = append(kinds, protocol.QuickFix)
- }
- fixes, err := suggestedAnalysisFixes(snapshot, pkg, e, kinds)
- if err != nil {
- return nil, err
- }
- if srcAnalyzer.Fix != "" {
- cmd, err := command.NewApplyFixCommand(e.Message, command.ApplyFixArgs{
- URI: protocol.URIFromSpanURI(spn.URI()),
- Range: rng,
- Fix: srcAnalyzer.Fix,
- })
- if err != nil {
- return nil, err
- }
- for _, kind := range kinds {
- fixes = append(fixes, source.SuggestedFixFromCommand(cmd, kind))
- }
- }
- related, err := relatedInformation(pkg, snapshot.FileSet(), e)
- if err != nil {
- return nil, err
- }
-
- severity := srcAnalyzer.Severity
- if severity == 0 {
- severity = protocol.SeverityWarning
- }
- diag := &source.Diagnostic{
- URI: spn.URI(),
- Range: rng,
- Severity: severity,
- Source: source.AnalyzerErrorKind(e.Category),
- Message: e.Message,
- Related: related,
- SuggestedFixes: fixes,
- Analyzer: srcAnalyzer,
- }
- // If the fixes only delete code, assume that the diagnostic is reporting dead code.
- if onlyDeletions(fixes) {
- diag.Tags = []protocol.DiagnosticTag{protocol.Unnecessary}
- }
- return []*source.Diagnostic{diag}, nil
-}
-
-// onlyDeletions returns true if all of the suggested fixes are deletions.
-func onlyDeletions(fixes []source.SuggestedFix) bool {
- for _, fix := range fixes {
- if fix.Command != nil {
- return false
- }
- for _, edits := range fix.Edits {
- for _, edit := range edits {
- if edit.NewText != "" {
- return false
- }
- if protocol.ComparePosition(edit.Range.Start, edit.Range.End) == 0 {
- return false
- }
- }
- }
- }
- return len(fixes) > 0
-}
-
-func typesCodeHref(snapshot *snapshot, code typesinternal.ErrorCode) string {
- target := snapshot.View().Options().LinkTarget
- return source.BuildLink(target, "golang.org/x/tools/internal/typesinternal", code.String())
-}
-
-func suggestedAnalysisFixes(snapshot *snapshot, pkg *pkg, diag *analysis.Diagnostic, kinds []protocol.CodeActionKind) ([]source.SuggestedFix, error) {
- var fixes []source.SuggestedFix
- for _, fix := range diag.SuggestedFixes {
- edits := make(map[span.URI][]protocol.TextEdit)
- for _, e := range fix.TextEdits {
- spn, err := span.NewRange(snapshot.FileSet(), e.Pos, e.End).Span()
- if err != nil {
- return nil, err
- }
- rng, err := spanToRange(pkg, spn)
- if err != nil {
- return nil, err
- }
- edits[spn.URI()] = append(edits[spn.URI()], protocol.TextEdit{
- Range: rng,
- NewText: string(e.NewText),
- })
- }
- for _, kind := range kinds {
- fixes = append(fixes, source.SuggestedFix{
- Title: fix.Message,
- Edits: edits,
- ActionKind: kind,
- })
- }
-
- }
- return fixes, nil
-}
-
-func relatedInformation(pkg *pkg, fset *token.FileSet, diag *analysis.Diagnostic) ([]source.RelatedInformation, error) {
- var out []source.RelatedInformation
- for _, related := range diag.Related {
- spn, err := span.NewRange(fset, related.Pos, related.End).Span()
- if err != nil {
- return nil, err
- }
- rng, err := spanToRange(pkg, spn)
- if err != nil {
- return nil, err
- }
- out = append(out, source.RelatedInformation{
- URI: spn.URI(),
- Range: rng,
- Message: related.Message,
- })
- }
- return out, nil
-}
-
-func typeErrorData(fset *token.FileSet, pkg *pkg, terr types.Error) (typesinternal.ErrorCode, span.Span, error) {
- ecode, start, end, ok := typesinternal.ReadGo116ErrorData(terr)
- if !ok {
- start, end = terr.Pos, terr.Pos
- ecode = 0
- }
- posn := fset.Position(start)
- pgf, err := pkg.File(span.URIFromPath(posn.Filename))
- if err != nil {
- return 0, span.Span{}, err
- }
- if !end.IsValid() || end == start {
- end = analysisinternal.TypeErrorEndPos(fset, pgf.Src, start)
- }
- spn, err := parsedGoSpan(pgf, start, end)
- if err != nil {
- return 0, span.Span{}, err
- }
- return ecode, spn, nil
-}
-
-func parsedGoSpan(pgf *source.ParsedGoFile, start, end token.Pos) (span.Span, error) {
- return span.FileSpan(pgf.Tok, pgf.Mapper.Converter, start, end)
-}
-
-// 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) {
- pgf, err := pkg.File(spn.URI())
- if err != nil {
- return protocol.Range{}, err
- }
- return pgf.Mapper.Range(spn)
-}
-
-// parseGoListError attempts to parse a standard `go list` error message
-// by stripping off the trailing error message.
-//
-// It works only on errors whose message is prefixed by colon,
-// followed by a space (": "). For example:
-//
-// attributes.go:13:1: expected 'package', found 'type'
-//
-func parseGoListError(input, wd string) span.Span {
- input = strings.TrimSpace(input)
- msgIndex := strings.Index(input, ": ")
- if msgIndex < 0 {
- return span.Parse(input)
- }
- return span.ParseInDir(input[:msgIndex], wd)
-}
-
-func parseGoListImportCycleError(snapshot *snapshot, e packages.Error, pkg *pkg) (string, span.Span, bool) {
- re := regexp.MustCompile(`(.*): import stack: \[(.+)\]`)
- matches := re.FindStringSubmatch(strings.TrimSpace(e.Msg))
- if len(matches) < 3 {
- return e.Msg, span.Span{}, false
- }
- msg := matches[1]
- importList := strings.Split(matches[2], " ")
- // Since the error is relative to the current package. The import that is causing
- // the import cycle error is the second one in the list.
- if len(importList) < 2 {
- return msg, span.Span{}, false
- }
- // Imports have quotation marks around them.
- circImp := strconv.Quote(importList[1])
- for _, cgf := range pkg.compiledGoFiles {
- // Search file imports for the import that is causing the import cycle.
- for _, imp := range cgf.File.Imports {
- if imp.Path.Value == circImp {
- spn, err := span.NewRange(snapshot.FileSet(), imp.Pos(), imp.End()).Span()
- if err != nil {
- return msg, span.Span{}, false
- }
- return msg, spn, true
- }
- }
- }
- return msg, span.Span{}, false
-}