diff --git a/pkg/linters/uncheckedflushreturn/testdata/src/uncheckedflushreturn/uncheckedflushreturn.go b/pkg/linters/uncheckedflushreturn/testdata/src/uncheckedflushreturn/uncheckedflushreturn.go index dc6ff53e2a6..cc2a92fc9e7 100644 --- a/pkg/linters/uncheckedflushreturn/testdata/src/uncheckedflushreturn/uncheckedflushreturn.go +++ b/pkg/linters/uncheckedflushreturn/testdata/src/uncheckedflushreturn/uncheckedflushreturn.go @@ -21,6 +21,12 @@ func badBlankAssign() { _ = bw.Flush() // want `error return from Flush\(\) is discarded` } +func deferBad() { + var sb strings.Builder + bw := bufio.NewWriter(&sb) + defer bw.Flush() // want `error return from Flush\(\) is discarded` +} + func good() { var sb strings.Builder bw := bufio.NewWriter(&sb) @@ -44,3 +50,9 @@ func suppressed() { tw := tabwriter.NewWriter(&sb, 0, 0, 1, ' ', 0) tw.Flush() //nolint:uncheckedflushreturn } + +func deferSuppressed() { + var sb strings.Builder + bw := bufio.NewWriter(&sb) + defer bw.Flush() //nolint:uncheckedflushreturn +} diff --git a/pkg/linters/uncheckedflushreturn/uncheckedflushreturn.go b/pkg/linters/uncheckedflushreturn/uncheckedflushreturn.go index 8f6581d1eac..eeb0ef81d2f 100644 --- a/pkg/linters/uncheckedflushreturn/uncheckedflushreturn.go +++ b/pkg/linters/uncheckedflushreturn/uncheckedflushreturn.go @@ -42,7 +42,7 @@ func run(pass *analysis.Pass) (any, error) { return nil, err } - nodeFilter := []ast.Node{(*ast.ExprStmt)(nil), (*ast.AssignStmt)(nil)} + nodeFilter := []ast.Node{(*ast.ExprStmt)(nil), (*ast.AssignStmt)(nil), (*ast.DeferStmt)(nil)} insp.Preorder(nodeFilter, func(n ast.Node) { switch stmt := n.(type) { case *ast.ExprStmt: @@ -57,6 +57,12 @@ func run(pass *analysis.Pass) (any, error) { return } checkDiscardedFlushAssign(pass, stmt, noLintIndex) + case *ast.DeferStmt: + position := pass.Fset.PositionFor(stmt.Pos(), false) + if filecheck.ShouldSkipFilename(position.Filename, generatedFiles) { + return + } + checkDiscardedFlushDefer(pass, stmt, noLintIndex) } }) return nil, nil @@ -95,6 +101,18 @@ func checkDiscardedFlushAssign(pass *analysis.Pass, assign *ast.AssignStmt, noLi reportUncheckedFlush(pass, call, noLintIndex) } +// checkDiscardedFlushDefer flags defer x.Flush() statements where the error +// return is dropped when the deferred call executes. +func checkDiscardedFlushDefer(pass *analysis.Pass, stmt *ast.DeferStmt, noLintIndex nolint.DirectiveIndex) { + if stmt.Call == nil { + return + } + if !isFlushCallReturningError(pass, stmt.Call) { + return + } + reportUncheckedFlush(pass, stmt.Call, noLintIndex) +} + func reportUncheckedFlush(pass *analysis.Pass, call *ast.CallExpr, noLintIndex nolint.DirectiveIndex) { position := pass.Fset.PositionFor(call.Pos(), false) if nolint.HasDirectiveForLinter(position, noLintIndex, "uncheckedflushreturn") {