gopls/internal/regtest: add a test for using staticcheck with generics

For golang/go#52159

Change-Id: I08120331b7f5c9eb06feac0d0eeb76a9a7b629df
Reviewed-on: https://go-review.googlesource.com/c/tools/+/399914
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Robert Findley <rfindley@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
Reviewed-by: Dylan Le <dungtuanle@google.com>
This commit is contained in:
Robert Findley 2022-04-12 10:53:04 -04:00
parent 1a5eed31fb
commit 728485ffcb
2 changed files with 95 additions and 0 deletions

View File

@ -0,0 +1,78 @@
// Copyright 2022 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 misc
import (
"testing"
"golang.org/x/tools/internal/testenv"
. "golang.org/x/tools/internal/lsp/regtest"
)
func TestStaticcheckGenerics(t *testing.T) {
testenv.NeedsGo1Point(t, 18) // generics were introduced in Go 1.18
const files = `
-- go.mod --
module mod.com
go 1.18
-- a/a.go --
package a
import (
"errors"
"sort"
"strings"
)
func Zero[P any]() P {
var p P
return p
}
type Inst[P any] struct {
Field P
}
func testGenerics[P *T, T any](p P) {
// Calls to instantiated functions should not break checks.
slice := Zero[string]()
sort.Slice(slice, func(i, j int) bool {
return slice[i] < slice[j]
})
// Usage of instantiated fields should not break checks.
g := Inst[string]{"hello"}
g.Field = strings.TrimLeft(g.Field, "12234")
// Use of type parameters should not break checks.
var q P
p = q // SA4009: p is overwritten before its first use
q = &*p // SA4001: &* will be simplified
}
// FooErr should be called ErrFoo (ST1012)
var FooErr error = errors.New("foo")
`
WithOptions(EditorConfig{
Settings: map[string]interface{}{
"staticcheck": true,
},
}).Run(t, files, func(t *testing.T, env *Env) {
env.OpenFile("a/a.go")
env.Await(
env.DiagnosticAtRegexpFromSource("a/a.go", "sort.Slice", "sortslice"),
env.DiagnosticAtRegexpFromSource("a/a.go", "sort.Slice.(slice)", "SA1028"),
env.DiagnosticAtRegexpFromSource("a/a.go", "var (FooErr)", "ST1012"),
env.DiagnosticAtRegexpFromSource("a/a.go", `"12234"`, "SA1024"),
env.DiagnosticAtRegexpFromSource("a/a.go", "testGenerics.*(p P)", "SA4009"),
env.DiagnosticAtRegexpFromSource("a/a.go", "q = (&\\*p)", "SA4001"),
)
})
}

View File

@ -465,6 +465,9 @@ type DiagnosticExpectation struct {
// path is the scratch workdir-relative path to the file being asserted on.
path string
// optionally, the diagnostic source
source string
}
// Check implements the Expectation interface.
@ -489,6 +492,9 @@ func (e DiagnosticExpectation) Check(s State) Verdict {
continue
}
}
if e.source != "" && e.source != d.Source {
continue
}
found = true
break
}
@ -515,6 +521,9 @@ func (e DiagnosticExpectation) Description() string {
if e.message != "" {
desc += fmt.Sprintf(" with message %q", e.message)
}
if e.source != "" {
desc += fmt.Sprintf(" from source %q", e.source)
}
return desc
}
@ -619,6 +628,14 @@ func (e *Env) DiagnosticAtRegexpWithMessage(name, re, msg string) DiagnosticExpe
return DiagnosticExpectation{path: name, pos: &pos, re: re, present: true, message: msg}
}
// DiagnosticAtRegexpFromSource expects a diagnostic at the first position
// matching re, from the given source.
func (e *Env) DiagnosticAtRegexpFromSource(name, re, source string) DiagnosticExpectation {
e.T.Helper()
pos := e.RegexpSearch(name, re)
return DiagnosticExpectation{path: name, pos: &pos, re: re, present: true, source: source}
}
// DiagnosticAt asserts that there is a diagnostic entry at the position
// specified by line and col, for the workdir-relative path name.
func DiagnosticAt(name string, line, col int) DiagnosticExpectation {