2023-08-24 14:32:12 -05:00
|
|
|
//@aux-build: proc_macros.rs
|
2020-08-28 09:10:16 -05:00
|
|
|
#![warn(clippy::unnecessary_lazy_evaluations)]
|
|
|
|
#![allow(clippy::redundant_closure)]
|
|
|
|
#![allow(clippy::bind_instead_of_map)]
|
2020-09-24 07:49:22 -05:00
|
|
|
#![allow(clippy::map_identity)]
|
2023-07-02 07:35:19 -05:00
|
|
|
#![allow(clippy::needless_borrow)]
|
|
|
|
#![allow(clippy::unnecessary_literal_unwrap)]
|
2023-10-21 07:16:11 -05:00
|
|
|
#![allow(clippy::unit_arg)]
|
2023-12-01 11:21:58 -06:00
|
|
|
#![allow(arithmetic_overflow)]
|
|
|
|
#![allow(unconditional_panic)]
|
2023-07-02 07:35:19 -05:00
|
|
|
|
|
|
|
use std::ops::Deref;
|
2020-08-28 09:10:16 -05:00
|
|
|
|
2023-03-24 08:04:35 -05:00
|
|
|
extern crate proc_macros;
|
|
|
|
use proc_macros::with_span;
|
2022-10-06 02:44:38 -05:00
|
|
|
|
2020-08-28 09:10:16 -05:00
|
|
|
struct Deep(Option<usize>);
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)]
|
|
|
|
struct SomeStruct {
|
|
|
|
some_field: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SomeStruct {
|
|
|
|
fn return_some_field(&self) -> usize {
|
|
|
|
self.some_field
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn some_call<T: Default>() -> T {
|
|
|
|
T::default()
|
|
|
|
}
|
|
|
|
|
2022-10-06 02:44:38 -05:00
|
|
|
struct Issue9427(i32);
|
|
|
|
|
|
|
|
impl Drop for Issue9427 {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
println!("{}", self.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-01 11:29:38 -06:00
|
|
|
struct Issue9427FollowUp;
|
|
|
|
|
|
|
|
impl Drop for Issue9427FollowUp {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
panic!("side effect drop");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-11 10:27:03 -06:00
|
|
|
struct Issue9427Followup2 {
|
|
|
|
ptr: *const (),
|
|
|
|
}
|
|
|
|
impl Issue9427Followup2 {
|
|
|
|
fn from_owned(ptr: *const ()) -> Option<Self> {
|
|
|
|
(!ptr.is_null()).then(|| Self { ptr })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Drop for Issue9427Followup2 {
|
|
|
|
fn drop(&mut self) {}
|
|
|
|
}
|
|
|
|
|
2023-07-02 07:35:19 -05:00
|
|
|
struct Issue10437;
|
|
|
|
impl Deref for Issue10437 {
|
|
|
|
type Target = u32;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
|
|
println!("side effect deref");
|
|
|
|
&0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-28 09:10:16 -05:00
|
|
|
fn main() {
|
|
|
|
let astronomers_pi = 10;
|
|
|
|
let ext_arr: [usize; 1] = [2];
|
|
|
|
let ext_str = SomeStruct { some_field: 10 };
|
|
|
|
|
|
|
|
let mut opt = Some(42);
|
|
|
|
let ext_opt = Some(42);
|
|
|
|
let nested_opt = Some(Some(42));
|
|
|
|
let nested_tuple_opt = Some(Some((42, 43)));
|
2022-07-18 02:39:37 -05:00
|
|
|
let cond = true;
|
2020-08-28 09:10:16 -05:00
|
|
|
|
|
|
|
// Should lint - Option
|
|
|
|
let _ = opt.unwrap_or_else(|| 2);
|
|
|
|
let _ = opt.unwrap_or_else(|| astronomers_pi);
|
|
|
|
let _ = opt.unwrap_or_else(|| ext_str.some_field);
|
|
|
|
let _ = opt.unwrap_or_else(|| ext_arr[0]);
|
|
|
|
let _ = opt.and_then(|_| ext_opt);
|
|
|
|
let _ = opt.or_else(|| ext_opt);
|
|
|
|
let _ = opt.or_else(|| None);
|
|
|
|
let _ = opt.get_or_insert_with(|| 2);
|
|
|
|
let _ = opt.ok_or_else(|| 2);
|
2020-09-24 07:49:22 -05:00
|
|
|
let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
|
2022-07-18 02:39:37 -05:00
|
|
|
let _ = cond.then(|| astronomers_pi);
|
2023-10-21 07:16:11 -05:00
|
|
|
let _ = true.then(|| -> _ {});
|
|
|
|
let _ = true.then(|| {});
|
2020-08-28 09:10:16 -05:00
|
|
|
|
2023-07-02 07:35:19 -05:00
|
|
|
// Should lint - Builtin deref
|
|
|
|
let r = &1;
|
|
|
|
let _ = Some(1).unwrap_or_else(|| *r);
|
|
|
|
let b = Box::new(1);
|
|
|
|
let _ = Some(1).unwrap_or_else(|| *b);
|
|
|
|
// Should lint - Builtin deref through autoderef
|
|
|
|
let _ = Some(1).as_ref().unwrap_or_else(|| &r);
|
|
|
|
let _ = Some(1).as_ref().unwrap_or_else(|| &b);
|
|
|
|
|
2020-08-28 09:10:16 -05:00
|
|
|
// Cases when unwrap is not called on a simple variable
|
|
|
|
let _ = Some(10).unwrap_or_else(|| 2);
|
|
|
|
let _ = Some(10).and_then(|_| ext_opt);
|
|
|
|
let _: Option<usize> = None.or_else(|| ext_opt);
|
|
|
|
let _ = None.get_or_insert_with(|| 2);
|
|
|
|
let _: Result<usize, usize> = None.ok_or_else(|| 2);
|
|
|
|
let _: Option<usize> = None.or_else(|| None);
|
|
|
|
|
|
|
|
let mut deep = Deep(Some(42));
|
|
|
|
let _ = deep.0.unwrap_or_else(|| 2);
|
|
|
|
let _ = deep.0.and_then(|_| ext_opt);
|
|
|
|
let _ = deep.0.or_else(|| None);
|
|
|
|
let _ = deep.0.get_or_insert_with(|| 2);
|
|
|
|
let _ = deep.0.ok_or_else(|| 2);
|
|
|
|
|
|
|
|
// Should not lint - Option
|
|
|
|
let _ = opt.unwrap_or_else(|| ext_str.return_some_field());
|
|
|
|
let _ = nested_opt.unwrap_or_else(|| Some(some_call()));
|
|
|
|
let _ = nested_tuple_opt.unwrap_or_else(|| Some((some_call(), some_call())));
|
|
|
|
let _ = opt.or_else(some_call);
|
|
|
|
let _ = opt.or_else(|| some_call());
|
|
|
|
let _: Result<usize, usize> = opt.ok_or_else(|| some_call());
|
|
|
|
let _: Result<usize, usize> = opt.ok_or_else(some_call);
|
|
|
|
let _ = deep.0.get_or_insert_with(|| some_call());
|
|
|
|
let _ = deep.0.or_else(some_call);
|
|
|
|
let _ = deep.0.or_else(|| some_call());
|
2020-09-24 07:49:22 -05:00
|
|
|
let _ = opt.ok_or_else(|| ext_arr[0]);
|
2020-08-28 09:10:16 -05:00
|
|
|
|
2023-07-02 07:35:19 -05:00
|
|
|
let _ = Some(1).unwrap_or_else(|| *Issue10437); // Issue10437 has a deref impl
|
|
|
|
let _ = Some(1).unwrap_or(*Issue10437);
|
|
|
|
|
|
|
|
let _ = Some(1).as_ref().unwrap_or_else(|| &Issue10437);
|
|
|
|
let _ = Some(1).as_ref().unwrap_or(&Issue10437);
|
|
|
|
|
2022-10-06 02:44:38 -05:00
|
|
|
// Should not lint - bool
|
|
|
|
let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
|
2022-12-01 11:29:38 -06:00
|
|
|
let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop
|
2024-01-11 10:27:03 -06:00
|
|
|
let _ = false.then(|| Issue9427Followup2 { ptr: std::ptr::null() });
|
2022-10-06 02:44:38 -05:00
|
|
|
|
2020-09-24 07:49:22 -05:00
|
|
|
// should not lint, bind_instead_of_map takes priority
|
2020-08-28 09:10:16 -05:00
|
|
|
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));
|
|
|
|
let _ = Some(10).and_then(|idx| Some(idx));
|
2020-09-24 07:49:22 -05:00
|
|
|
|
|
|
|
// should lint, bind_instead_of_map doesn't apply
|
2020-08-28 09:10:16 -05:00
|
|
|
let _: Option<usize> = None.or_else(|| Some(3));
|
|
|
|
let _ = deep.0.or_else(|| Some(3));
|
|
|
|
let _ = opt.or_else(|| Some(3));
|
|
|
|
|
|
|
|
// Should lint - Result
|
|
|
|
let res: Result<usize, usize> = Err(5);
|
|
|
|
let res2: Result<usize, SomeStruct> = Err(SomeStruct { some_field: 5 });
|
|
|
|
|
|
|
|
let _ = res2.unwrap_or_else(|_| 2);
|
|
|
|
let _ = res2.unwrap_or_else(|_| astronomers_pi);
|
|
|
|
let _ = res2.unwrap_or_else(|_| ext_str.some_field);
|
|
|
|
|
|
|
|
// Should not lint - Result
|
|
|
|
let _ = res.unwrap_or_else(|err| err);
|
|
|
|
let _ = res.unwrap_or_else(|err| ext_arr[err]);
|
|
|
|
let _ = res2.unwrap_or_else(|err| err.some_field);
|
|
|
|
let _ = res2.unwrap_or_else(|err| err.return_some_field());
|
|
|
|
let _ = res2.unwrap_or_else(|_| ext_str.return_some_field());
|
|
|
|
|
2020-09-24 07:49:22 -05:00
|
|
|
// should not lint, bind_instead_of_map takes priority
|
2020-08-28 09:10:16 -05:00
|
|
|
let _: Result<usize, usize> = res.and_then(|x| Ok(x));
|
|
|
|
let _: Result<usize, usize> = res.or_else(|err| Err(err));
|
|
|
|
|
|
|
|
let _: Result<usize, usize> = res.and_then(|_| Ok(2));
|
|
|
|
let _: Result<usize, usize> = res.and_then(|_| Ok(astronomers_pi));
|
|
|
|
let _: Result<usize, usize> = res.and_then(|_| Ok(ext_str.some_field));
|
|
|
|
|
2020-09-24 07:49:22 -05:00
|
|
|
let _: Result<usize, usize> = res.or_else(|_| Err(2));
|
|
|
|
let _: Result<usize, usize> = res.or_else(|_| Err(astronomers_pi));
|
|
|
|
let _: Result<usize, usize> = res.or_else(|_| Err(ext_str.some_field));
|
|
|
|
|
|
|
|
// should lint, bind_instead_of_map doesn't apply
|
2020-08-28 09:10:16 -05:00
|
|
|
let _: Result<usize, usize> = res.and_then(|_| Err(2));
|
|
|
|
let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
|
|
|
|
let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
|
|
|
|
|
|
|
|
let _: Result<usize, usize> = res.or_else(|_| Ok(2));
|
|
|
|
let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
|
|
|
|
let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
|
2022-03-24 08:50:04 -05:00
|
|
|
let _: Result<usize, usize> = res.
|
2022-12-01 11:29:38 -06:00
|
|
|
// some lines
|
|
|
|
// some lines
|
|
|
|
// some lines
|
|
|
|
// some lines
|
|
|
|
// some lines
|
|
|
|
// some lines
|
|
|
|
or_else(|_| Ok(ext_str.some_field));
|
2020-08-28 09:10:16 -05:00
|
|
|
|
2020-09-24 07:49:22 -05:00
|
|
|
// neither bind_instead_of_map nor unnecessary_lazy_eval applies here
|
|
|
|
let _: Result<usize, usize> = res.and_then(|x| Err(x));
|
|
|
|
let _: Result<usize, usize> = res.or_else(|err| Ok(err));
|
2020-08-28 09:10:16 -05:00
|
|
|
}
|
2022-10-06 02:44:38 -05:00
|
|
|
|
|
|
|
#[allow(unused)]
|
|
|
|
fn issue9485() {
|
|
|
|
// should not lint, is in proc macro
|
|
|
|
with_span!(span Some(42).unwrap_or_else(|| 2););
|
|
|
|
}
|
2023-12-01 11:21:58 -06:00
|
|
|
|
|
|
|
fn issue9422(x: usize) -> Option<usize> {
|
|
|
|
(x >= 5).then(|| x - 5)
|
|
|
|
// (x >= 5).then_some(x - 5) // clippy suggestion panics
|
|
|
|
}
|
|
|
|
|
|
|
|
fn panicky_arithmetic_ops(x: usize, y: isize) {
|
|
|
|
#![allow(clippy::identity_op, clippy::eq_op)]
|
|
|
|
|
|
|
|
// See comments in `eager_or_lazy.rs` for the rules that this is meant to follow
|
|
|
|
|
|
|
|
let _x = false.then(|| i32::MAX + 1);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| i32::MAX * 2);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| i32::MAX - 1);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| i32::MIN - 1);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| 255u8 << 7);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| 255u8 << 8);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| 255u8 >> 8);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| 255u8 >> x);
|
|
|
|
let _x = false.then(|| i32::MAX + -1);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| -i32::MAX);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| -i32::MIN);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| -y);
|
|
|
|
let _x = false.then(|| 255 >> -7);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| 255 << -1);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| 1 / 0);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| x << -1);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| x << 2);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| x + x);
|
|
|
|
let _x = false.then(|| x * x);
|
|
|
|
let _x = false.then(|| x - x);
|
|
|
|
let _x = false.then(|| x / x);
|
|
|
|
let _x = false.then(|| x % x);
|
|
|
|
let _x = false.then(|| x + 1);
|
|
|
|
let _x = false.then(|| 1 + x);
|
|
|
|
|
|
|
|
let _x = false.then(|| x / 0);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| x % 0);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| y / -1);
|
|
|
|
let _x = false.then(|| 1 / -1);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| i32::MIN / -1);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| i32::MIN / x as i32);
|
|
|
|
let _x = false.then(|| i32::MIN / 0);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| 4 / 2);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
let _x = false.then(|| 1 / x);
|
|
|
|
|
|
|
|
// const eval doesn't read variables, but floating point math never panics, so we can still emit a
|
|
|
|
// warning
|
|
|
|
let f1 = 1.0;
|
|
|
|
let f2 = 2.0;
|
|
|
|
let _x = false.then(|| f1 + f2);
|
|
|
|
//~^ ERROR: unnecessary closure used with `bool::then`
|
|
|
|
}
|