Skip to content

Commit 728485f

Browse files
committed
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 <[email protected]> Run-TryBot: Robert Findley <[email protected]> gopls-CI: kokoro <[email protected]> Reviewed-by: Dylan Le <[email protected]>
1 parent 1a5eed3 commit 728485f

File tree

2 files changed

+95
-0
lines changed

2 files changed

+95
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package misc
6+
7+
import (
8+
"testing"
9+
10+
"golang.org/x/tools/internal/testenv"
11+
12+
. "golang.org/x/tools/internal/lsp/regtest"
13+
)
14+
15+
func TestStaticcheckGenerics(t *testing.T) {
16+
testenv.NeedsGo1Point(t, 18) // generics were introduced in Go 1.18
17+
18+
const files = `
19+
-- go.mod --
20+
module mod.com
21+
22+
go 1.18
23+
-- a/a.go --
24+
package a
25+
26+
import (
27+
"errors"
28+
"sort"
29+
"strings"
30+
)
31+
32+
func Zero[P any]() P {
33+
var p P
34+
return p
35+
}
36+
37+
type Inst[P any] struct {
38+
Field P
39+
}
40+
41+
func testGenerics[P *T, T any](p P) {
42+
// Calls to instantiated functions should not break checks.
43+
slice := Zero[string]()
44+
sort.Slice(slice, func(i, j int) bool {
45+
return slice[i] < slice[j]
46+
})
47+
48+
// Usage of instantiated fields should not break checks.
49+
g := Inst[string]{"hello"}
50+
g.Field = strings.TrimLeft(g.Field, "12234")
51+
52+
// Use of type parameters should not break checks.
53+
var q P
54+
p = q // SA4009: p is overwritten before its first use
55+
q = &*p // SA4001: &* will be simplified
56+
}
57+
58+
59+
// FooErr should be called ErrFoo (ST1012)
60+
var FooErr error = errors.New("foo")
61+
`
62+
63+
WithOptions(EditorConfig{
64+
Settings: map[string]interface{}{
65+
"staticcheck": true,
66+
},
67+
}).Run(t, files, func(t *testing.T, env *Env) {
68+
env.OpenFile("a/a.go")
69+
env.Await(
70+
env.DiagnosticAtRegexpFromSource("a/a.go", "sort.Slice", "sortslice"),
71+
env.DiagnosticAtRegexpFromSource("a/a.go", "sort.Slice.(slice)", "SA1028"),
72+
env.DiagnosticAtRegexpFromSource("a/a.go", "var (FooErr)", "ST1012"),
73+
env.DiagnosticAtRegexpFromSource("a/a.go", `"12234"`, "SA1024"),
74+
env.DiagnosticAtRegexpFromSource("a/a.go", "testGenerics.*(p P)", "SA4009"),
75+
env.DiagnosticAtRegexpFromSource("a/a.go", "q = (&\\*p)", "SA4001"),
76+
)
77+
})
78+
}

internal/lsp/regtest/expectation.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,9 @@ type DiagnosticExpectation struct {
465465

466466
// path is the scratch workdir-relative path to the file being asserted on.
467467
path string
468+
469+
// optionally, the diagnostic source
470+
source string
468471
}
469472

470473
// Check implements the Expectation interface.
@@ -489,6 +492,9 @@ func (e DiagnosticExpectation) Check(s State) Verdict {
489492
continue
490493
}
491494
}
495+
if e.source != "" && e.source != d.Source {
496+
continue
497+
}
492498
found = true
493499
break
494500
}
@@ -515,6 +521,9 @@ func (e DiagnosticExpectation) Description() string {
515521
if e.message != "" {
516522
desc += fmt.Sprintf(" with message %q", e.message)
517523
}
524+
if e.source != "" {
525+
desc += fmt.Sprintf(" from source %q", e.source)
526+
}
518527
return desc
519528
}
520529

@@ -619,6 +628,14 @@ func (e *Env) DiagnosticAtRegexpWithMessage(name, re, msg string) DiagnosticExpe
619628
return DiagnosticExpectation{path: name, pos: &pos, re: re, present: true, message: msg}
620629
}
621630

631+
// DiagnosticAtRegexpFromSource expects a diagnostic at the first position
632+
// matching re, from the given source.
633+
func (e *Env) DiagnosticAtRegexpFromSource(name, re, source string) DiagnosticExpectation {
634+
e.T.Helper()
635+
pos := e.RegexpSearch(name, re)
636+
return DiagnosticExpectation{path: name, pos: &pos, re: re, present: true, source: source}
637+
}
638+
622639
// DiagnosticAt asserts that there is a diagnostic entry at the position
623640
// specified by line and col, for the workdir-relative path name.
624641
func DiagnosticAt(name string, line, col int) DiagnosticExpectation {

0 commit comments

Comments
 (0)