aboutsummaryrefslogtreecommitdiff
path: root/gopls/internal/regtest/misc/staticcheck_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'gopls/internal/regtest/misc/staticcheck_test.go')
-rw-r--r--gopls/internal/regtest/misc/staticcheck_test.go110
1 files changed, 110 insertions, 0 deletions
diff --git a/gopls/internal/regtest/misc/staticcheck_test.go b/gopls/internal/regtest/misc/staticcheck_test.go
new file mode 100644
index 000000000..fa049ab0e
--- /dev/null
+++ b/gopls/internal/regtest/misc/staticcheck_test.go
@@ -0,0 +1,110 @@
+// 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/gopls/internal/lsp/regtest"
+)
+
+func TestStaticcheckGenerics(t *testing.T) {
+ testenv.NeedsGo1Point(t, 19) // generics were introduced in Go 1.18, staticcheck requires go1.19+
+
+ 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(
+ Settings{"staticcheck": true},
+ ).Run(t, files, func(t *testing.T, env *Env) {
+ env.OpenFile("a/a.go")
+ env.AfterChange(
+ Diagnostics(env.AtRegexp("a/a.go", "sort.Slice"), FromSource("sortslice")),
+ Diagnostics(env.AtRegexp("a/a.go", "sort.Slice.(slice)"), FromSource("SA1028")),
+ Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)"), FromSource("ST1012")),
+ Diagnostics(env.AtRegexp("a/a.go", `"12234"`), FromSource("SA1024")),
+ Diagnostics(env.AtRegexp("a/a.go", "testGenerics.*(p P)"), FromSource("SA4009")),
+ Diagnostics(env.AtRegexp("a/a.go", "q = (&\\*p)"), FromSource("SA4001")),
+ )
+ })
+}
+
+// Test for golang/go#56270: an analysis with related info should not panic if
+// analysis.RelatedInformation.End is not set.
+func TestStaticcheckRelatedInfo(t *testing.T) {
+ testenv.NeedsGo1Point(t, 19) // staticcheck is only supported at Go 1.19+
+ const files = `
+-- go.mod --
+module mod.test
+
+go 1.18
+-- p.go --
+package p
+
+import (
+ "fmt"
+)
+
+func Foo(enabled interface{}) {
+ if enabled, ok := enabled.(bool); ok {
+ } else {
+ _ = fmt.Sprintf("invalid type %T", enabled) // enabled is always bool here
+ }
+}
+`
+
+ WithOptions(
+ Settings{"staticcheck": true},
+ ).Run(t, files, func(t *testing.T, env *Env) {
+ env.OpenFile("p.go")
+ env.AfterChange(
+ Diagnostics(env.AtRegexp("p.go", ", (enabled)"), FromSource("SA9008")),
+ )
+ })
+}