mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
internal/lsp: add a test to make sure we handle bad imports
There was a regression where gopls would not type-check any package with a bad import. This change fixes the regression and adds a test to make sure it doesn't happen again. Change-Id: I3acf0917d46e9444c20135559f057f0ecd20e15b Reviewed-on: https://go-review.googlesource.com/c/tools/+/201539 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Michael Matloob <matloob@golang.org> Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
parent
e4d7c6f25b
commit
de666e9706
@ -20,7 +20,7 @@ func TestMarker(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
const expectNotes = 12
|
||||
const expectNotes = 13
|
||||
expectMarkers := map[string]string{
|
||||
"αSimpleMarker": "α",
|
||||
"OffsetMarker": "β",
|
||||
@ -32,6 +32,7 @@ func TestMarker(t *testing.T) {
|
||||
"Comment": "ι",
|
||||
"LineComment": "someFunc",
|
||||
"NonIdentifier": "+",
|
||||
"StringMarker": "\"hello\"",
|
||||
}
|
||||
expectChecks := map[string][]interface{}{
|
||||
"αSimpleMarker": nil,
|
||||
@ -44,7 +45,7 @@ func TestMarker(t *testing.T) {
|
||||
for name, tok := range expectMarkers {
|
||||
offset := bytes.Index(content, []byte(tok))
|
||||
markers[name] = token.Pos(offset + 1)
|
||||
end := bytes.Index(content[offset+1:], []byte(tok))
|
||||
end := bytes.Index(content[offset:], []byte(tok))
|
||||
if end > 0 {
|
||||
markers[name+"@"] = token.Pos(offset + end + 2)
|
||||
}
|
||||
@ -130,10 +131,6 @@ func checkMarker(t *testing.T, fset *token.FileSet, readFile expect.ReadFile, ma
|
||||
if start != expectStart {
|
||||
t.Errorf("%v: Expected %v got %v", fset.Position(pos), fset.Position(expectStart), fset.Position(start))
|
||||
}
|
||||
// Don't check the end for the LineComment test.
|
||||
if name == "LineComment" {
|
||||
return
|
||||
}
|
||||
if expectEnd, ok := markers[name+"@"]; ok && end != expectEnd {
|
||||
t.Errorf("%v: Expected end %v got %v", fset.Position(pos), fset.Position(expectEnd), fset.Position(end))
|
||||
}
|
||||
|
1
go/expect/testdata/test.go
vendored
1
go/expect/testdata/test.go
vendored
@ -19,6 +19,7 @@ const (
|
||||
)
|
||||
|
||||
/*Marker ι inside ι a comment*/ //@mark(Comment,"ι inside ")
|
||||
var x = "hello" //@mark(StringMarker, `"hello"`)
|
||||
|
||||
// someFunc is a function. //@mark(LineComment, "someFunc")
|
||||
func someFunc(a, b int) int {
|
||||
|
@ -1057,6 +1057,10 @@ func invokeGo(cfg *Config, args ...string) (*bytes.Buffer, error) {
|
||||
// status if there's a dependency on a package that doesn't exist. But it should return
|
||||
// a zero exit status and set an error on that package.
|
||||
if len(stderr.String()) > 0 && strings.Contains(stderr.String(), "no Go files in") {
|
||||
// Don't clobber stdout if `go list` actually returned something.
|
||||
if len(stdout.String()) > 0 {
|
||||
return stdout, nil
|
||||
}
|
||||
// try to extract package name from string
|
||||
stderrStr := stderr.String()
|
||||
var importPath string
|
||||
|
6
internal/lsp/cache/analysis.go
vendored
6
internal/lsp/cache/analysis.go
vendored
@ -133,10 +133,10 @@ func (s *snapshot) actionHandle(ctx context.Context, id packageID, mode source.P
|
||||
return ah, nil
|
||||
}
|
||||
|
||||
func (ah *actionHandle) analyze(ctx context.Context) ([]*analysis.Diagnostic, interface{}, error) {
|
||||
v := ah.handle.Get(ctx)
|
||||
func (act *actionHandle) analyze(ctx context.Context) ([]*analysis.Diagnostic, interface{}, error) {
|
||||
v := act.handle.Get(ctx)
|
||||
if v == nil {
|
||||
return nil, nil, errors.Errorf("no analyses for %s", ah.pkg.ID())
|
||||
return nil, nil, errors.Errorf("no analyses for %s", act.pkg.ID())
|
||||
}
|
||||
data := v.(*actionData)
|
||||
return data.diagnostics, data.result, data.err
|
||||
|
9
internal/lsp/cache/check.go
vendored
9
internal/lsp/cache/check.go
vendored
@ -18,6 +18,7 @@ import (
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
"golang.org/x/tools/internal/lsp/telemetry"
|
||||
"golang.org/x/tools/internal/memoize"
|
||||
"golang.org/x/tools/internal/telemetry/log"
|
||||
"golang.org/x/tools/internal/telemetry/trace"
|
||||
errors "golang.org/x/xerrors"
|
||||
)
|
||||
@ -107,7 +108,6 @@ func (imp *importer) buildKey(ctx context.Context, id packageID, mode source.Par
|
||||
if m == nil {
|
||||
return nil, errors.Errorf("no metadata for %s", id)
|
||||
}
|
||||
|
||||
phs, err := imp.parseGoHandles(ctx, m, mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -135,7 +135,12 @@ func (imp *importer) buildKey(ctx context.Context, id packageID, mode source.Par
|
||||
for _, dep := range deps {
|
||||
depHandle, err := depImporter.checkPackageHandle(ctx, dep)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("no dep handle for %s: %+v", dep, err)
|
||||
log.Error(ctx, "no dep handle", err, telemetry.Package.Of(dep))
|
||||
|
||||
// One bad dependency should not prevent us from checking the entire package.
|
||||
// Add a special key to mark a bad dependency.
|
||||
depKeys = append(depKeys, []byte(fmt.Sprintf("%s import not found", id)))
|
||||
continue
|
||||
}
|
||||
cph.imports[depHandle.m.pkgPath] = depHandle.m.id
|
||||
depKeys = append(depKeys, depHandle.key)
|
||||
|
@ -55,6 +55,10 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnosti
|
||||
if diag.Range.Start.Character == 0 {
|
||||
expect = fmt.Sprintf("%v:%v: %v", diag.URI.Filename(), diag.Range.Start.Line+1, diag.Message)
|
||||
}
|
||||
// Skip the badimport test for now, until we do a better job with diagnostic ranges.
|
||||
if strings.Contains(diag.URI.Filename(), "badimport") {
|
||||
continue
|
||||
}
|
||||
_, found := got[expect]
|
||||
if !found {
|
||||
t.Errorf("missing diagnostic %q", expect)
|
||||
@ -63,6 +67,10 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnosti
|
||||
}
|
||||
}
|
||||
for extra := range got {
|
||||
// Skip the badimport test for now, until we do a better job with diagnostic ranges.
|
||||
if strings.Contains(extra, "badimport") {
|
||||
continue
|
||||
}
|
||||
t.Errorf("extra diagnostic %q", extra)
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnosti
|
||||
}
|
||||
return
|
||||
}
|
||||
if diff := tests.DiffDiagnostics(uri, want, got); diff != "" {
|
||||
if diff := tests.DiffDiagnostics(want, got); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []source.Diagnosti
|
||||
}
|
||||
return
|
||||
}
|
||||
if diff := tests.DiffDiagnostics(uri, want, got); diff != "" {
|
||||
if diff := tests.DiffDiagnostics(want, got); diff != "" {
|
||||
t.Error(diff)
|
||||
}
|
||||
}
|
||||
|
5
internal/lsp/testdata/bad/badimport.go
vendored
Normal file
5
internal/lsp/testdata/bad/badimport.go
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
package bad
|
||||
|
||||
import (
|
||||
_ "nosuchpkg" //@diag("_", "LSP", "could not import nosuchpkg (no package data for import path nosuchpkg)")
|
||||
)
|
2
internal/lsp/testdata/summary.txt.golden
vendored
2
internal/lsp/testdata/summary.txt.golden
vendored
@ -6,7 +6,7 @@ DeepCompletionsCount = 5
|
||||
FuzzyCompletionsCount = 7
|
||||
RankedCompletionsCount = 1
|
||||
CaseSensitiveCompletionsCount = 4
|
||||
DiagnosticsCount = 21
|
||||
DiagnosticsCount = 22
|
||||
FoldingRangesCount = 2
|
||||
FormatCount = 6
|
||||
ImportCount = 2
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
|
||||
// DiffDiagnostics prints the diff between expected and actual diagnostics test
|
||||
// results.
|
||||
func DiffDiagnostics(uri span.URI, want, got []source.Diagnostic) string {
|
||||
func DiffDiagnostics(want, got []source.Diagnostic) string {
|
||||
sortDiagnostics(want)
|
||||
sortDiagnostics(got)
|
||||
|
||||
@ -25,11 +25,21 @@ func DiffDiagnostics(uri span.URI, want, got []source.Diagnostic) string {
|
||||
if w.Message != g.Message {
|
||||
return summarizeDiagnostics(i, want, got, "incorrect Message got %v want %v", g.Message, w.Message)
|
||||
}
|
||||
if w.Severity != g.Severity {
|
||||
return summarizeDiagnostics(i, want, got, "incorrect Severity got %v want %v", g.Severity, w.Severity)
|
||||
}
|
||||
if w.Source != g.Source {
|
||||
return summarizeDiagnostics(i, want, got, "incorrect Source got %v want %v", g.Source, w.Source)
|
||||
}
|
||||
// Don't check the range on the badimport test.
|
||||
if strings.Contains(string(g.URI), "badimport") {
|
||||
continue
|
||||
}
|
||||
if protocol.ComparePosition(w.Range.Start, g.Range.Start) != 0 {
|
||||
return summarizeDiagnostics(i, want, got, "incorrect Start got %v want %v", g.Range.Start, w.Range.Start)
|
||||
}
|
||||
// Special case for diagnostics on parse errors.
|
||||
if strings.Contains(string(uri), "noparse") {
|
||||
if strings.Contains(string(g.URI), "noparse") {
|
||||
if protocol.ComparePosition(g.Range.Start, g.Range.End) != 0 || protocol.ComparePosition(w.Range.Start, g.Range.End) != 0 {
|
||||
return summarizeDiagnostics(i, want, got, "incorrect End got %v want %v", g.Range.End, w.Range.Start)
|
||||
}
|
||||
@ -38,12 +48,6 @@ func DiffDiagnostics(uri span.URI, want, got []source.Diagnostic) string {
|
||||
return summarizeDiagnostics(i, want, got, "incorrect End got %v want %v", g.Range.End, w.Range.End)
|
||||
}
|
||||
}
|
||||
if w.Severity != g.Severity {
|
||||
return summarizeDiagnostics(i, want, got, "incorrect Severity got %v want %v", g.Severity, w.Severity)
|
||||
}
|
||||
if w.Source != g.Source {
|
||||
return summarizeDiagnostics(i, want, got, "incorrect Source got %v want %v", g.Source, w.Source)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
@ -257,12 +257,12 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
||||
filename := data.Exported.File(testModule, fragment)
|
||||
data.fragments[filename] = fragment
|
||||
}
|
||||
data.Exported.Config.Logf = nil
|
||||
data.Exported.Config.Logf = t.Logf
|
||||
data.Config.Logf = t.Logf
|
||||
|
||||
// Merge the exported.Config with the view.Config.
|
||||
data.Config = *data.Exported.Config
|
||||
data.Config.Fset = token.NewFileSet()
|
||||
data.Config.Logf = nil
|
||||
data.Config.Context = Context(nil)
|
||||
data.Config.ParseFile = func(fset *token.FileSet, filename string, src []byte) (*ast.File, error) {
|
||||
panic("ParseFile should not be called")
|
||||
|
Loading…
x
Reference in New Issue
Block a user