diff --git a/pkg/linters/nilctxpassed/nilctxpassed.go b/pkg/linters/nilctxpassed/nilctxpassed.go index 90c75a472d0..2f15a6330f5 100644 --- a/pkg/linters/nilctxpassed/nilctxpassed.go +++ b/pkg/linters/nilctxpassed/nilctxpassed.go @@ -57,6 +57,11 @@ func run(pass *analysis.Pass) (any, error) { for i, arg := range call.Args { var paramType types.Type if sig.Variadic() && params.Len() > 0 && i >= params.Len()-1 { + if call.Ellipsis.IsValid() && i == len(call.Args)-1 { + // Spread call passes the whole variadic slice (e.g. f(nil...)), + // not an individual variadic element. + continue + } // Variadic: the last param is a slice; check its element type. sliceType, ok := params.At(params.Len() - 1).Type().(*types.Slice) if !ok { diff --git a/pkg/linters/nilctxpassed/testdata/src/nilctxpassed/nilctxpassed.go b/pkg/linters/nilctxpassed/testdata/src/nilctxpassed/nilctxpassed.go index b69661b94d1..fa40e9e2fc3 100644 --- a/pkg/linters/nilctxpassed/testdata/src/nilctxpassed/nilctxpassed.go +++ b/pkg/linters/nilctxpassed/testdata/src/nilctxpassed/nilctxpassed.go @@ -34,6 +34,17 @@ func BadNilVariadic() { takesVariadicCtx(nil) // want `nil passed as context\.Context; use context\.Background\(\) or context\.TODO\(\) instead` } +// not flagged: nil spread is a nil variadic slice (zero args), not a context element +func GoodNilVariadicSpread() { + takesVariadicCtx(nil...) +} + +// not flagged: existing slice spread passes slice elements +func GoodExistingVariadicSpread() { + var existing []context.Context + takesVariadicCtx(existing...) +} + // not flagged: proper context values func GoodContextBackground() { takesCtx(context.Background())