go/analysis/passes/lostcancel: add typeparams test

testdata/src/typeparams is similar to testdata/src/a but
uses type parameters.

For golang/go#48704

Change-Id: Id6911e0e18b31a0de917835e4bf83c50adea1599
Reviewed-on: https://go-review.googlesource.com/c/tools/+/358694
Reviewed-by: Robert Findley <rfindley@google.com>
Trust: Guodong Li <guodongli@google.com>
diff --git a/go/analysis/passes/lostcancel/lostcancel_test.go b/go/analysis/passes/lostcancel/lostcancel_test.go
index a1d8f85..bda0293 100644
--- a/go/analysis/passes/lostcancel/lostcancel_test.go
+++ b/go/analysis/passes/lostcancel/lostcancel_test.go
@@ -5,13 +5,17 @@
 package lostcancel_test
 
 import (
-	"testing"
-
 	"golang.org/x/tools/go/analysis/analysistest"
 	"golang.org/x/tools/go/analysis/passes/lostcancel"
+	"golang.org/x/tools/internal/typeparams"
+	"testing"
 )
 
 func Test(t *testing.T) {
 	testdata := analysistest.TestData()
-	analysistest.Run(t, testdata, lostcancel.Analyzer, "a", "b")
+	tests := []string{"a", "b"}
+	if typeparams.Enabled {
+		tests = append(tests, "typeparams")
+	}
+	analysistest.Run(t, testdata, lostcancel.Analyzer, tests...)
 }
diff --git a/go/analysis/passes/lostcancel/testdata/src/typeparams/typeparams.go b/go/analysis/passes/lostcancel/testdata/src/typeparams/typeparams.go
new file mode 100644
index 0000000..d6d0b5f
--- /dev/null
+++ b/go/analysis/passes/lostcancel/testdata/src/typeparams/typeparams.go
@@ -0,0 +1,59 @@
+// 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.
+
+// This file contains tests for the lostcancel checker.
+
+//go:build go1.18
+
+package typeparams
+
+import (
+	"context"
+	"time"
+)
+
+var bg = context.Background()
+
+func _[T any]() {
+	var _, cancel = context.WithCancel(bg) // want `the cancel function is not used on all paths \(possible context leak\)`
+	if false {
+		_ = cancel
+	}
+} // want "this return statement may be reached without using the cancel var defined on line 19"
+
+func _[T any]() {
+	_, cancel := context.WithCancel(bg)
+	defer cancel() // ok
+}
+
+// User-defined Context that matches type "context.Context"
+type C1[P1 any, P2 any] interface {
+	Deadline() (deadline time.Time, ok P1)
+	Done() <-chan struct{}
+	Err() error
+	Value(key P2) P2
+}
+
+func _(bg C1[bool, interface{}]) {
+	ctx, _ := context.WithCancel(bg)    // want "the cancel function returned by context.WithCancel should be called, not discarded, to avoid a context leak"
+	ctx, _ = context.WithTimeout(bg, 0) // want "the cancel function returned by context.WithTimeout should be called, not discarded, to avoid a context leak"
+	_ = ctx
+}
+
+// User-defined Context that doesn't match type "context.Context"
+type C2[P any] interface {
+	WithCancel(parent C1[P, bool]) (ctx C1[P, bool], cancel func())
+}
+
+func _(c C2[interface{}]) {
+	ctx, _ := c.WithCancel(nil) // not "context.WithCancel()"
+	_ = ctx
+}
+
+// Further regression test for Go issue 16143.
+func _() {
+	type C[P any] struct{ f func() P }
+	var x C[int]
+	x.f()
+}