diff --git a/go/analysis/passes/lostcancel/doc.go b/go/analysis/passes/lostcancel/doc.go index 28bf6c7e264..f789bdc8111 100644 --- a/go/analysis/passes/lostcancel/doc.go +++ b/go/analysis/passes/lostcancel/doc.go @@ -10,7 +10,7 @@ // lostcancel: check cancel func returned by context.WithCancel is called // // The cancellation function returned by context.WithCancel, WithTimeout, -// and WithDeadline must be called or the new context will remain live -// until its parent context is cancelled. +// WithDeadline and variants such as WithCancelCause must be called, +// or the new context will remain live until its parent context is cancelled. // (The background context is never cancelled.) package lostcancel diff --git a/go/analysis/passes/lostcancel/lostcancel.go b/go/analysis/passes/lostcancel/lostcancel.go index bf56a5c06f6..26fdc1206f8 100644 --- a/go/analysis/passes/lostcancel/lostcancel.go +++ b/go/analysis/passes/lostcancel/lostcancel.go @@ -198,7 +198,9 @@ func isContextWithCancel(info *types.Info, n ast.Node) bool { return false } switch sel.Sel.Name { - case "WithCancel", "WithTimeout", "WithDeadline": + case "WithCancel", "WithCancelCause", + "WithTimeout", "WithTimeoutCause", + "WithDeadline", "WithDeadlineCause": default: return false } diff --git a/go/analysis/passes/lostcancel/testdata/src/typeparams/typeparams.go b/go/analysis/passes/lostcancel/testdata/src/typeparams/typeparams.go index 1030ba4c1be..fd2f487f9e0 100644 --- a/go/analysis/passes/lostcancel/testdata/src/typeparams/typeparams.go +++ b/go/analysis/passes/lostcancel/testdata/src/typeparams/typeparams.go @@ -8,9 +8,14 @@ package typeparams import ( "context" + "io" "time" ) +// +// These comment lines are ballast to ensure +// that this is L17. Add/remove as needed. + var bg = context.Background() func _[T any]() { @@ -18,7 +23,7 @@ func _[T any]() { if false { _ = cancel } -} // want "this return statement may be reached without using the cancel var defined on line 17" +} // want "this return statement may be reached without using the cancel var defined on line 22" func _[T any]() { _, cancel := context.WithCancel(bg) @@ -55,3 +60,16 @@ func _() { var x C[int] x.f() } + +func withCancelCause(maybe bool) { + { + _, cancel := context.WithCancelCause(bg) + defer cancel(io.EOF) // ok + } + { + _, cancel := context.WithCancelCause(bg) // want "the cancel function is not used on all paths \\(possible context leak\\)" + if maybe { + cancel(io.EOF) + } + } +} // want "this return statement may be reached without using the cancel var defined on line 70" diff --git a/gopls/doc/analyzers.md b/gopls/doc/analyzers.md index ec2b6316374..f7083bb0e89 100644 --- a/gopls/doc/analyzers.md +++ b/gopls/doc/analyzers.md @@ -428,8 +428,8 @@ Package documentation: [loopclosure](https://pkg.go.dev/golang.org/x/tools/go/an The cancellation function returned by context.WithCancel, WithTimeout, -and WithDeadline must be called or the new context will remain live -until its parent context is cancelled. +WithDeadline and variants such as WithCancelCause must be called, +or the new context will remain live until its parent context is cancelled. (The background context is never cancelled.) Default: on. diff --git a/gopls/internal/doc/api.json b/gopls/internal/doc/api.json index 6b8873cf817..298c3ab49e1 100644 --- a/gopls/internal/doc/api.json +++ b/gopls/internal/doc/api.json @@ -466,7 +466,7 @@ }, { "Name": "\"lostcancel\"", - "Doc": "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nand WithDeadline must be called or the new context will remain live\nuntil its parent context is cancelled.\n(The background context is never cancelled.)", + "Doc": "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nWithDeadline and variants such as WithCancelCause must be called,\nor the new context will remain live until its parent context is cancelled.\n(The background context is never cancelled.)", "Default": "true" }, { @@ -1114,7 +1114,7 @@ }, { "Name": "lostcancel", - "Doc": "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nand WithDeadline must be called or the new context will remain live\nuntil its parent context is cancelled.\n(The background context is never cancelled.)", + "Doc": "check cancel func returned by context.WithCancel is called\n\nThe cancellation function returned by context.WithCancel, WithTimeout,\nWithDeadline and variants such as WithCancelCause must be called,\nor the new context will remain live until its parent context is cancelled.\n(The background context is never cancelled.)", "URL": "https://pkg.go.dev/golang.org/x/tools/go/analysis/passes/lostcancel", "Default": true },