Skip to content

Commit

Permalink
go/analysis/passes/tests: update for generics
Browse files Browse the repository at this point in the history
Warn about Test functions that contain type parameters.

For golang/go#48704

Change-Id: I3f6852613482ec6f33e5650a014564915f11b920
Reviewed-on: https://go-review.googlesource.com/c/tools/+/359494
Run-TryBot: Tim King <taking@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Tim King <taking@google.com>
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
  • Loading branch information
timothy-king committed Oct 29, 2021
1 parent 4d2571b commit a2be0cd
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 3 deletions.
10 changes: 10 additions & 0 deletions go/analysis/passes/tests/testdata/src/typeparams/typeparams.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright 2021 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 typeparams

func Zero[T any]() T {
var zero T
return zero
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright 2021 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 typeparams

import "testing"

func Test(*testing.T) {
_ = Zero[int]() // It is fine to use generics within tests.
}

// Note: We format {Test,Benchmark}typeParam with a 't' in "type" to avoid an error from
// cmd/go/internal/load. That package can also give an error about Test and Benchmark
// functions with TypeParameters. These tests may need to be updated if that logic changes.
func TesttypeParam[T any](*testing.T) {} // want "TesttypeParam has type parameters: it will not be run by go test as a TestXXX function" "TesttypeParam has malformed name"
func BenchmarktypeParam[T any](*testing.B) {} // want "BenchmarktypeParam has type parameters: it will not be run by go test as a BenchmarkXXX function" "BenchmarktypeParam has malformed name"

func ExampleZero[T any]() { // want "ExampleZero should not have type params"
print(Zero[T]())
}
10 changes: 10 additions & 0 deletions go/analysis/passes/tests/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"unicode/utf8"

"golang.org/x/tools/go/analysis"
"golang.org/x/tools/internal/typeparams"
)

const Doc = `check for common mistaken usages of tests and examples
Expand Down Expand Up @@ -170,6 +171,9 @@ func checkExampleName(pass *analysis.Pass, fn *ast.FuncDecl) {
if results := fn.Type.Results; results != nil && len(results.List) != 0 {
pass.Reportf(fn.Pos(), "%s should return nothing", fnName)
}
if tparams := typeparams.ForFuncType(fn.Type); tparams != nil && len(tparams.List) > 0 {
pass.Reportf(fn.Pos(), "%s should not have type params", fnName)
}

if fnName == "Example" {
// Nothing more to do.
Expand Down Expand Up @@ -236,6 +240,12 @@ func checkTest(pass *analysis.Pass, fn *ast.FuncDecl, prefix string) {
return
}

if tparams := typeparams.ForFuncType(fn.Type); tparams != nil && len(tparams.List) > 0 {
// Note: cmd/go/internal/load also errors about TestXXX and BenchmarkXXX functions with type parameters.
// We have currently decided to also warn before compilation/package loading. This can help users in IDEs.
pass.Reportf(fn.Pos(), "%s has type parameters: it will not be run by go test as a %sXXX function", fn.Name.Name, prefix)
}

if !isTestSuffix(fn.Name.Name[len(prefix):]) {
pass.Reportf(fn.Pos(), "%s has malformed name: first letter after '%s' must not be lowercase", fn.Name.Name, prefix)
}
Expand Down
10 changes: 7 additions & 3 deletions go/analysis/passes/tests/tests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import (

"golang.org/x/tools/go/analysis/analysistest"
"golang.org/x/tools/go/analysis/passes/tests"
"golang.org/x/tools/internal/typeparams"
)

func Test(t *testing.T) {
testdata := analysistest.TestData()

analysistest.Run(t, testdata, tests.Analyzer,
pkgs := []string{
"a", // loads "a", "a [a.test]", and "a.test"
"b_x_test", // loads "b" and "b_x_test"
"divergent",
)
}
if typeparams.Enabled {
pkgs = append(pkgs, "typeparams")
}
analysistest.Run(t, testdata, tests.Analyzer, pkgs...)
}

0 comments on commit a2be0cd

Please sign in to comment.