//@aux-build:proc_macros.rs #![feature(try_blocks)] #![deny(clippy::try_err)] #![allow( clippy::unnecessary_wraps, clippy::needless_question_mark, clippy::needless_return_with_question_mark )] extern crate proc_macros; use proc_macros::{external, inline_macros}; use std::io; use std::task::Poll; // Tests that a simple case works // Should flag `Err(err)?` pub fn basic_test() -> Result { let err: i32 = 1; // To avoid warnings during rustfix if true { return Err(err); } Ok(0) } // Tests that `.into()` is added when appropriate pub fn into_test() -> Result { let err: u8 = 1; // To avoid warnings during rustfix if true { return Err(err.into()); } Ok(0) } // Tests that tries in general don't trigger the error pub fn negative_test() -> Result { Ok(nested_error()? + 1) } // Tests that `.into()` isn't added when the error type // matches the surrounding closure's return type, even // when it doesn't match the surrounding function's. pub fn closure_matches_test() -> Result { let res: Result = Some(1) .into_iter() .map(|i| { let err: i8 = 1; // To avoid warnings during rustfix if true { return Err(err); } Ok(i) }) .next() .unwrap(); Ok(res?) } // Tests that `.into()` isn't added when the error type // doesn't match the surrounding closure's return type. pub fn closure_into_test() -> Result { let res: Result = Some(1) .into_iter() .map(|i| { let err: i8 = 1; // To avoid warnings during rustfix if true { return Err(err.into()); } Ok(i) }) .next() .unwrap(); Ok(res?) } fn nested_error() -> Result { Ok(1) } #[inline_macros] fn calling_macro() -> Result { // macro inline!( match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => return Err(1), } ); // `Err` arg is another macro inline!( match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => return Err(inline!(1)), } ); Ok(5) } fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); calling_macro().unwrap(); // We don't want to lint in external macros external! { pub fn try_err_fn() -> Result { let err: i32 = 1; // To avoid warnings during rustfix if true { Err(err)? } else { Ok(2) } } } } #[inline_macros] pub fn macro_inside(fail: bool) -> Result { if fail { return Err(inline!(inline!(String::from("aasdfasdfasdfa")))); } Ok(0) } pub fn poll_write(n: usize) -> Poll> { if n == 0 { return Poll::Ready(Err(io::ErrorKind::WriteZero.into())) } else if n == 1 { return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))) }; Poll::Ready(Ok(n)) } pub fn poll_next(ready: bool) -> Poll>> { if !ready { return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into()))) } Poll::Ready(None) } // Tests that `return` is not duplicated pub fn try_return(x: bool) -> Result { if x { return Err(42); } Ok(0) } // Test that the lint is suppressed in try block. pub fn try_block() -> Result<(), i32> { let _: Result<_, i32> = try { Err(1)?; }; Ok(()) }