1// run-rustfix
2// aux-build:macro_rules.rs
3
4#![deny(clippy::try_err)]
5#![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)]
6
7#[macro_use]
8extern crate macro_rules;
9
10use std::io;
11use std::task::Poll;
12
13// Tests that a simple case works
14// Should flag `Err(err)?`
15pub fn basic_test() -> Result<i32, i32> {
16    let err: i32 = 1;
17    // To avoid warnings during rustfix
18    if true {
19        return Err(err);
20    }
21    Ok(0)
22}
23
24// Tests that `.into()` is added when appropriate
25pub fn into_test() -> Result<i32, i32> {
26    let err: u8 = 1;
27    // To avoid warnings during rustfix
28    if true {
29        return Err(err.into());
30    }
31    Ok(0)
32}
33
34// Tests that tries in general don't trigger the error
35pub fn negative_test() -> Result<i32, i32> {
36    Ok(nested_error()? + 1)
37}
38
39// Tests that `.into()` isn't added when the error type
40// matches the surrounding closure's return type, even
41// when it doesn't match the surrounding function's.
42pub fn closure_matches_test() -> Result<i32, i32> {
43    let res: Result<i32, i8> = Some(1)
44        .into_iter()
45        .map(|i| {
46            let err: i8 = 1;
47            // To avoid warnings during rustfix
48            if true {
49                return Err(err);
50            }
51            Ok(i)
52        })
53        .next()
54        .unwrap();
55
56    Ok(res?)
57}
58
59// Tests that `.into()` isn't added when the error type
60// doesn't match the surrounding closure's return type.
61pub fn closure_into_test() -> Result<i32, i32> {
62    let res: Result<i32, i16> = Some(1)
63        .into_iter()
64        .map(|i| {
65            let err: i8 = 1;
66            // To avoid warnings during rustfix
67            if true {
68                return Err(err.into());
69            }
70            Ok(i)
71        })
72        .next()
73        .unwrap();
74
75    Ok(res?)
76}
77
78fn nested_error() -> Result<i32, i32> {
79    Ok(1)
80}
81
82// Bad suggestion when in macro (see #6242)
83macro_rules! try_validation {
84    ($e: expr) => {{
85        match $e {
86            Ok(_) => 0,
87            Err(_) => return Err(1),
88        }
89    }};
90}
91
92macro_rules! ret_one {
93    () => {
94        1
95    };
96}
97
98macro_rules! try_validation_in_macro {
99    ($e: expr) => {{
100        match $e {
101            Ok(_) => 0,
102            Err(_) => return Err(ret_one!()),
103        }
104    }};
105}
106
107fn calling_macro() -> Result<i32, i32> {
108    // macro
109    try_validation!(Ok::<_, i32>(5));
110    // `Err` arg is another macro
111    try_validation_in_macro!(Ok::<_, i32>(5));
112    Ok(5)
113}
114
115fn main() {
116    basic_test().unwrap();
117    into_test().unwrap();
118    negative_test().unwrap();
119    closure_matches_test().unwrap();
120    closure_into_test().unwrap();
121    calling_macro().unwrap();
122
123    // We don't want to lint in external macros
124    try_err!();
125}
126
127macro_rules! bar {
128    () => {
129        String::from("aasdfasdfasdfa")
130    };
131}
132
133macro_rules! foo {
134    () => {
135        bar!()
136    };
137}
138
139pub fn macro_inside(fail: bool) -> Result<i32, String> {
140    if fail {
141        return Err(foo!());
142    }
143    Ok(0)
144}
145
146pub fn poll_write(n: usize) -> Poll<io::Result<usize>> {
147    if n == 0 {
148        return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))
149    } else if n == 1 {
150        return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))
151    };
152
153    Poll::Ready(Ok(n))
154}
155
156pub fn poll_next(ready: bool) -> Poll<Option<io::Result<()>>> {
157    if !ready {
158        return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))
159    }
160
161    Poll::Ready(None)
162}
163
164// Tests that `return` is not duplicated
165pub fn try_return(x: bool) -> Result<i32, i32> {
166    if x {
167        return Err(42);
168    }
169    Ok(0)
170}
171