Skip to content

Commit 7ee2955

Browse files
committed
internal/lsp/cache: refactor and improve go get quick fixes
Generating go get quick fixes in a single place only made it harder to get them right. Do it during diagnostics generation, as is the new norm. Also improve the user experience. When we fail to import a package because one of its dependencies is missing, it makes more sense to run go get on the package we tried to import, not the one that's missing: that will download all of its missing dependencies if there happen to be more. Change-Id: Ib6a8140bccfafcb9f966d25639799dd4c7347c3d Reviewed-on: https://go-review.googlesource.com/c/tools/+/300072 Trust: Heschi Kreinick <[email protected]> Run-TryBot: Heschi Kreinick <[email protected]> Reviewed-by: Rebecca Stambler <[email protected]> gopls-CI: kokoro <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 1e524e2 commit 7ee2955

File tree

2 files changed

+51
-50
lines changed

2 files changed

+51
-50
lines changed

internal/lsp/cache/check.go

Lines changed: 25 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"go/types"
1414
"path"
1515
"path/filepath"
16-
"regexp"
1716
"sort"
1817
"strings"
1918
"sync"
@@ -22,7 +21,6 @@ import (
2221
"golang.org/x/tools/go/ast/astutil"
2322
"golang.org/x/tools/go/packages"
2423
"golang.org/x/tools/internal/event"
25-
"golang.org/x/tools/internal/lsp/command"
2624
"golang.org/x/tools/internal/lsp/debug/tag"
2725
"golang.org/x/tools/internal/lsp/protocol"
2826
"golang.org/x/tools/internal/lsp/source"
@@ -509,44 +507,10 @@ func typeCheck(ctx context.Context, snapshot *snapshot, m *metadata, mode source
509507
return nil, err
510508
}
511509
pkg.diagnostics = append(pkg.diagnostics, depsErrors...)
512-
if err := addGoGetFixes(ctx, snapshot, pkg); err != nil {
513-
return nil, err
514-
}
515510

516511
return pkg, nil
517512
}
518513

519-
var importErrorRe = regexp.MustCompile(`could not import ([^\s]+)`)
520-
var missingModuleErrorRe = regexp.MustCompile(`cannot find module providing package ([^\s:]+)`)
521-
522-
func addGoGetFixes(ctx context.Context, snapshot source.Snapshot, pkg *pkg) error {
523-
if len(pkg.compiledGoFiles) == 0 || snapshot.GoModForFile(pkg.compiledGoFiles[0].URI) == "" {
524-
// Go get only supports module mode for now.
525-
return nil
526-
}
527-
for _, diag := range pkg.diagnostics {
528-
matches := importErrorRe.FindStringSubmatch(diag.Message)
529-
if len(matches) == 0 {
530-
matches = missingModuleErrorRe.FindStringSubmatch(diag.Message)
531-
}
532-
if len(matches) == 0 {
533-
continue
534-
}
535-
direct := !strings.Contains(diag.Message, "error while importing")
536-
title := fmt.Sprintf("go get package %v", matches[1])
537-
cmd, err := command.NewGoGetPackageCommand(title, command.GoGetPackageArgs{
538-
URI: protocol.URIFromSpanURI(pkg.compiledGoFiles[0].URI),
539-
AddRequire: direct,
540-
Pkg: matches[1],
541-
})
542-
if err != nil {
543-
return err
544-
}
545-
diag.SuggestedFixes = append(diag.SuggestedFixes, source.SuggestedFixFromCommand(cmd))
546-
}
547-
return nil
548-
}
549-
550514
func (s *snapshot) depsErrors(ctx context.Context, pkg *pkg) ([]*source.Diagnostic, error) {
551515
// Select packages that can't be found, and were imported in non-workspace packages.
552516
// Workspace packages already show their own errors.
@@ -592,28 +556,34 @@ func (s *snapshot) depsErrors(ctx context.Context, pkg *pkg) ([]*source.Diagnost
592556
}
593557
}
594558

595-
// Apply a diagnostic to any import involved in the error, stopping after
559+
// Apply a diagnostic to any import involved in the error, stopping once
596560
// we reach the workspace.
597561
var errors []*source.Diagnostic
598562
for _, depErr := range relevantErrors {
599563
for i := len(depErr.ImportStack) - 1; i >= 0; i-- {
600564
item := depErr.ImportStack[i]
565+
if _, ok := s.isWorkspacePackage(packageID(item)); ok {
566+
break
567+
}
568+
601569
for _, imp := range allImports[item] {
602570
rng, err := source.NewMappedRange(s.FileSet(), imp.cgf.Mapper, imp.imp.Pos(), imp.imp.End()).Range()
603571
if err != nil {
604572
return nil, err
605573
}
574+
fixes, err := goGetQuickFixes(s, imp.cgf.URI, item)
575+
if err != nil {
576+
return nil, err
577+
}
606578
errors = append(errors, &source.Diagnostic{
607-
URI: imp.cgf.URI,
608-
Range: rng,
609-
Severity: protocol.SeverityError,
610-
Source: source.TypeError,
611-
Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
579+
URI: imp.cgf.URI,
580+
Range: rng,
581+
Severity: protocol.SeverityError,
582+
Source: source.TypeError,
583+
Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
584+
SuggestedFixes: fixes,
612585
})
613586
}
614-
if _, ok := s.isWorkspacePackage(packageID(item)); ok {
615-
break
616-
}
617587
}
618588
}
619589

@@ -651,12 +621,17 @@ func (s *snapshot) depsErrors(ctx context.Context, pkg *pkg) ([]*source.Diagnost
651621
if err != nil {
652622
return nil, err
653623
}
624+
fixes, err := goGetQuickFixes(s, pm.URI, item)
625+
if err != nil {
626+
return nil, err
627+
}
654628
errors = append(errors, &source.Diagnostic{
655-
URI: pm.URI,
656-
Range: rng,
657-
Severity: protocol.SeverityError,
658-
Source: source.TypeError,
659-
Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
629+
URI: pm.URI,
630+
Range: rng,
631+
Severity: protocol.SeverityError,
632+
Source: source.TypeError,
633+
Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
634+
SuggestedFixes: fixes,
660635
})
661636
break
662637
}

internal/lsp/cache/errors.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ func parseErrorDiagnostics(ctx context.Context, snapshot *snapshot, pkg *pkg, er
101101
}}, nil
102102
}
103103

104+
var importErrorRe = regexp.MustCompile(`could not import ([^\s]+)`)
105+
104106
func typeErrorDiagnostics(ctx context.Context, snapshot *snapshot, pkg *pkg, e extendedError) ([]*source.Diagnostic, error) {
105107
code, spn, err := typeErrorData(snapshot.FileSet(), pkg, e.primary)
106108
if err != nil {
@@ -137,9 +139,33 @@ func typeErrorDiagnostics(ctx context.Context, snapshot *snapshot, pkg *pkg, e e
137139
Message: secondary.Msg,
138140
})
139141
}
142+
143+
if match := importErrorRe.FindStringSubmatch(e.primary.Msg); match != nil {
144+
diag.SuggestedFixes, err = goGetQuickFixes(snapshot, spn.URI(), match[1])
145+
if err != nil {
146+
return nil, err
147+
}
148+
}
140149
return []*source.Diagnostic{diag}, nil
141150
}
142151

152+
func goGetQuickFixes(snapshot *snapshot, uri span.URI, pkg string) ([]source.SuggestedFix, error) {
153+
// Go get only supports module mode for now.
154+
if snapshot.workspaceMode()&moduleMode == 0 {
155+
return nil, nil
156+
}
157+
title := fmt.Sprintf("go get package %v", pkg)
158+
cmd, err := command.NewGoGetPackageCommand(title, command.GoGetPackageArgs{
159+
URI: protocol.URIFromSpanURI(uri),
160+
AddRequire: true,
161+
Pkg: pkg,
162+
})
163+
if err != nil {
164+
return nil, err
165+
}
166+
return []source.SuggestedFix{source.SuggestedFixFromCommand(cmd)}, nil
167+
}
168+
143169
func analysisDiagnosticDiagnostics(ctx context.Context, snapshot *snapshot, pkg *pkg, a *analysis.Analyzer, e *analysis.Diagnostic) ([]*source.Diagnostic, error) {
144170
var srcAnalyzer *source.Analyzer
145171
// Find the analyzer that generated this diagnostic.

0 commit comments

Comments
 (0)