From 10e9d3cefa8752e7ddbc2b6316539e6b578a306b Mon Sep 17 00:00:00 2001 From: Robert Findley Date: Tue, 27 Sep 2022 13:04:59 -0400 Subject: [PATCH] gopls/internal/lsp: tolerate new 'imported and not used' error message Tolerate the new form of the "... imported but not used" error message, to allow landing this change in go/types. Along the way, improve the test output when comparing diagnostics, and formatting results. For golang/go#54845 Change-Id: I998d539f82e0f70c85bdb4c40858be5e01dd08b6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/435355 gopls-CI: kokoro TryBot-Result: Gopher Robot Run-TryBot: Robert Findley Reviewed-by: Alan Donovan Reviewed-by: Robert Griesemer Auto-Submit: Robert Findley --- .../lsp/analysis/undeclaredname/undeclared.go | 1 + .../unusedvariable/testdata/src/assign/a.go | 34 +++---- .../testdata/src/assign/a.go.golden | 20 ++-- .../unusedvariable/testdata/src/decl/a.go | 8 +- .../testdata/src/decl/a.go.golden | 2 +- .../analysis/unusedvariable/unusedvariable.go | 15 +-- gopls/internal/lsp/cmd/test/check.go | 4 +- gopls/internal/lsp/lsp_test.go | 8 +- gopls/internal/lsp/source/source_test.go | 4 +- gopls/internal/lsp/testdata/bad/bad0.go | 2 +- gopls/internal/lsp/testdata/bad/bad1.go | 16 ++-- .../lsp/testdata/format/bad_format.go.golden | 2 +- .../lsp/testdata/format/bad_format.go.in | 2 +- .../lsp/testdata/generated/generated.go | 2 +- .../lsp/testdata/generated/generator.go | 2 +- .../internal/lsp/testdata/testy/testy_test.go | 2 +- gopls/internal/lsp/tests/util.go | 93 ++++++++++--------- .../regtest/workspace/workspace_test.go | 2 +- 18 files changed, 113 insertions(+), 106 deletions(-) diff --git a/gopls/internal/lsp/analysis/undeclaredname/undeclared.go b/gopls/internal/lsp/analysis/undeclaredname/undeclared.go index c06ae3538c..eaecc8f0e1 100644 --- a/gopls/internal/lsp/analysis/undeclaredname/undeclared.go +++ b/gopls/internal/lsp/analysis/undeclaredname/undeclared.go @@ -45,6 +45,7 @@ var Analyzer = &analysis.Analyzer{ RunDespiteErrors: true, } +// The prefix for this error message changed in Go 1.20. var undeclaredNamePrefixes = []string{"undeclared name: ", "undefined: "} func run(pass *analysis.Pass) (interface{}, error) { diff --git a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go index eccfe14c3a..aa9f46e5b3 100644 --- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go +++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go @@ -14,55 +14,55 @@ type A struct { } func singleAssignment() { - v := "s" // want `v declared but not used` + v := "s" // want `v declared (and|but) not used` - s := []int{ // want `s declared but not used` + s := []int{ // want `s declared (and|but) not used` 1, 2, } - a := func(s string) bool { // want `a declared but not used` + a := func(s string) bool { // want `a declared (and|but) not used` return false } if 1 == 1 { - s := "v" // want `s declared but not used` + s := "v" // want `s declared (and|but) not used` } panic("I should survive") } func noOtherStmtsInBlock() { - v := "s" // want `v declared but not used` + v := "s" // want `v declared (and|but) not used` } func partOfMultiAssignment() { - f, err := os.Open("file") // want `f declared but not used` + f, err := os.Open("file") // want `f declared (and|but) not used` panic(err) } func sideEffects(cBool chan bool, cInt chan int) { - b := <-c // want `b declared but not used` - s := fmt.Sprint("") // want `s declared but not used` - a := A{ // want `a declared but not used` + b := <-c // want `b declared (and|but) not used` + s := fmt.Sprint("") // want `s declared (and|but) not used` + a := A{ // want `a declared (and|but) not used` b: func() int { return 1 }(), } - c := A{<-cInt} // want `c declared but not used` - d := fInt() + <-cInt // want `d declared but not used` - e := fBool() && <-cBool // want `e declared but not used` - f := map[int]int{ // want `f declared but not used` + c := A{<-cInt} // want `c declared (and|but) not used` + d := fInt() + <-cInt // want `d declared (and|but) not used` + e := fBool() && <-cBool // want `e declared (and|but) not used` + f := map[int]int{ // want `f declared (and|but) not used` fInt(): <-cInt, } - g := []int{<-cInt} // want `g declared but not used` - h := func(s string) {} // want `h declared but not used` - i := func(s string) {}() // want `i declared but not used` + g := []int{<-cInt} // want `g declared (and|but) not used` + h := func(s string) {} // want `h declared (and|but) not used` + i := func(s string) {}() // want `i declared (and|but) not used` } func commentAbove() { // v is a variable - v := "s" // want `v declared but not used` + v := "s" // want `v declared (and|but) not used` } func fBool() bool { diff --git a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden index 8d6e561fa6..18173ce0bf 100644 --- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden +++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/assign/a.go.golden @@ -24,26 +24,26 @@ func noOtherStmtsInBlock() { } func partOfMultiAssignment() { - _, err := os.Open("file") // want `f declared but not used` + _, err := os.Open("file") // want `f declared (and|but) not used` panic(err) } func sideEffects(cBool chan bool, cInt chan int) { - <-c // want `b declared but not used` - fmt.Sprint("") // want `s declared but not used` - A{ // want `a declared but not used` + <-c // want `b declared (and|but) not used` + fmt.Sprint("") // want `s declared (and|but) not used` + A{ // want `a declared (and|but) not used` b: func() int { return 1 }(), } - A{<-cInt} // want `c declared but not used` - fInt() + <-cInt // want `d declared but not used` - fBool() && <-cBool // want `e declared but not used` - map[int]int{ // want `f declared but not used` + A{<-cInt} // want `c declared (and|but) not used` + fInt() + <-cInt // want `d declared (and|but) not used` + fBool() && <-cBool // want `e declared (and|but) not used` + map[int]int{ // want `f declared (and|but) not used` fInt(): <-cInt, } - []int{<-cInt} // want `g declared but not used` - func(s string) {}() // want `i declared but not used` + []int{<-cInt} // want `g declared (and|but) not used` + func(s string) {}() // want `i declared (and|but) not used` } func commentAbove() { diff --git a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go index 024e49db9c..8e843024a5 100644 --- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go +++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go @@ -5,17 +5,17 @@ package decl func a() { - var b, c bool // want `b declared but not used` + var b, c bool // want `b declared (and|but) not used` panic(c) if 1 == 1 { - var s string // want `s declared but not used` + var s string // want `s declared (and|but) not used` } } func b() { // b is a variable - var b bool // want `b declared but not used` + var b bool // want `b declared (and|but) not used` } func c() { @@ -23,7 +23,7 @@ func c() { d string // some comment for c - c bool // want `c declared but not used` + c bool // want `c declared (and|but) not used` ) panic(d) diff --git a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden index a589a47af1..6ed97332ee 100644 --- a/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden +++ b/gopls/internal/lsp/analysis/unusedvariable/testdata/src/decl/a.go.golden @@ -5,7 +5,7 @@ package decl func a() { - var c bool // want `b declared but not used` + var c bool // want `b declared (and|but) not used` panic(c) if 1 == 1 { diff --git a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go index 47564f1f15..026befb7df 100644 --- a/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go +++ b/gopls/internal/lsp/analysis/unusedvariable/unusedvariable.go @@ -34,15 +34,18 @@ var Analyzer = &analysis.Analyzer{ type fixesForError map[types.Error][]analysis.SuggestedFix -const unusedVariableSuffix = " declared but not used" +// The suffix for this error message changed in Go 1.20. +var unusedVariableSuffixes = []string{" declared and not used", " declared but not used"} func run(pass *analysis.Pass) (interface{}, error) { for _, typeErr := range analysisinternal.GetTypeErrors(pass) { - if strings.HasSuffix(typeErr.Msg, unusedVariableSuffix) { - varName := strings.TrimSuffix(typeErr.Msg, unusedVariableSuffix) - err := runForError(pass, typeErr, varName) - if err != nil { - return nil, err + for _, suffix := range unusedVariableSuffixes { + if strings.HasSuffix(typeErr.Msg, suffix) { + varName := strings.TrimSuffix(typeErr.Msg, suffix) + err := runForError(pass, typeErr, varName) + if err != nil { + return nil, err + } } } } diff --git a/gopls/internal/lsp/cmd/test/check.go b/gopls/internal/lsp/cmd/test/check.go index 4f5e471dd3..819863dada 100644 --- a/gopls/internal/lsp/cmd/test/check.go +++ b/gopls/internal/lsp/cmd/test/check.go @@ -59,7 +59,5 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []*source.Diagnost diag.Severity = 0 } - if diff := tests.DiffDiagnostics(uri, want, got); diff != "" { - t.Error(diff) - } + tests.CompareDiagnostics(t, uri, want, got) } diff --git a/gopls/internal/lsp/lsp_test.go b/gopls/internal/lsp/lsp_test.go index 269fdaf3fb..a61f683078 100644 --- a/gopls/internal/lsp/lsp_test.go +++ b/gopls/internal/lsp/lsp_test.go @@ -223,9 +223,7 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []*source.Diagnost v := r.server.session.View(r.data.Config.Dir) r.collectDiagnostics(v) got := append([]*source.Diagnostic(nil), r.diagnostics[uri]...) // copy - if diff := tests.DiffDiagnostics(uri, want, got); diff != "" { - t.Error(diff) - } + tests.CompareDiagnostics(t, uri, want, got) } func (r *runner) FoldingRanges(t *testing.T, spn span.Span) { @@ -416,8 +414,8 @@ func (r *runner) Format(t *testing.T, spn span.Span) { t.Error(err) } got := diff.ApplyEdits(string(m.Content), sedits) - if gofmted != got { - t.Errorf("format failed for %s, expected:\n%v\ngot:\n%v", filename, gofmted, got) + if diff := compare.Text(gofmted, got); diff != "" { + t.Errorf("format failed for %s (-want +got):\n%s", filename, diff) } } diff --git a/gopls/internal/lsp/source/source_test.go b/gopls/internal/lsp/source/source_test.go index 155832a482..1f348764cf 100644 --- a/gopls/internal/lsp/source/source_test.go +++ b/gopls/internal/lsp/source/source_test.go @@ -156,9 +156,7 @@ func (r *runner) Diagnostics(t *testing.T, uri span.URI, want []*source.Diagnost if err != nil { t.Fatal(err) } - if diff := tests.DiffDiagnostics(fileID.URI, want, got); diff != "" { - t.Error(diff) - } + tests.CompareDiagnostics(t, fileID.URI, want, got) } func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, items tests.CompletionItems) { diff --git a/gopls/internal/lsp/testdata/bad/bad0.go b/gopls/internal/lsp/testdata/bad/bad0.go index e8f3c2f297..9eedf4aead 100644 --- a/gopls/internal/lsp/testdata/bad/bad0.go +++ b/gopls/internal/lsp/testdata/bad/bad0.go @@ -9,7 +9,7 @@ func stuff() { //@item(stuff, "stuff", "func()", "func") x := "heeeeyyyy" random2(x) //@diag("x", "compiler", "cannot use x \\(variable of type string\\) as int value in argument to random2", "error") random2(1) //@complete("dom", random, random2, random3) - y := 3 //@diag("y", "compiler", "y declared but not used", "error") + y := 3 //@diag("y", "compiler", "y declared (and|but) not used", "error") } type bob struct { //@item(bob, "bob", "struct{...}", "struct") diff --git a/gopls/internal/lsp/testdata/bad/bad1.go b/gopls/internal/lsp/testdata/bad/bad1.go index 04472feae4..13b3d0af61 100644 --- a/gopls/internal/lsp/testdata/bad/bad1.go +++ b/gopls/internal/lsp/testdata/bad/bad1.go @@ -14,9 +14,9 @@ func random() int { //@item(random, "random", "func() int", "func") } func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func"),item(bad_y_param, "y", "int", "var") - x := 6 //@item(x, "x", "int", "var"),diag("x", "compiler", "x declared but not used", "error") - var q blah //@item(q, "q", "blah", "var"),diag("q", "compiler", "q declared but not used", "error"),diag("blah", "compiler", "(undeclared name|undefined): blah", "error") - var t **blob //@item(t, "t", "**blob", "var"),diag("t", "compiler", "t declared but not used", "error"),diag("blob", "compiler", "(undeclared name|undefined): blob", "error") + x := 6 //@item(x, "x", "int", "var"),diag("x", "compiler", "x declared (and|but) not used", "error") + var q blah //@item(q, "q", "blah", "var"),diag("q", "compiler", "q declared (and|but) not used", "error"),diag("blah", "compiler", "(undeclared name|undefined): blah", "error") + var t **blob //@item(t, "t", "**blob", "var"),diag("t", "compiler", "t declared (and|but) not used", "error"),diag("blob", "compiler", "(undeclared name|undefined): blob", "error") //@complete("", q, t, x, bad_y_param, global_a, bob, random, random2, random3, stateFunc, stuff) return y @@ -25,10 +25,10 @@ func random2(y int) int { //@item(random2, "random2", "func(y int) int", "func") func random3(y ...int) { //@item(random3, "random3", "func(y ...int)", "func"),item(y_variadic_param, "y", "[]int", "var") //@complete("", y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff) - var ch chan (favType1) //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", "compiler", "ch declared but not used", "error"),diag("favType1", "compiler", "(undeclared name|undefined): favType1", "error") - var m map[keyType]int //@item(m, "m", "map[keyType]int", "var"),diag("m", "compiler", "m declared but not used", "error"),diag("keyType", "compiler", "(undeclared name|undefined): keyType", "error") - var arr []favType2 //@item(arr, "arr", "[]favType2", "var"),diag("arr", "compiler", "arr declared but not used", "error"),diag("favType2", "compiler", "(undeclared name|undefined): favType2", "error") - var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", "compiler", "fn1 declared but not used", "error"),diag("badResult", "compiler", "(undeclared name|undefined): badResult", "error") - var fn2 func(badParam) //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", "compiler", "fn2 declared but not used", "error"),diag("badParam", "compiler", "(undeclared name|undefined): badParam", "error") + var ch chan (favType1) //@item(ch, "ch", "chan (favType1)", "var"),diag("ch", "compiler", "ch declared (and|but) not used", "error"),diag("favType1", "compiler", "(undeclared name|undefined): favType1", "error") + var m map[keyType]int //@item(m, "m", "map[keyType]int", "var"),diag("m", "compiler", "m declared (and|but) not used", "error"),diag("keyType", "compiler", "(undeclared name|undefined): keyType", "error") + var arr []favType2 //@item(arr, "arr", "[]favType2", "var"),diag("arr", "compiler", "arr declared (and|but) not used", "error"),diag("favType2", "compiler", "(undeclared name|undefined): favType2", "error") + var fn1 func() badResult //@item(fn1, "fn1", "func() badResult", "var"),diag("fn1", "compiler", "fn1 declared (and|but) not used", "error"),diag("badResult", "compiler", "(undeclared name|undefined): badResult", "error") + var fn2 func(badParam) //@item(fn2, "fn2", "func(badParam)", "var"),diag("fn2", "compiler", "fn2 declared (and|but) not used", "error"),diag("badParam", "compiler", "(undeclared name|undefined): badParam", "error") //@complete("", arr, ch, fn1, fn2, m, y_variadic_param, global_a, bob, random, random2, random3, stateFunc, stuff) } diff --git a/gopls/internal/lsp/testdata/format/bad_format.go.golden b/gopls/internal/lsp/testdata/format/bad_format.go.golden index c2ac5a1a13..f0c24d6356 100644 --- a/gopls/internal/lsp/testdata/format/bad_format.go.golden +++ b/gopls/internal/lsp/testdata/format/bad_format.go.golden @@ -9,7 +9,7 @@ import ( func hello() { - var x int //@diag("x", "compiler", "x declared but not used", "error") + var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") } func hi() { diff --git a/gopls/internal/lsp/testdata/format/bad_format.go.in b/gopls/internal/lsp/testdata/format/bad_format.go.in index 06187238eb..995ec399a1 100644 --- a/gopls/internal/lsp/testdata/format/bad_format.go.in +++ b/gopls/internal/lsp/testdata/format/bad_format.go.in @@ -11,7 +11,7 @@ func hello() { - var x int //@diag("x", "compiler", "x declared but not used", "error") + var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") } func hi() { diff --git a/gopls/internal/lsp/testdata/generated/generated.go b/gopls/internal/lsp/testdata/generated/generated.go index c92bd9eb8c..c7adc18040 100644 --- a/gopls/internal/lsp/testdata/generated/generated.go +++ b/gopls/internal/lsp/testdata/generated/generated.go @@ -3,5 +3,5 @@ package generated // Code generated by generator.go. DO NOT EDIT. func _() { - var y int //@diag("y", "compiler", "y declared but not used", "error") + var y int //@diag("y", "compiler", "y declared (and|but) not used", "error") } diff --git a/gopls/internal/lsp/testdata/generated/generator.go b/gopls/internal/lsp/testdata/generated/generator.go index f26e33c806..8e2a4fab72 100644 --- a/gopls/internal/lsp/testdata/generated/generator.go +++ b/gopls/internal/lsp/testdata/generated/generator.go @@ -1,5 +1,5 @@ package generated func _() { - var x int //@diag("x", "compiler", "x declared but not used", "error") + var x int //@diag("x", "compiler", "x declared (and|but) not used", "error") } diff --git a/gopls/internal/lsp/testdata/testy/testy_test.go b/gopls/internal/lsp/testdata/testy/testy_test.go index 487b730176..a7e897840a 100644 --- a/gopls/internal/lsp/testdata/testy/testy_test.go +++ b/gopls/internal/lsp/testdata/testy/testy_test.go @@ -8,7 +8,7 @@ import ( ) func TestSomething(t *testing.T) { //@item(TestSomething, "TestSomething(t *testing.T)", "", "func") - var x int //@mark(testyX, "x"),diag("x", "compiler", "x declared but not used", "error"),refs("x", testyX) + var x int //@mark(testyX, "x"),diag("x", "compiler", "x declared (and|but) not used", "error"),refs("x", testyX) a() //@mark(testyA, "a") } diff --git a/gopls/internal/lsp/tests/util.go b/gopls/internal/lsp/tests/util.go index 6f2d01cd8d..aa9381d4ca 100644 --- a/gopls/internal/lsp/tests/util.go +++ b/gopls/internal/lsp/tests/util.go @@ -9,11 +9,13 @@ import ( "context" "fmt" "go/token" + "path" "path/filepath" "regexp" "sort" "strconv" "strings" + "testing" "golang.org/x/tools/gopls/internal/lsp/protocol" "golang.org/x/tools/gopls/internal/lsp/source" @@ -65,43 +67,69 @@ func DiffLinks(mapper *protocol.ColumnMapper, wantLinks []Link, gotLinks []proto return "" } -// DiffDiagnostics prints the diff between expected and actual diagnostics test -// results. If the sole expectation is "no_diagnostics", the check is suppressed. -// The Message field of each want element must be a regular expression. -func DiffDiagnostics(uri span.URI, want, got []*source.Diagnostic) string { +// CompareDiagnostics reports testing errors to t when the diagnostic set got +// does not match want. If the sole expectation has source "no_diagnostics", +// the test expects that no diagnostics were received for the given document. +func CompareDiagnostics(t *testing.T, uri span.URI, want, got []*source.Diagnostic) { + t.Helper() + fileName := path.Base(string(uri)) + // A special case to test that there are no diagnostics for a file. if len(want) == 1 && want[0].Source == "no_diagnostics" { - if len(got) != 0 { - return fmt.Sprintf("expected no diagnostics for %s, got %v", uri, got) + want = nil + } + + // Build a helper function to match an actual diagnostic to an overlapping + // expected diagnostic (if any). + unmatched := make([]*source.Diagnostic, len(want)) + copy(unmatched, want) + source.SortDiagnostics(unmatched) + match := func(g *source.Diagnostic) *source.Diagnostic { + // Find the last expected diagnostic d for which start(d) < end(g), and + // check to see if it overlaps. + i := sort.Search(len(unmatched), func(i int) bool { + d := unmatched[i] + // See rangeOverlaps: if a range is a single point, we consider End to be + // included in the range... + if g.Range.Start == g.Range.End { + return protocol.ComparePosition(d.Range.Start, g.Range.End) > 0 + } + // ...otherwise the end position of a range is not included. + return protocol.ComparePosition(d.Range.Start, g.Range.End) >= 0 + }) + if i == 0 { + return nil } - return "" + w := unmatched[i-1] + if rangeOverlaps(w.Range, g.Range) { + unmatched = append(unmatched[:i-1], unmatched[i:]...) + return w + } + return nil } - source.SortDiagnostics(want) - source.SortDiagnostics(got) - - if len(got) != len(want) { - // TODO(adonovan): print the actual difference, not the difference in length! - return summarizeDiagnostics(-1, uri, want, got, "different lengths got %v want %v", len(got), len(want)) - } - for i, w := range want { - g := got[i] - if !rangeOverlaps(g.Range, w.Range) { - return summarizeDiagnostics(i, uri, want, got, "got Range %v, want overlap with %v", g.Range, w.Range) + for _, g := range got { + w := match(g) + if w == nil { + t.Errorf("%s:%s: unexpected diagnostic %q", fileName, g.Range, g.Message) + continue } if match, err := regexp.MatchString(w.Message, g.Message); err != nil { - return summarizeDiagnostics(i, uri, want, got, "%s: invalid regular expression %q: %v", w.Range.Start, w.Message, err) + t.Errorf("%s:%s: invalid regular expression %q: %v", fileName, w.Range.Start, w.Message, err) } else if !match { - return summarizeDiagnostics(i, uri, want, got, "%s: got Message %q, want match for pattern %q", g.Range.Start, g.Message, w.Message) + t.Errorf("%s:%s: got Message %q, want match for pattern %q", fileName, g.Range.Start, g.Message, w.Message) } if w.Severity != g.Severity { - return summarizeDiagnostics(i, uri, want, got, "%s: got Severity %v, want %v", g.Range.Start, g.Severity, w.Severity) + t.Errorf("%s:%s: got Severity %v, want %v", fileName, g.Range.Start, g.Severity, w.Severity) } if w.Source != g.Source { - return summarizeDiagnostics(i, uri, want, got, "%s: got Source %v, want %v", g.Range.Start, g.Source, w.Source) + t.Errorf("%s:%s: got Source %v, want %v", fileName, g.Range.Start, g.Source, w.Source) } } - return "" + + for _, w := range unmatched { + t.Errorf("%s:%s: unmatched diagnostic pattern %q", fileName, w.Range, w.Message) + } } // rangeOverlaps reports whether r1 and r2 overlap. @@ -125,25 +153,6 @@ func inRange(p protocol.Position, r protocol.Range) bool { return false } -func summarizeDiagnostics(i int, uri span.URI, want, got []*source.Diagnostic, reason string, args ...interface{}) string { - msg := &bytes.Buffer{} - fmt.Fprint(msg, "diagnostics failed") - if i >= 0 { - fmt.Fprintf(msg, " at %d", i) - } - fmt.Fprint(msg, " because of ") - fmt.Fprintf(msg, reason, args...) - fmt.Fprint(msg, ":\nexpected:\n") - for _, d := range want { - fmt.Fprintf(msg, " %s:%v: %s\n", uri, d.Range, d.Message) - } - fmt.Fprintf(msg, "got:\n") - for _, d := range got { - fmt.Fprintf(msg, " %s:%v: %s\n", uri, d.Range, d.Message) - } - return msg.String() -} - func DiffCodeLens(uri span.URI, want, got []protocol.CodeLens) string { sortCodeLens(want) sortCodeLens(got) diff --git a/gopls/internal/regtest/workspace/workspace_test.go b/gopls/internal/regtest/workspace/workspace_test.go index 92cd174c2e..5d3053c285 100644 --- a/gopls/internal/regtest/workspace/workspace_test.go +++ b/gopls/internal/regtest/workspace/workspace_test.go @@ -1215,7 +1215,7 @@ import ( env.Await( OnceMet( env.DoneWithOpen(), - env.DiagnosticAtRegexpWithMessage("a/main.go", "V", "declared but not used"), + env.DiagnosticAtRegexpWithMessage("a/main.go", "V", "not used"), ), ) env.CloseBuffer("a/main.go")