golang.org/x/tools/gopls@v0.15.3/internal/test/integration/misc/staticcheck_test.go (about)

     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/gopls/internal/test/integration"
    13  )
    14  
    15  func TestStaticcheckGenerics(t *testing.T) {
    16  	testenv.NeedsGo1Point(t, 20) // staticcheck requires go1.20+
    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(
    64  		Settings{"staticcheck": true},
    65  	).Run(t, files, func(t *testing.T, env *Env) {
    66  		env.OpenFile("a/a.go")
    67  		env.AfterChange(
    68  			Diagnostics(env.AtRegexp("a/a.go", "sort.Slice"), FromSource("sortslice")),
    69  			Diagnostics(env.AtRegexp("a/a.go", "sort.Slice.(slice)"), FromSource("SA1028")),
    70  			Diagnostics(env.AtRegexp("a/a.go", "var (FooErr)"), FromSource("ST1012")),
    71  			Diagnostics(env.AtRegexp("a/a.go", `"12234"`), FromSource("SA1024")),
    72  			Diagnostics(env.AtRegexp("a/a.go", "testGenerics.*(p P)"), FromSource("SA4009")),
    73  			Diagnostics(env.AtRegexp("a/a.go", "q = (&\\*p)"), FromSource("SA4001")),
    74  		)
    75  	})
    76  }
    77  
    78  // Test for golang/go#56270: an analysis with related info should not panic if
    79  // analysis.RelatedInformation.End is not set.
    80  func TestStaticcheckRelatedInfo(t *testing.T) {
    81  	testenv.NeedsGo1Point(t, 20) // staticcheck is only supported at Go 1.20+
    82  	const files = `
    83  -- go.mod --
    84  module mod.test
    85  
    86  go 1.18
    87  -- p.go --
    88  package p
    89  
    90  import (
    91  	"fmt"
    92  )
    93  
    94  func Foo(enabled interface{}) {
    95  	if enabled, ok := enabled.(bool); ok {
    96  	} else {
    97  		_ = fmt.Sprintf("invalid type %T", enabled) // enabled is always bool here
    98  	}
    99  }
   100  `
   101  
   102  	WithOptions(
   103  		Settings{"staticcheck": true},
   104  	).Run(t, files, func(t *testing.T, env *Env) {
   105  		env.OpenFile("p.go")
   106  		env.AfterChange(
   107  			Diagnostics(env.AtRegexp("p.go", ", (enabled)"), FromSource("SA9008")),
   108  		)
   109  	})
   110  }