diff --git a/clippy_lints/src/unused_io_amount.rs b/clippy_lints/src/unused_io_amount.rs index 5e8e530f480f..3387f35bac3d 100644 --- a/clippy_lints/src/unused_io_amount.rs +++ b/clippy_lints/src/unused_io_amount.rs @@ -47,25 +47,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { func.kind, hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _)) ) { - check_method_call(cx, &args[0], expr); + check_map_error(cx, &args[0], expr); } } else { - check_method_call(cx, res, expr); + check_map_error(cx, res, expr); } }, - hir::ExprKind::MethodCall(path, _, args, _) => match &*path.ident.as_str() { "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => { - check_method_call(cx, &args[0], expr); + check_map_error(cx, &args[0], expr); }, _ => (), }, - _ => (), } } } +fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { + let mut call = call; + while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind { + if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") { + call = &args[0]; + } else { + break; + } + } + check_method_call(cx, call, expr); +} + fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { if let hir::ExprKind::MethodCall(path, _, _, _) = call.kind { let symbol = &*path.ident.as_str(); diff --git a/tests/ui/unused_io_amount.rs b/tests/ui/unused_io_amount.rs index ebaba9629db1..8b141e25942d 100644 --- a/tests/ui/unused_io_amount.rs +++ b/tests/ui/unused_io_amount.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![warn(clippy::unused_io_amount)] -use std::io; +use std::io::{self, Read}; fn question_mark(s: &mut T) -> io::Result<()> { s.write(b"test")?; @@ -22,4 +22,43 @@ fn vectored(s: &mut T) -> io::Result<()> { Ok(()) } +fn ok(file: &str) -> Option<()> { + let mut reader = std::fs::File::open(file).ok()?; + let mut result = [0u8; 0]; + reader.read(&mut result).ok()?; + Some(()) +} + +#[allow(clippy::redundant_closure)] +#[allow(clippy::bind_instead_of_map)] +fn or_else(file: &str) -> io::Result<()> { + let mut reader = std::fs::File::open(file)?; + let mut result = [0u8; 0]; + reader.read(&mut result).or_else(|err| Err(err))?; + Ok(()) +} + +#[derive(Debug)] +enum Error { + Kind, +} + +fn or(file: &str) -> Result<(), Error> { + let mut reader = std::fs::File::open(file).unwrap(); + let mut result = [0u8; 0]; + reader.read(&mut result).or(Err(Error::Kind))?; + Ok(()) +} + +fn combine_or(file: &str) -> Result<(), Error> { + let mut reader = std::fs::File::open(file).unwrap(); + let mut result = [0u8; 0]; + reader + .read(&mut result) + .or(Err(Error::Kind)) + .or(Err(Error::Kind)) + .expect("error"); + Ok(()) +} + fn main() {} diff --git a/tests/ui/unused_io_amount.stderr b/tests/ui/unused_io_amount.stderr index 5219d63980b4..d8dfc0e5a798 100644 --- a/tests/ui/unused_io_amount.stderr +++ b/tests/ui/unused_io_amount.stderr @@ -36,5 +36,33 @@ error: written amount is not handled LL | s.write_vectored(&[io::IoSlice::new(&[])])?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 6 previous errors +error: read amount is not handled. Use `Read::read_exact` instead + --> $DIR/unused_io_amount.rs:28:5 + | +LL | reader.read(&mut result).ok()?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: read amount is not handled. Use `Read::read_exact` instead + --> $DIR/unused_io_amount.rs:37:5 + | +LL | reader.read(&mut result).or_else(|err| Err(err))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: read amount is not handled. Use `Read::read_exact` instead + --> $DIR/unused_io_amount.rs:49:5 + | +LL | reader.read(&mut result).or(Err(Error::Kind))?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: read amount is not handled. Use `Read::read_exact` instead + --> $DIR/unused_io_amount.rs:56:5 + | +LL | / reader +LL | | .read(&mut result) +LL | | .or(Err(Error::Kind)) +LL | | .or(Err(Error::Kind)) +LL | | .expect("error"); + | |________________________^ + +error: aborting due to 10 previous errors