mirror of https://github.com/golang/go.git
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 <noreply+kokoro@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Robert Findley <rfindley@google.com> Reviewed-by: Alan Donovan <adonovan@google.com> Reviewed-by: Robert Griesemer <gri@google.com> Auto-Submit: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
eb45e986a7
commit
10e9d3cefa
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue