Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Philipp Krones 2024-01-11 17:19:53 +01:00
commit 2c0cea7cbc
No known key found for this signature in database
GPG key ID: 1CA0DF2AF59D68A5
170 changed files with 5217 additions and 855 deletions

View file

@ -19,8 +19,8 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
error: hardcoded path to a diagnostic item
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
LL | const OPS_MOD: [&str; 5] = ["core", "ops"];
| ^^^^^^^^^^^^^^^
LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: convert all references to use `sym::deref_method`

View file

@ -0,0 +1 @@
pub-underscore-fields-behavior = "AllPubFields"

View file

@ -0,0 +1 @@
pub-underscore-fields-behavior = "PublicallyExported"

View file

@ -0,0 +1,60 @@
error: field marked as public but also inferred as unused because it's prefixed with `_`
--> $DIR/pub_underscore_fields.rs:15:9
|
LL | pub _b: u8,
| ^^^^^^
|
= help: consider removing the underscore, or making the field private
= note: `-D clippy::pub-underscore-fields` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::pub_underscore_fields)]`
error: field marked as public but also inferred as unused because it's prefixed with `_`
--> $DIR/pub_underscore_fields.rs:23:13
|
LL | pub(in crate::inner) _f: Option<()>,
| ^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider removing the underscore, or making the field private
error: field marked as public but also inferred as unused because it's prefixed with `_`
--> $DIR/pub_underscore_fields.rs:27:13
|
LL | pub _g: String,
| ^^^^^^
|
= help: consider removing the underscore, or making the field private
error: field marked as public but also inferred as unused because it's prefixed with `_`
--> $DIR/pub_underscore_fields.rs:34:9
|
LL | pub _a: usize,
| ^^^^^^
|
= help: consider removing the underscore, or making the field private
error: field marked as public but also inferred as unused because it's prefixed with `_`
--> $DIR/pub_underscore_fields.rs:41:9
|
LL | pub _c: i64,
| ^^^^^^
|
= help: consider removing the underscore, or making the field private
error: field marked as public but also inferred as unused because it's prefixed with `_`
--> $DIR/pub_underscore_fields.rs:44:9
|
LL | pub _e: Option<u8>,
| ^^^^^^
|
= help: consider removing the underscore, or making the field private
error: field marked as public but also inferred as unused because it's prefixed with `_`
--> $DIR/pub_underscore_fields.rs:57:9
|
LL | pub(crate) _b: Option<String>,
| ^^^^^^^^^^^^^
|
= help: consider removing the underscore, or making the field private
error: aborting due to 7 previous errors

View file

@ -0,0 +1,12 @@
error: field marked as public but also inferred as unused because it's prefixed with `_`
--> $DIR/pub_underscore_fields.rs:15:9
|
LL | pub _b: u8,
| ^^^^^^
|
= help: consider removing the underscore, or making the field private
= note: `-D clippy::pub-underscore-fields` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::pub_underscore_fields)]`
error: aborting due to 1 previous error

View file

@ -0,0 +1,66 @@
//@revisions: exported all_pub_fields
//@[all_pub_fields] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/pub_underscore_fields/all_pub_fields
//@[exported] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/pub_underscore_fields/exported
#![allow(unused)]
#![warn(clippy::pub_underscore_fields)]
use std::marker::PhantomData;
pub mod inner {
use std::marker;
pub struct PubSuper {
pub(super) a: usize,
pub _b: u8,
_c: i32,
pub _mark: marker::PhantomData<u8>,
}
mod inner2 {
pub struct PubModVisibility {
pub(in crate::inner) e: bool,
pub(in crate::inner) _f: Option<()>,
}
struct PrivateStructPubField {
pub _g: String,
}
}
}
fn main() {
pub struct StructWithOneViolation {
pub _a: usize,
}
// should handle structs with multiple violations
pub struct StructWithMultipleViolations {
a: u8,
_b: usize,
pub _c: i64,
#[doc(hidden)]
pub d: String,
pub _e: Option<u8>,
}
// shouldn't warn on anonymous fields
pub struct AnonymousFields(pub usize, i32);
// don't warn on empty structs
pub struct Empty1;
pub struct Empty2();
pub struct Empty3 {};
pub struct PubCrate {
pub(crate) a: String,
pub(crate) _b: Option<String>,
}
// shouldn't warn on fields named pub
pub struct NamedPub {
r#pub: bool,
_pub: String,
pub(crate) _mark: PhantomData<u8>,
}
}

View file

@ -49,6 +49,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
missing-docs-in-crate-items
msrv
pass-by-value-size-limit
pub-underscore-fields-behavior
semicolon-inside-block-ignore-singleline
semicolon-outside-block-ignore-multiline
single-char-binding-names-threshold
@ -124,6 +125,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
missing-docs-in-crate-items
msrv
pass-by-value-size-limit
pub-underscore-fields-behavior
semicolon-inside-block-ignore-singleline
semicolon-outside-block-ignore-multiline
single-char-binding-names-threshold

View file

@ -17,7 +17,7 @@ fn main() {
with_span!(
span
fn coverting() {
fn converting() {
let x = 0u32 as u64;
}
);

View file

@ -365,3 +365,52 @@ fn avoid_subtract_overflow(q: u32) {
fn issue11426() {
(&42u8 >> 0xa9008fb6c9d81e42_0e25730562a601c8_u128) as usize;
}
fn issue11642() {
fn square(x: i16) -> u32 {
let x = x as i32;
(x * x) as u32;
x.pow(2) as u32;
(-2_i32).pow(2) as u32
}
let _a = |x: i32| -> u32 { (x * x * x * x) as u32 };
(-2_i32).pow(3) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
let x: i32 = 10;
(x * x) as u32;
(x * x * x) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
let y: i16 = -2;
(y * y * y * y * -2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
(y * y * y * y * 2) as u16;
(y * y * y * 2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
(y * y * y * -2) as u16;
//~^ ERROR: casting `i16` to `u16` may lose the sign of the value
fn foo(a: i32, b: i32, c: i32) -> u32 {
(a * a * b * b * c * c) as u32;
(a * b * c) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(a * -b * c) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(a * b * c * c) as u32;
(a * -2) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(a * b * c * -2) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(a / b) as u32;
(a / b * c) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(a / b + b * c) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
a.pow(3) as u32;
//~^ ERROR: casting `i32` to `u32` may lose the sign of the value
(a.abs() * b.pow(2) / c.abs()) as u32
}
}

View file

@ -444,5 +444,77 @@ help: ... or use `try_from` and handle the error accordingly
LL | let c = u8::try_from(q / 1000);
| ~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to 51 previous errors
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:379:5
|
LL | (-2_i32).pow(3) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:384:5
|
LL | (x * x * x) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> $DIR/cast.rs:388:5
|
LL | (y * y * y * y * -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> $DIR/cast.rs:391:5
|
LL | (y * y * y * 2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i16` to `u16` may lose the sign of the value
--> $DIR/cast.rs:393:5
|
LL | (y * y * y * -2) as u16;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:398:9
|
LL | (a * b * c) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:400:9
|
LL | (a * -b * c) as u32;
| ^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:403:9
|
LL | (a * -2) as u32;
| ^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:405:9
|
LL | (a * b * c * -2) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:408:9
|
LL | (a / b * c) as u32;
| ^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:410:9
|
LL | (a / b + b * c) as u32;
| ^^^^^^^^^^^^^^^^^^^^^^
error: casting `i32` to `u32` may lose the sign of the value
--> $DIR/cast.rs:412:9
|
LL | a.pow(3) as u32;
| ^^^^^^^^^^^^^^^
error: aborting due to 63 previous errors

View file

@ -1,10 +0,0 @@
#![warn(clippy::let_unit_value)]
fn f() {}
static FN: fn() = f;
fn main() {
FN();
//~^ ERROR: this let-binding has unit value
//~| NOTE: `-D clippy::let-unit-value` implied by `-D warnings`
}

View file

@ -5,6 +5,4 @@ static FN: fn() = f;
fn main() {
let _: () = FN();
//~^ ERROR: this let-binding has unit value
//~| NOTE: `-D clippy::let-unit-value` implied by `-D warnings`
}

View file

@ -1,11 +0,0 @@
error: this let-binding has unit value
--> $DIR/ice-8821.rs:7:5
|
LL | let _: () = FN();
| ^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `FN();`
|
= note: `-D clippy::let-unit-value` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
error: aborting due to 1 previous error

View file

@ -73,9 +73,7 @@ mod nested_local {
mod function_def {
fn ret_f64() -> f64 {
// Even though the output type is specified,
// this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
1.0_f64
1.
}
fn test() {

View file

@ -73,8 +73,6 @@ mod nested_local {
mod function_def {
fn ret_f64() -> f64 {
// Even though the output type is specified,
// this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
1.
}

View file

@ -86,66 +86,60 @@ LL | let y = 1.;
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:78:9
|
LL | 1.
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:84:27
--> $DIR/default_numeric_fallback_f64.rs:82:27
|
LL | let f = || -> _ { 1. };
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:88:29
--> $DIR/default_numeric_fallback_f64.rs:86:29
|
LL | let f = || -> f64 { 1. };
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:102:21
--> $DIR/default_numeric_fallback_f64.rs:100:21
|
LL | generic_arg(1.);
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:105:32
--> $DIR/default_numeric_fallback_f64.rs:103:32
|
LL | let x: _ = generic_arg(1.);
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:123:28
--> $DIR/default_numeric_fallback_f64.rs:121:28
|
LL | GenericStruct { x: 1. };
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:126:36
--> $DIR/default_numeric_fallback_f64.rs:124:36
|
LL | let _ = GenericStruct { x: 1. };
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:144:24
--> $DIR/default_numeric_fallback_f64.rs:142:24
|
LL | GenericEnum::X(1.);
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:164:23
--> $DIR/default_numeric_fallback_f64.rs:162:23
|
LL | s.generic_arg(1.);
| ^^ help: consider adding suffix: `1.0_f64`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_f64.rs:174:25
--> $DIR/default_numeric_fallback_f64.rs:172:25
|
LL | inline!(let x = 22.;);
| ^^^ help: consider adding suffix: `22.0_f64`
|
= note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 24 previous errors
error: aborting due to 23 previous errors

View file

@ -74,9 +74,7 @@ mod nested_local {
mod function_def {
fn ret_i32() -> i32 {
// Even though the output type is specified,
// this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
1_i32
1
}
fn test() {
@ -186,4 +184,36 @@ fn check_expect_suppression() {
let x = 21;
}
mod type_already_inferred {
// Should NOT lint if bound to return type
fn ret_i32() -> i32 {
1
}
// Should NOT lint if bound to return type
fn ret_if_i32(b: bool) -> i32 {
if b { 100 } else { 0 }
}
// Should NOT lint if bound to return type
fn ret_i32_tuple() -> (i32, i32) {
(0, 1)
}
// Should NOT lint if bound to return type
fn ret_stmt(b: bool) -> (i32, i32) {
if b {
return (0, 1);
}
(0, 0)
}
#[allow(clippy::useless_vec)]
fn vec_macro() {
// Should NOT lint in `vec!` call if the type was already stated
let data_i32: Vec<i32> = vec![1, 2, 3];
let data_i32 = vec![1_i32, 2_i32, 3_i32];
}
}
fn main() {}

View file

@ -74,8 +74,6 @@ mod nested_local {
mod function_def {
fn ret_i32() -> i32 {
// Even though the output type is specified,
// this unsuffixed literal is linted to reduce heuristics and keep codebase simple.
1
}
@ -186,4 +184,36 @@ fn check_expect_suppression() {
let x = 21;
}
mod type_already_inferred {
// Should NOT lint if bound to return type
fn ret_i32() -> i32 {
1
}
// Should NOT lint if bound to return type
fn ret_if_i32(b: bool) -> i32 {
if b { 100 } else { 0 }
}
// Should NOT lint if bound to return type
fn ret_i32_tuple() -> (i32, i32) {
(0, 1)
}
// Should NOT lint if bound to return type
fn ret_stmt(b: bool) -> (i32, i32) {
if b {
return (0, 1);
}
(0, 0)
}
#[allow(clippy::useless_vec)]
fn vec_macro() {
// Should NOT lint in `vec!` call if the type was already stated
let data_i32: Vec<i32> = vec![1, 2, 3];
let data_i32 = vec![1, 2, 3];
}
}
fn main() {}

View file

@ -98,66 +98,78 @@ LL | let y = 1;
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:79:9
|
LL | 1
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:85:27
--> $DIR/default_numeric_fallback_i32.rs:83:27
|
LL | let f = || -> _ { 1 };
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:89:29
--> $DIR/default_numeric_fallback_i32.rs:87:29
|
LL | let f = || -> i32 { 1 };
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:103:21
--> $DIR/default_numeric_fallback_i32.rs:101:21
|
LL | generic_arg(1);
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:106:32
--> $DIR/default_numeric_fallback_i32.rs:104:32
|
LL | let x: _ = generic_arg(1);
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:124:28
--> $DIR/default_numeric_fallback_i32.rs:122:28
|
LL | GenericStruct { x: 1 };
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:127:36
--> $DIR/default_numeric_fallback_i32.rs:125:36
|
LL | let _ = GenericStruct { x: 1 };
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:145:24
--> $DIR/default_numeric_fallback_i32.rs:143:24
|
LL | GenericEnum::X(1);
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:165:23
--> $DIR/default_numeric_fallback_i32.rs:163:23
|
LL | s.generic_arg(1);
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:175:25
--> $DIR/default_numeric_fallback_i32.rs:173:25
|
LL | inline!(let x = 22;);
| ^^ help: consider adding suffix: `22_i32`
|
= note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 26 previous errors
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:215:29
|
LL | let data_i32 = vec![1, 2, 3];
| ^ help: consider adding suffix: `1_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:215:32
|
LL | let data_i32 = vec![1, 2, 3];
| ^ help: consider adding suffix: `2_i32`
error: default numeric fallback might occur
--> $DIR/default_numeric_fallback_i32.rs:215:35
|
LL | let data_i32 = vec![1, 2, 3];
| ^ help: consider adding suffix: `3_i32`
error: aborting due to 28 previous errors

View file

@ -1,7 +1,6 @@
#![allow(clippy::non_canonical_clone_impl, clippy::non_canonical_partial_ord_impl, dead_code)]
#![warn(clippy::expl_impl_clone_on_copy)]
#[derive(Copy)]
struct Qux;

View file

@ -1,5 +1,5 @@
error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:8:1
--> $DIR/derive.rs:7:1
|
LL | / impl Clone for Qux {
LL | |
@ -10,7 +10,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:8:1
--> $DIR/derive.rs:7:1
|
LL | / impl Clone for Qux {
LL | |
@ -23,7 +23,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:33:1
--> $DIR/derive.rs:32:1
|
LL | / impl<'a> Clone for Lt<'a> {
LL | |
@ -34,7 +34,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:33:1
--> $DIR/derive.rs:32:1
|
LL | / impl<'a> Clone for Lt<'a> {
LL | |
@ -45,7 +45,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:45:1
--> $DIR/derive.rs:44:1
|
LL | / impl Clone for BigArray {
LL | |
@ -56,7 +56,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:45:1
--> $DIR/derive.rs:44:1
|
LL | / impl Clone for BigArray {
LL | |
@ -67,7 +67,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:57:1
--> $DIR/derive.rs:56:1
|
LL | / impl Clone for FnPtr {
LL | |
@ -78,7 +78,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:57:1
--> $DIR/derive.rs:56:1
|
LL | / impl Clone for FnPtr {
LL | |
@ -89,7 +89,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
--> $DIR/derive.rs:78:1
--> $DIR/derive.rs:77:1
|
LL | / impl<T: Clone> Clone for Generic2<T> {
LL | |
@ -100,7 +100,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> $DIR/derive.rs:78:1
--> $DIR/derive.rs:77:1
|
LL | / impl<T: Clone> Clone for Generic2<T> {
LL | |

View file

@ -12,16 +12,49 @@ enum Opcode {
Div = 3,
}
struct Data {
foo: &'static [u8],
bar: &'static [u8],
}
fn int_to_opcode(op: u8) -> Option<Opcode> {
(op < 4).then(|| unsafe { std::mem::transmute(op) })
}
fn f(op: u8, unrelated: u8) {
fn f(op: u8, op2: Data, unrelated: u8) {
true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
(unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
(op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
(op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
(op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
let _: Option<Opcode> = (op > 0 && op < 10).then(|| unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (op > 0 && op < 10 && unrelated == 0).then(|| unsafe { std::mem::transmute(op) });
// lint even when the transmutable goes through field/array accesses
let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then(|| unsafe { std::mem::transmute(op2.foo[0]) });
// don't lint: wrong index used in the transmute
let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[1]) });
// don't lint: no check for the transmutable in the condition
let _: Option<Opcode> = (op2.foo[0] > 0 && op2.bar[1] < 10).then_some(unsafe { std::mem::transmute(op2.bar[0]) });
// don't lint: wrong variable
let _: Option<Opcode> = (op2.foo[0] > 0 && op2.bar[1] < 10).then_some(unsafe { std::mem::transmute(op) });
// range contains checks
let _: Option<Opcode> = (1..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = ((1..=3).contains(&op) || op == 4).then(|| unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (1..3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (1..).contains(&op).then(|| unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (..3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
// unrelated binding in contains
let _: Option<Opcode> = (1..=3)
.contains(&unrelated)
.then_some(unsafe { std::mem::transmute(op) });
}
unsafe fn f2(op: u8) {

View file

@ -12,16 +12,49 @@ enum Opcode {
Div = 3,
}
struct Data {
foo: &'static [u8],
bar: &'static [u8],
}
fn int_to_opcode(op: u8) -> Option<Opcode> {
(op < 4).then_some(unsafe { std::mem::transmute(op) })
}
fn f(op: u8, unrelated: u8) {
fn f(op: u8, op2: Data, unrelated: u8) {
true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
(unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
(op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
(op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
(op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
let _: Option<Opcode> = (op > 0 && op < 10).then_some(unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (op > 0 && op < 10 && unrelated == 0).then_some(unsafe { std::mem::transmute(op) });
// lint even when the transmutable goes through field/array accesses
let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[0]) });
// don't lint: wrong index used in the transmute
let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[1]) });
// don't lint: no check for the transmutable in the condition
let _: Option<Opcode> = (op2.foo[0] > 0 && op2.bar[1] < 10).then_some(unsafe { std::mem::transmute(op2.bar[0]) });
// don't lint: wrong variable
let _: Option<Opcode> = (op2.foo[0] > 0 && op2.bar[1] < 10).then_some(unsafe { std::mem::transmute(op) });
// range contains checks
let _: Option<Opcode> = (1..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = ((1..=3).contains(&op) || op == 4).then_some(unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (1..3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (1..).contains(&op).then_some(unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (..3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
let _: Option<Opcode> = (..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
// unrelated binding in contains
let _: Option<Opcode> = (1..=3)
.contains(&unrelated)
.then_some(unsafe { std::mem::transmute(op) });
}
unsafe fn f2(op: u8) {

View file

@ -1,5 +1,5 @@
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:16:33
--> $DIR/eager_transmute.rs:21:33
|
LL | (op < 4).then_some(unsafe { std::mem::transmute(op) })
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -12,7 +12,7 @@ LL | (op < 4).then(|| unsafe { std::mem::transmute(op) })
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:22:33
--> $DIR/eager_transmute.rs:27:33
|
LL | (op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -23,7 +23,7 @@ LL | (op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:23:33
--> $DIR/eager_transmute.rs:28:33
|
LL | (op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -34,7 +34,7 @@ LL | (op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:24:34
--> $DIR/eager_transmute.rs:29:34
|
LL | (op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -45,7 +45,106 @@ LL | (op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:28:24
--> $DIR/eager_transmute.rs:31:68
|
LL | let _: Option<Opcode> = (op > 0 && op < 10).then_some(unsafe { std::mem::transmute(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = (op > 0 && op < 10).then(|| unsafe { std::mem::transmute(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:32:86
|
LL | let _: Option<Opcode> = (op > 0 && op < 10 && unrelated == 0).then_some(unsafe { std::mem::transmute(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = (op > 0 && op < 10 && unrelated == 0).then(|| unsafe { std::mem::transmute(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:35:84
|
LL | let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[0]) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = (op2.foo[0] > 0 && op2.foo[0] < 10).then(|| unsafe { std::mem::transmute(op2.foo[0]) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:47:70
|
LL | let _: Option<Opcode> = (1..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = (1..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:48:83
|
LL | let _: Option<Opcode> = ((1..=3).contains(&op) || op == 4).then_some(unsafe { std::mem::transmute(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = ((1..=3).contains(&op) || op == 4).then(|| unsafe { std::mem::transmute(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:49:69
|
LL | let _: Option<Opcode> = (1..3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = (1..3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:50:68
|
LL | let _: Option<Opcode> = (1..).contains(&op).then_some(unsafe { std::mem::transmute(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = (1..).contains(&op).then(|| unsafe { std::mem::transmute(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:51:68
|
LL | let _: Option<Opcode> = (..3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = (..3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:52:69
|
LL | let _: Option<Opcode> = (..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) });
| ^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
LL | let _: Option<Opcode> = (..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) });
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:61:24
|
LL | (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -56,7 +155,7 @@ LL | (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:57:60
--> $DIR/eager_transmute.rs:90:60
|
LL | let _: Option<NonZeroU8> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -67,7 +166,7 @@ LL | let _: Option<NonZeroU8> = (v1 > 0).then(|| unsafe { std::mem::transmut
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:63:86
--> $DIR/eager_transmute.rs:96:86
|
LL | let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -78,7 +177,7 @@ LL | let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| u
| ~~~~ ++
error: this transmute is always evaluated eagerly, even if the condition is false
--> $DIR/eager_transmute.rs:69:93
--> $DIR/eager_transmute.rs:102:93
|
LL | let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
| ^^^^^^^^^^^^^^^^^^^^^^^
@ -88,5 +187,5 @@ help: consider using `bool::then` to only transmute if the condition holds
LL | let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
| ~~~~ ++
error: aborting due to 8 previous errors
error: aborting due to 17 previous errors

View file

@ -0,0 +1,27 @@
#![warn(clippy::empty_enum_variants_with_brackets)]
#![allow(dead_code)]
pub enum PublicTestEnum {
NonEmptyBraces { x: i32, y: i32 }, // No error
NonEmptyParentheses(i32, i32), // No error
EmptyBraces, //~ ERROR: enum variant has empty brackets
EmptyParentheses, //~ ERROR: enum variant has empty brackets
}
enum TestEnum {
NonEmptyBraces { x: i32, y: i32 }, // No error
NonEmptyParentheses(i32, i32), // No error
EmptyBraces, //~ ERROR: enum variant has empty brackets
EmptyParentheses, //~ ERROR: enum variant has empty brackets
AnotherEnum, // No error
}
enum TestEnumWithFeatures {
NonEmptyBraces {
#[cfg(feature = "thisisneverenabled")]
x: i32,
}, // No error
NonEmptyParentheses(#[cfg(feature = "thisisneverenabled")] i32), // No error
}
fn main() {}

View file

@ -0,0 +1,27 @@
#![warn(clippy::empty_enum_variants_with_brackets)]
#![allow(dead_code)]
pub enum PublicTestEnum {
NonEmptyBraces { x: i32, y: i32 }, // No error
NonEmptyParentheses(i32, i32), // No error
EmptyBraces {}, //~ ERROR: enum variant has empty brackets
EmptyParentheses(), //~ ERROR: enum variant has empty brackets
}
enum TestEnum {
NonEmptyBraces { x: i32, y: i32 }, // No error
NonEmptyParentheses(i32, i32), // No error
EmptyBraces {}, //~ ERROR: enum variant has empty brackets
EmptyParentheses(), //~ ERROR: enum variant has empty brackets
AnotherEnum, // No error
}
enum TestEnumWithFeatures {
NonEmptyBraces {
#[cfg(feature = "thisisneverenabled")]
x: i32,
}, // No error
NonEmptyParentheses(#[cfg(feature = "thisisneverenabled")] i32), // No error
}
fn main() {}

View file

@ -0,0 +1,36 @@
error: enum variant has empty brackets
--> $DIR/empty_enum_variants_with_brackets.rs:7:16
|
LL | EmptyBraces {},
| ^^^
|
= note: `-D clippy::empty-enum-variants-with-brackets` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::empty_enum_variants_with_brackets)]`
= help: remove the brackets
error: enum variant has empty brackets
--> $DIR/empty_enum_variants_with_brackets.rs:8:21
|
LL | EmptyParentheses(),
| ^^
|
= help: remove the brackets
error: enum variant has empty brackets
--> $DIR/empty_enum_variants_with_brackets.rs:14:16
|
LL | EmptyBraces {},
| ^^^
|
= help: remove the brackets
error: enum variant has empty brackets
--> $DIR/empty_enum_variants_with_brackets.rs:15:21
|
LL | EmptyParentheses(),
| ^^
|
= help: remove the brackets
error: aborting due to 4 previous errors

View file

@ -22,9 +22,9 @@ mod rustc_ok {
#[expect(illegal_floating_point_literal_pattern)]
match x {
5.0 => {}
6.0 => {}
_ => {}
5.0 => {},
6.0 => {},
_ => {},
}
}
}
@ -41,9 +41,9 @@ mod rustc_warn {
#[expect(illegal_floating_point_literal_pattern)]
//~^ ERROR: this lint expectation is unfulfilled
match x {
5 => {}
6 => {}
_ => {}
5 => {},
6 => {},
_ => {},
}
}
}

View file

@ -6,7 +6,9 @@
clippy::unnecessary_operation,
clippy::op_ref,
clippy::double_parens,
clippy::uninlined_format_args
clippy::uninlined_format_args,
clippy::borrow_deref_ref,
clippy::deref_addrof
)]
use std::fmt::Write as _;
@ -40,32 +42,45 @@ fn main() {
let x = 0;
x;
//~^ ERROR: this operation has no effect
x;
//~^ ERROR: this operation has no effect
x + 1;
x;
//~^ ERROR: this operation has no effect
1 + x;
x - ZERO; //no error, as we skip lookups (for now)
x;
//~^ ERROR: this operation has no effect
((ZERO)) | x; //no error, as we skip lookups (for now)
x;
//~^ ERROR: this operation has no effect
x;
//~^ ERROR: this operation has no effect
x / ONE; //no error, as we skip lookups (for now)
x / 2; //no false positive
x & NEG_ONE; //no error, as we skip lookups (for now)
x;
//~^ ERROR: this operation has no effect
let u: u8 = 0;
u;
//~^ ERROR: this operation has no effect
1 << 0; // no error, this case is allowed, see issue 3430
42;
//~^ ERROR: this operation has no effect
1;
//~^ ERROR: this operation has no effect
42;
//~^ ERROR: this operation has no effect
x;
//~^ ERROR: this operation has no effect
x;
//~^ ERROR: this operation has no effect
let mut a = A(String::new());
let b = a << 0; // no error: non-integer
@ -73,10 +88,15 @@ fn main() {
1 * Meter; // no error: non-integer
2;
//~^ ERROR: this operation has no effect
-2;
//~^ ERROR: this operation has no effect
2 + x;
//~^ ERROR: this operation has no effect
-2 + x;
//~^ ERROR: this operation has no effect
x + 1;
//~^ ERROR: this operation has no effect
(x + 1) % 3; // no error
4 % 3; // no error
4 % -3; // no error
@ -85,38 +105,110 @@ fn main() {
let a = 0;
let b = true;
(if b { 1 } else { 2 });
//~^ ERROR: this operation has no effect
(if b { 1 } else { 2 }) + if b { 3 } else { 4 };
//~^ ERROR: this operation has no effect
(match a { 0 => 10, _ => 20 });
//~^ ERROR: this operation has no effect
(match a { 0 => 10, _ => 20 }) + match a { 0 => 30, _ => 40 };
//~^ ERROR: this operation has no effect
(if b { 1 } else { 2 }) + match a { 0 => 30, _ => 40 };
//~^ ERROR: this operation has no effect
(match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 };
//~^ ERROR: this operation has no effect
(if b { 1 } else { 2 });
//~^ ERROR: this operation has no effect
({ a }) + 3;
//~^ ERROR: this operation has no effect
({ a } * 2);
//~^ ERROR: this operation has no effect
(loop { let mut c = 0; if c == 10 { break c; } c += 1; }) + { a * 2 };
//~^ ERROR: this operation has no effect
fn f(_: i32) {
todo!();
}
f(a + { 8 * 5 });
//~^ ERROR: this operation has no effect
f(if b { 1 } else { 2 } + 3);
//~^ ERROR: this operation has no effect
const _: i32 = { 2 * 4 } + 3;
//~^ ERROR: this operation has no effect
const _: i32 = { 1 + 2 * 3 } + 3;
//~^ ERROR: this operation has no effect
a as usize;
//~^ ERROR: this operation has no effect
let _ = a as usize;
//~^ ERROR: this operation has no effect
({ a } as usize);
//~^ ERROR: this operation has no effect
2 * { a };
//~^ ERROR: this operation has no effect
(({ a } + 4));
//~^ ERROR: this operation has no effect
1;
//~^ ERROR: this operation has no effect
// Issue #9904
let x = 0i32;
let _: i32 = x;
//~^ ERROR: this operation has no effect
}
pub fn decide(a: bool, b: bool) -> u32 {
(if a { 1 } else { 2 }) + if b { 3 } else { 5 }
}
/// The following tests are from / for issue #12050
/// In short, the lint didn't work for coerced references,
/// e.g. let x = &0; let y = x + 0;
/// because the suggested fix was `let y = x;` but
/// it should have been `let y = *x;`
fn issue_12050() {
{
let x = &0i32;
let _: i32 = *x;
//~^ ERROR: this operation has no effect
let _: i32 = *x;
//~^ ERROR: this operation has no effect
}
{
let x = &&0i32;
let _: i32 = **x;
//~^ ERROR: this operation has no effect
let x = &&0i32;
let _: i32 = **x;
//~^ ERROR: this operation has no effect
}
{
// this is just silly
let x = &&&0i32;
let _: i32 = ***x;
//~^ ERROR: this operation has no effect
let _: i32 = ***x;
//~^ ERROR: this operation has no effect
let x = 0i32;
let _: i32 = *&x;
//~^ ERROR: this operation has no effect
let _: i32 = **&&x;
//~^ ERROR: this operation has no effect
let _: i32 = *&*&x;
//~^ ERROR: this operation has no effect
let _: i32 = **&&*&x;
//~^ ERROR: this operation has no effect
}
{
// this is getting ridiculous, but we should still see the same
// error message so let's just keep going
let x = &0i32;
let _: i32 = ***&&*&x;
//~^ ERROR: this operation has no effect
let _: i32 = ***&&*&x;
//~^ ERROR: this operation has no effect
}
}

View file

@ -6,7 +6,9 @@
clippy::unnecessary_operation,
clippy::op_ref,
clippy::double_parens,
clippy::uninlined_format_args
clippy::uninlined_format_args,
clippy::borrow_deref_ref,
clippy::deref_addrof
)]
use std::fmt::Write as _;
@ -40,32 +42,45 @@ fn main() {
let x = 0;
x + 0;
//~^ ERROR: this operation has no effect
x + (1 - 1);
//~^ ERROR: this operation has no effect
x + 1;
0 + x;
//~^ ERROR: this operation has no effect
1 + x;
x - ZERO; //no error, as we skip lookups (for now)
x | (0);
//~^ ERROR: this operation has no effect
((ZERO)) | x; //no error, as we skip lookups (for now)
x * 1;
//~^ ERROR: this operation has no effect
1 * x;
//~^ ERROR: this operation has no effect
x / ONE; //no error, as we skip lookups (for now)
x / 2; //no false positive
x & NEG_ONE; //no error, as we skip lookups (for now)
-1 & x;
//~^ ERROR: this operation has no effect
let u: u8 = 0;
u & 255;
//~^ ERROR: this operation has no effect
1 << 0; // no error, this case is allowed, see issue 3430
42 << 0;
//~^ ERROR: this operation has no effect
1 >> 0;
//~^ ERROR: this operation has no effect
42 >> 0;
//~^ ERROR: this operation has no effect
&x >> 0;
//~^ ERROR: this operation has no effect
x >> &0;
//~^ ERROR: this operation has no effect
let mut a = A(String::new());
let b = a << 0; // no error: non-integer
@ -73,10 +88,15 @@ fn main() {
1 * Meter; // no error: non-integer
2 % 3;
//~^ ERROR: this operation has no effect
-2 % 3;
//~^ ERROR: this operation has no effect
2 % -3 + x;
//~^ ERROR: this operation has no effect
-2 % -3 + x;
//~^ ERROR: this operation has no effect
x + 1 % 3;
//~^ ERROR: this operation has no effect
(x + 1) % 3; // no error
4 % 3; // no error
4 % -3; // no error
@ -85,38 +105,110 @@ fn main() {
let a = 0;
let b = true;
0 + if b { 1 } else { 2 };
//~^ ERROR: this operation has no effect
0 + if b { 1 } else { 2 } + if b { 3 } else { 4 };
//~^ ERROR: this operation has no effect
0 + match a { 0 => 10, _ => 20 };
//~^ ERROR: this operation has no effect
0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 };
//~^ ERROR: this operation has no effect
0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 };
//~^ ERROR: this operation has no effect
0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 };
//~^ ERROR: this operation has no effect
(if b { 1 } else { 2 }) + 0;
//~^ ERROR: this operation has no effect
0 + { a } + 3;
//~^ ERROR: this operation has no effect
0 + { a } * 2;
//~^ ERROR: this operation has no effect
0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 };
//~^ ERROR: this operation has no effect
fn f(_: i32) {
todo!();
}
f(1 * a + { 8 * 5 });
//~^ ERROR: this operation has no effect
f(0 + if b { 1 } else { 2 } + 3);
//~^ ERROR: this operation has no effect
const _: i32 = { 2 * 4 } + 0 + 3;
//~^ ERROR: this operation has no effect
const _: i32 = 0 + { 1 + 2 * 3 } + 3;
//~^ ERROR: this operation has no effect
0 + a as usize;
//~^ ERROR: this operation has no effect
let _ = 0 + a as usize;
//~^ ERROR: this operation has no effect
0 + { a } as usize;
//~^ ERROR: this operation has no effect
2 * (0 + { a });
//~^ ERROR: this operation has no effect
1 * ({ a } + 4);
//~^ ERROR: this operation has no effect
1 * 1;
//~^ ERROR: this operation has no effect
// Issue #9904
let x = 0i32;
let _: i32 = &x + 0;
//~^ ERROR: this operation has no effect
}
pub fn decide(a: bool, b: bool) -> u32 {
0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
}
/// The following tests are from / for issue #12050
/// In short, the lint didn't work for coerced references,
/// e.g. let x = &0; let y = x + 0;
/// because the suggested fix was `let y = x;` but
/// it should have been `let y = *x;`
fn issue_12050() {
{
let x = &0i32;
let _: i32 = *x + 0;
//~^ ERROR: this operation has no effect
let _: i32 = x + 0;
//~^ ERROR: this operation has no effect
}
{
let x = &&0i32;
let _: i32 = **x + 0;
//~^ ERROR: this operation has no effect
let x = &&0i32;
let _: i32 = *x + 0;
//~^ ERROR: this operation has no effect
}
{
// this is just silly
let x = &&&0i32;
let _: i32 = ***x + 0;
//~^ ERROR: this operation has no effect
let _: i32 = **x + 0;
//~^ ERROR: this operation has no effect
let x = 0i32;
let _: i32 = *&x + 0;
//~^ ERROR: this operation has no effect
let _: i32 = **&&x + 0;
//~^ ERROR: this operation has no effect
let _: i32 = *&*&x + 0;
//~^ ERROR: this operation has no effect
let _: i32 = **&&*&x + 0;
//~^ ERROR: this operation has no effect
}
{
// this is getting ridiculous, but we should still see the same
// error message so let's just keep going
let x = &0i32;
let _: i32 = **&&*&x + 0;
//~^ ERROR: this operation has no effect
let _: i32 = **&&*&x + 0;
//~^ ERROR: this operation has no effect
}
}

View file

@ -1,5 +1,5 @@
error: this operation has no effect
--> $DIR/identity_op.rs:42:5
--> $DIR/identity_op.rs:44:5
|
LL | x + 0;
| ^^^^^ help: consider reducing it to: `x`
@ -8,238 +8,310 @@ LL | x + 0;
= help: to override `-D warnings` add `#[allow(clippy::identity_op)]`
error: this operation has no effect
--> $DIR/identity_op.rs:43:5
--> $DIR/identity_op.rs:46:5
|
LL | x + (1 - 1);
| ^^^^^^^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:45:5
--> $DIR/identity_op.rs:49:5
|
LL | 0 + x;
| ^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:48:5
--> $DIR/identity_op.rs:53:5
|
LL | x | (0);
| ^^^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:51:5
--> $DIR/identity_op.rs:57:5
|
LL | x * 1;
| ^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:52:5
--> $DIR/identity_op.rs:59:5
|
LL | 1 * x;
| ^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:58:5
--> $DIR/identity_op.rs:66:5
|
LL | -1 & x;
| ^^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:61:5
--> $DIR/identity_op.rs:70:5
|
LL | u & 255;
| ^^^^^^^ help: consider reducing it to: `u`
error: this operation has no effect
--> $DIR/identity_op.rs:64:5
--> $DIR/identity_op.rs:74:5
|
LL | 42 << 0;
| ^^^^^^^ help: consider reducing it to: `42`
error: this operation has no effect
--> $DIR/identity_op.rs:65:5
--> $DIR/identity_op.rs:76:5
|
LL | 1 >> 0;
| ^^^^^^ help: consider reducing it to: `1`
error: this operation has no effect
--> $DIR/identity_op.rs:66:5
--> $DIR/identity_op.rs:78:5
|
LL | 42 >> 0;
| ^^^^^^^ help: consider reducing it to: `42`
error: this operation has no effect
--> $DIR/identity_op.rs:67:5
--> $DIR/identity_op.rs:80:5
|
LL | &x >> 0;
| ^^^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:68:5
--> $DIR/identity_op.rs:82:5
|
LL | x >> &0;
| ^^^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:75:5
--> $DIR/identity_op.rs:90:5
|
LL | 2 % 3;
| ^^^^^ help: consider reducing it to: `2`
error: this operation has no effect
--> $DIR/identity_op.rs:76:5
--> $DIR/identity_op.rs:92:5
|
LL | -2 % 3;
| ^^^^^^ help: consider reducing it to: `-2`
error: this operation has no effect
--> $DIR/identity_op.rs:77:5
--> $DIR/identity_op.rs:94:5
|
LL | 2 % -3 + x;
| ^^^^^^ help: consider reducing it to: `2`
error: this operation has no effect
--> $DIR/identity_op.rs:78:5
--> $DIR/identity_op.rs:96:5
|
LL | -2 % -3 + x;
| ^^^^^^^ help: consider reducing it to: `-2`
error: this operation has no effect
--> $DIR/identity_op.rs:79:9
--> $DIR/identity_op.rs:98:9
|
LL | x + 1 % 3;
| ^^^^^ help: consider reducing it to: `1`
error: this operation has no effect
--> $DIR/identity_op.rs:87:5
--> $DIR/identity_op.rs:107:5
|
LL | 0 + if b { 1 } else { 2 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
error: this operation has no effect
--> $DIR/identity_op.rs:88:5
--> $DIR/identity_op.rs:109:5
|
LL | 0 + if b { 1 } else { 2 } + if b { 3 } else { 4 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
error: this operation has no effect
--> $DIR/identity_op.rs:89:5
--> $DIR/identity_op.rs:111:5
|
LL | 0 + match a { 0 => 10, _ => 20 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
error: this operation has no effect
--> $DIR/identity_op.rs:90:5
--> $DIR/identity_op.rs:113:5
|
LL | 0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
error: this operation has no effect
--> $DIR/identity_op.rs:91:5
--> $DIR/identity_op.rs:115:5
|
LL | 0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
error: this operation has no effect
--> $DIR/identity_op.rs:92:5
--> $DIR/identity_op.rs:117:5
|
LL | 0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })`
error: this operation has no effect
--> $DIR/identity_op.rs:93:5
--> $DIR/identity_op.rs:119:5
|
LL | (if b { 1 } else { 2 }) + 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
error: this operation has no effect
--> $DIR/identity_op.rs:95:5
--> $DIR/identity_op.rs:122:5
|
LL | 0 + { a } + 3;
| ^^^^^^^^^ help: consider reducing it to: `({ a })`
error: this operation has no effect
--> $DIR/identity_op.rs:96:5
--> $DIR/identity_op.rs:124:5
|
LL | 0 + { a } * 2;
| ^^^^^^^^^^^^^ help: consider reducing it to: `({ a } * 2)`
error: this operation has no effect
--> $DIR/identity_op.rs:97:5
--> $DIR/identity_op.rs:126:5
|
LL | 0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(loop { let mut c = 0; if c == 10 { break c; } c += 1; })`
error: this operation has no effect
--> $DIR/identity_op.rs:102:7
--> $DIR/identity_op.rs:133:7
|
LL | f(1 * a + { 8 * 5 });
| ^^^^^ help: consider reducing it to: `a`
error: this operation has no effect
--> $DIR/identity_op.rs:103:7
--> $DIR/identity_op.rs:135:7
|
LL | f(0 + if b { 1 } else { 2 } + 3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `if b { 1 } else { 2 }`
error: this operation has no effect
--> $DIR/identity_op.rs:104:20
--> $DIR/identity_op.rs:138:20
|
LL | const _: i32 = { 2 * 4 } + 0 + 3;
| ^^^^^^^^^^^^^ help: consider reducing it to: `{ 2 * 4 }`
error: this operation has no effect
--> $DIR/identity_op.rs:105:20
--> $DIR/identity_op.rs:140:20
|
LL | const _: i32 = 0 + { 1 + 2 * 3 } + 3;
| ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `{ 1 + 2 * 3 }`
error: this operation has no effect
--> $DIR/identity_op.rs:107:5
--> $DIR/identity_op.rs:143:5
|
LL | 0 + a as usize;
| ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize`
error: this operation has no effect
--> $DIR/identity_op.rs:108:13
--> $DIR/identity_op.rs:145:13
|
LL | let _ = 0 + a as usize;
| ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize`
error: this operation has no effect
--> $DIR/identity_op.rs:109:5
--> $DIR/identity_op.rs:147:5
|
LL | 0 + { a } as usize;
| ^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `({ a } as usize)`
error: this operation has no effect
--> $DIR/identity_op.rs:111:9
--> $DIR/identity_op.rs:150:9
|
LL | 2 * (0 + { a });
| ^^^^^^^^^^^ help: consider reducing it to: `{ a }`
error: this operation has no effect
--> $DIR/identity_op.rs:112:5
--> $DIR/identity_op.rs:152:5
|
LL | 1 * ({ a } + 4);
| ^^^^^^^^^^^^^^^ help: consider reducing it to: `(({ a } + 4))`
error: this operation has no effect
--> $DIR/identity_op.rs:113:5
--> $DIR/identity_op.rs:154:5
|
LL | 1 * 1;
| ^^^^^ help: consider reducing it to: `1`
error: this operation has no effect
--> $DIR/identity_op.rs:117:18
--> $DIR/identity_op.rs:159:18
|
LL | let _: i32 = &x + 0;
| ^^^^^^ help: consider reducing it to: `x`
error: this operation has no effect
--> $DIR/identity_op.rs:121:5
--> $DIR/identity_op.rs:164:5
|
LL | 0 + if a { 1 } else { 2 } + if b { 3 } else { 5 }
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if a { 1 } else { 2 })`
error: aborting due to 40 previous errors
error: this operation has no effect
--> $DIR/identity_op.rs:175:22
|
LL | let _: i32 = *x + 0;
| ^^^^^^ help: consider reducing it to: `*x`
error: this operation has no effect
--> $DIR/identity_op.rs:177:22
|
LL | let _: i32 = x + 0;
| ^^^^^ help: consider reducing it to: `*x`
error: this operation has no effect
--> $DIR/identity_op.rs:182:22
|
LL | let _: i32 = **x + 0;
| ^^^^^^^ help: consider reducing it to: `**x`
error: this operation has no effect
--> $DIR/identity_op.rs:185:22
|
LL | let _: i32 = *x + 0;
| ^^^^^^ help: consider reducing it to: `**x`
error: this operation has no effect
--> $DIR/identity_op.rs:191:22
|
LL | let _: i32 = ***x + 0;
| ^^^^^^^^ help: consider reducing it to: `***x`
error: this operation has no effect
--> $DIR/identity_op.rs:193:22
|
LL | let _: i32 = **x + 0;
| ^^^^^^^ help: consider reducing it to: `***x`
error: this operation has no effect
--> $DIR/identity_op.rs:196:22
|
LL | let _: i32 = *&x + 0;
| ^^^^^^^ help: consider reducing it to: `*&x`
error: this operation has no effect
--> $DIR/identity_op.rs:198:22
|
LL | let _: i32 = **&&x + 0;
| ^^^^^^^^^ help: consider reducing it to: `**&&x`
error: this operation has no effect
--> $DIR/identity_op.rs:200:22
|
LL | let _: i32 = *&*&x + 0;
| ^^^^^^^^^ help: consider reducing it to: `*&*&x`
error: this operation has no effect
--> $DIR/identity_op.rs:202:22
|
LL | let _: i32 = **&&*&x + 0;
| ^^^^^^^^^^^ help: consider reducing it to: `**&&*&x`
error: this operation has no effect
--> $DIR/identity_op.rs:209:22
|
LL | let _: i32 = **&&*&x + 0;
| ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x`
error: this operation has no effect
--> $DIR/identity_op.rs:211:22
|
LL | let _: i32 = **&&*&x + 0;
| ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x`
error: aborting due to 52 previous errors

View file

@ -130,3 +130,8 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> {
Ok(())
}
const fn issue12103(x: u32) -> Option<u32> {
// Should not issue an error in `const` context
if x > 42 { Some(150) } else { None }
}

View file

@ -1,5 +1,7 @@
//@no-rustfix
//@aux-build:proc_macros.rs
#![warn(clippy::into_iter_without_iter)]
extern crate proc_macros;
use std::iter::IntoIterator;
@ -111,6 +113,43 @@ impl IntoIterator for &Alias {
}
}
// Fine to lint, the impls comes from a local macro.
pub struct Issue12037;
macro_rules! generate_impl {
() => {
impl<'a> IntoIterator for &'a Issue12037 {
type IntoIter = std::slice::Iter<'a, u8>;
type Item = &'a u8;
fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
};
}
generate_impl!();
// Impl comes from an external crate
proc_macros::external! {
pub struct ImplWithForeignSpan;
impl<'a> IntoIterator for &'a ImplWithForeignSpan {
type IntoIter = std::slice::Iter<'a, u8>;
type Item = &'a u8;
fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
}
pub struct Allowed;
#[allow(clippy::into_iter_without_iter)]
impl<'a> IntoIterator for &'a Allowed {
type IntoIter = std::slice::Iter<'a, u8>;
type Item = &'a u8;
fn into_iter(self) -> Self::IntoIter {
todo!()
}
}
fn main() {}
pub mod issue11635 {

View file

@ -1,5 +1,5 @@
error: `IntoIterator` implemented for a reference type without an `iter` method
--> $DIR/into_iter_without_iter.rs:7:1
--> $DIR/into_iter_without_iter.rs:9:1
|
LL | / impl<'a> IntoIterator for &'a S1 {
LL | |
@ -23,7 +23,7 @@ LL + }
|
error: `IntoIterator` implemented for a reference type without an `iter_mut` method
--> $DIR/into_iter_without_iter.rs:15:1
--> $DIR/into_iter_without_iter.rs:17:1
|
LL | / impl<'a> IntoIterator for &'a mut S1 {
LL | |
@ -45,7 +45,7 @@ LL + }
|
error: `IntoIterator` implemented for a reference type without an `iter` method
--> $DIR/into_iter_without_iter.rs:25:1
--> $DIR/into_iter_without_iter.rs:27:1
|
LL | / impl<'a, T> IntoIterator for &'a S2<T> {
LL | |
@ -67,7 +67,7 @@ LL + }
|
error: `IntoIterator` implemented for a reference type without an `iter_mut` method
--> $DIR/into_iter_without_iter.rs:33:1
--> $DIR/into_iter_without_iter.rs:35:1
|
LL | / impl<'a, T> IntoIterator for &'a mut S2<T> {
LL | |
@ -89,7 +89,7 @@ LL + }
|
error: `IntoIterator` implemented for a reference type without an `iter_mut` method
--> $DIR/into_iter_without_iter.rs:84:1
--> $DIR/into_iter_without_iter.rs:86:1
|
LL | / impl<'a, T> IntoIterator for &mut S4<'a, T> {
LL | |
@ -110,5 +110,31 @@ LL + }
LL + }
|
error: aborting due to 5 previous errors
error: `IntoIterator` implemented for a reference type without an `iter` method
--> $DIR/into_iter_without_iter.rs:120:9
|
LL | / impl<'a> IntoIterator for &'a Issue12037 {
LL | | type IntoIter = std::slice::Iter<'a, u8>;
LL | | type Item = &'a u8;
LL | | fn into_iter(self) -> Self::IntoIter {
LL | | todo!()
LL | | }
LL | | }
| |_________^
...
LL | generate_impl!();
| ---------------- in this macro invocation
|
= note: this error originates in the macro `generate_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider implementing `iter`
|
LL ~
LL + impl Issue12037 {
LL + fn iter(&self) -> std::slice::Iter<'a, u8> {
LL + <&Self as IntoIterator>::into_iter(self)
LL + }
LL + }
|
error: aborting due to 6 previous errors

View file

@ -1,21 +1,72 @@
#![warn(clippy::iter_filter_is_ok)]
#![allow(
clippy::map_identity,
clippy::result_filter_map,
clippy::needless_borrow,
clippy::redundant_closure
)]
fn main() {
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
{
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
}
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
{
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
}
{
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
.flatten();
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
.flatten();
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
}
{
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
}
}
fn avoid_linting_when_filter_has_side_effects() {
// Don't lint below
let mut counter = 0;
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
counter += 1;
o.is_ok()
});
}
fn avoid_linting_when_commented() {
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
// Roses are red,
// Violets are blue,
@ -24,3 +75,131 @@ fn main() {
o.is_ok()
});
}
fn ice_12058() {
// check that checking the parent node doesn't cause an ICE
// by indexing the parameters of a closure without parameters
Some(1).or_else(|| {
vec![Ok(1), Err(())].into_iter().filter(|z| *z != Ok(2));
None
});
}
fn avoid_linting_map() {
// should not lint
let _ = vec![Ok(1), Err(())]
.into_iter()
.filter(|o| o.is_ok())
.map(|o| o.unwrap());
// should not lint
let _ = vec![Ok(1), Err(())].into_iter().filter(|o| o.is_ok()).map(|o| o);
}
fn avoid_false_positive_due_to_is_ok_and_iterator_impl() {
#[derive(Default, Clone)]
struct Foo {}
impl Foo {
fn is_ok(&self) -> bool {
true
}
}
impl Iterator for Foo {
type Item = Foo;
fn next(&mut self) -> Option<Self::Item> {
Some(Foo::default())
}
}
let data = vec![Foo::default()];
// should not lint
let _ = data.clone().into_iter().filter(Foo::is_ok);
// should not lint
let _ = data.clone().into_iter().filter(|f| f.is_ok());
}
fn avoid_false_positive_due_to_is_ok_and_into_iterator_impl() {
#[derive(Default, Clone)]
struct Foo {}
impl Foo {
fn is_ok(&self) -> bool {
true
}
}
let data = vec![Foo::default()];
// should not lint
let _ = data.clone().into_iter().filter(Foo::is_ok);
// should not lint
let _ = data.clone().into_iter().filter(|f| f.is_ok());
}
fn avoid_fp_for_trivial() {
let _ = vec![Ok(1), Err(()), Ok(3)]
.into_iter()
// should not lint
.filter(|o| (Err(()) as Result<i32, ()>).is_ok());
}
fn avoid_false_positive_due_to_method_name() {
fn is_ok(x: &Result<i32, i32>) -> bool {
x.is_ok()
}
vec![Ok(1), Err(2), Ok(3)].into_iter().filter(is_ok);
// should not lint
}
fn avoid_fp_due_to_trait_type() {
struct Foo {
bar: i32,
}
impl Foo {
fn is_ok(obj: &Result<i32, i32>) -> bool {
obj.is_ok()
}
}
vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Foo::is_ok);
// should not lint
}
fn avoid_fp_with_call_to_outside_var() {
let outside: Result<i32, ()> = Ok(1);
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| outside.is_ok());
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| Result::is_ok(&outside));
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| std::result::Result::is_ok(&outside));
}
fn avoid_fp_with_call_to_outside_var_mix_match_types() {
let outside = Some(1);
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| outside.is_some());
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| Option::is_some(&outside));
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| std::option::Option::is_some(&outside));
}

View file

@ -1,21 +1,72 @@
#![warn(clippy::iter_filter_is_ok)]
#![allow(
clippy::map_identity,
clippy::result_filter_map,
clippy::needless_borrow,
clippy::redundant_closure
)]
fn main() {
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
//~^ HELP: consider using `flatten` instead
{
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
//~^ HELP: consider using `flatten` instead
}
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
//~^ HELP: consider using `flatten` instead
{
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok());
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok());
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2)].into_iter().filter(|&o| { o.is_ok() });
//~^ HELP: consider using `flatten` instead
}
{
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
.filter(std::result::Result::is_ok);
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
.filter(|a| std::result::Result::is_ok(a));
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| { std::result::Result::is_ok(a) });
//~^ HELP: consider using `flatten` instead
}
{
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok());
//~^ HELP: consider using `flatten` instead
let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok());
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Ok(1), Err(2)].into_iter().filter(|ref o| { o.is_ok() });
//~^ HELP: consider using `flatten` instead
}
}
fn avoid_linting_when_filter_has_side_effects() {
// Don't lint below
let mut counter = 0;
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
counter += 1;
o.is_ok()
});
}
fn avoid_linting_when_commented() {
let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| {
// Roses are red,
// Violets are blue,
@ -24,3 +75,131 @@ fn main() {
o.is_ok()
});
}
fn ice_12058() {
// check that checking the parent node doesn't cause an ICE
// by indexing the parameters of a closure without parameters
Some(1).or_else(|| {
vec![Ok(1), Err(())].into_iter().filter(|z| *z != Ok(2));
None
});
}
fn avoid_linting_map() {
// should not lint
let _ = vec![Ok(1), Err(())]
.into_iter()
.filter(|o| o.is_ok())
.map(|o| o.unwrap());
// should not lint
let _ = vec![Ok(1), Err(())].into_iter().filter(|o| o.is_ok()).map(|o| o);
}
fn avoid_false_positive_due_to_is_ok_and_iterator_impl() {
#[derive(Default, Clone)]
struct Foo {}
impl Foo {
fn is_ok(&self) -> bool {
true
}
}
impl Iterator for Foo {
type Item = Foo;
fn next(&mut self) -> Option<Self::Item> {
Some(Foo::default())
}
}
let data = vec![Foo::default()];
// should not lint
let _ = data.clone().into_iter().filter(Foo::is_ok);
// should not lint
let _ = data.clone().into_iter().filter(|f| f.is_ok());
}
fn avoid_false_positive_due_to_is_ok_and_into_iterator_impl() {
#[derive(Default, Clone)]
struct Foo {}
impl Foo {
fn is_ok(&self) -> bool {
true
}
}
let data = vec![Foo::default()];
// should not lint
let _ = data.clone().into_iter().filter(Foo::is_ok);
// should not lint
let _ = data.clone().into_iter().filter(|f| f.is_ok());
}
fn avoid_fp_for_trivial() {
let _ = vec![Ok(1), Err(()), Ok(3)]
.into_iter()
// should not lint
.filter(|o| (Err(()) as Result<i32, ()>).is_ok());
}
fn avoid_false_positive_due_to_method_name() {
fn is_ok(x: &Result<i32, i32>) -> bool {
x.is_ok()
}
vec![Ok(1), Err(2), Ok(3)].into_iter().filter(is_ok);
// should not lint
}
fn avoid_fp_due_to_trait_type() {
struct Foo {
bar: i32,
}
impl Foo {
fn is_ok(obj: &Result<i32, i32>) -> bool {
obj.is_ok()
}
}
vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Foo::is_ok);
// should not lint
}
fn avoid_fp_with_call_to_outside_var() {
let outside: Result<i32, ()> = Ok(1);
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| outside.is_ok());
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| Result::is_ok(&outside));
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| std::result::Result::is_ok(&outside));
}
fn avoid_fp_with_call_to_outside_var_mix_match_types() {
let outside = Some(1);
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| outside.is_some());
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| Option::is_some(&outside));
let _ = vec![Ok(1), Err(2), Ok(3)]
.into_iter()
// should not lint
.filter(|o| std::option::Option::is_some(&outside));
}

View file

@ -1,23 +1,77 @@
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:4:52
--> $DIR/iter_filter_is_ok.rs:11:56
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
= note: `-D clippy::iter-filter-is-ok` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_ok)]`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:6:52
--> $DIR/iter_filter_is_ok.rs:13:56
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok());
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:10:45
--> $DIR/iter_filter_is_ok.rs:16:49
|
LL | let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
LL | let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: aborting due to 3 previous errors
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:21:56
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:24:56
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok());
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:28:49
|
LL | let _ = vec![Ok(1), Err(2)].into_iter().filter(|&o| { o.is_ok() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:35:14
|
LL | .filter(std::result::Result::is_ok);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:40:14
|
LL | .filter(|a| std::result::Result::is_ok(a));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:43:56
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| { std::result::Result::is_ok(a) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:48:56
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:51:56
|
LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_ok` on iterator over `Result`s
--> $DIR/iter_filter_is_ok.rs:55:49
|
LL | let _ = vec![Ok(1), Err(2)].into_iter().filter(|ref o| { o.is_ok() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: aborting due to 12 previous errors

View file

@ -1,23 +1,70 @@
#![warn(clippy::iter_filter_is_some)]
#![allow(
clippy::map_identity,
clippy::result_filter_map,
clippy::needless_borrow,
clippy::option_filter_map,
clippy::redundant_closure
)]
use std::collections::HashMap;
fn main() {
let _ = vec![Some(1)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
let _ = vec![Some(1)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
{
let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
}
#[rustfmt::skip]
let _ = vec![Some(1)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
{
let _ = vec![Some(1), None, Some(3)]
.into_iter()
.flatten();
//~^ HELP: consider using `flatten` instead
let _ = vec![Some(1), None, Some(3)]
.into_iter()
.flatten();
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
}
{
let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
}
{
let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Some(1), None, Some(3)].into_iter().flatten();
//~^ HELP: consider using `flatten` instead
}
}
fn avoid_linting_when_filter_has_side_effects() {
// Don't lint below
let mut counter = 0;
let _ = vec![Some(1)].into_iter().filter(|o| {
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| {
counter += 1;
o.is_some()
});
}
let _ = vec![Some(1)].into_iter().filter(|o| {
fn avoid_linting_when_commented() {
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| {
// Roses are red,
// Violets are blue,
// `Err` is not an `Option`,
@ -25,3 +72,169 @@ fn main() {
o.is_some()
});
}
fn ice_12058() {
// check that checking the parent node doesn't cause an ICE
// by indexing the parameters of a closure without parameters
Some(1).or_else(|| {
vec![Some(1), None, Some(3)].into_iter().filter(|z| *z != Some(2));
None
});
}
fn avoid_linting_map() {
// should not lint
let _ = vec![Some(1), None, Some(3)]
.into_iter()
.filter(|o| o.is_some())
.map(|o| o.unwrap());
// should not lint
let _ = vec![Some(1), None, Some(3)]
.into_iter()
.filter(|o| o.is_some())
.map(|o| o);
}
fn avoid_false_positive_due_to_is_some_and_iterator_impl() {
#[derive(Default, Clone)]
struct Foo {}
impl Foo {
fn is_some(&self) -> bool {
true
}
}
impl Iterator for Foo {
type Item = Foo;
fn next(&mut self) -> Option<Self::Item> {
Some(Foo::default())
}
}
let data = vec![Foo::default()];
// should not lint
let _ = data.clone().into_iter().filter(Foo::is_some);
// should not lint
let _ = data.clone().into_iter().filter(|f| f.is_some());
}
fn avoid_false_positive_due_to_is_some_and_into_iterator_impl() {
#[derive(Default, Clone)]
struct Foo {}
impl Foo {
fn is_some(&self) -> bool {
true
}
}
let data = vec![Foo::default()];
// should not lint
let _ = data.clone().into_iter().filter(Foo::is_some);
// should not lint
let _ = data.clone().into_iter().filter(|f| f.is_some());
}
fn avoid_unpack_fp() {
let _ = vec![(Some(1), None), (None, Some(3))]
.into_iter()
// should not lint
.filter(|(a, _)| a.is_some());
let _ = vec![(Some(1), None), (None, Some(3))]
.into_iter()
// should not lint
.filter(|(a, _)| a.is_some())
.collect::<Vec<_>>();
let m = HashMap::from([(1, 1)]);
let _ = vec![1, 2, 4].into_iter().filter(|a| m.get(a).is_some());
// should not lint
}
fn avoid_fp_for_external() {
let value = HashMap::from([(1, 1)]);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| value.get(&1).is_some());
let value = Option::Some(1);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| value.is_some());
}
fn avoid_fp_for_trivial() {
let value = HashMap::from([(1, 1)]);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| Some(1).is_some());
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| None::<i32>.is_some());
}
fn avoid_false_positive_due_to_method_name() {
fn is_some(x: &Option<i32>) -> bool {
x.is_some()
}
vec![Some(1), None, Some(3)].into_iter().filter(is_some);
// should not lint
}
fn avoid_fp_due_to_trait_type() {
struct Foo {
bar: i32,
}
impl Foo {
fn is_some(obj: &Option<i32>) -> bool {
obj.is_some()
}
}
vec![Some(1), None, Some(3)].into_iter().filter(Foo::is_some);
// should not lint
}
fn avoid_fp_with_call_to_outside_var() {
let outside = Some(1);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| outside.is_some());
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| Option::is_some(&outside));
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| std::option::Option::is_some(&outside));
}
fn avoid_fp_with_call_to_outside_var_mix_match_types() {
let outside: Result<i32, ()> = Ok(1);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| outside.is_ok());
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| Result::is_ok(&outside));
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| std::result::Result::is_ok(&outside));
}

View file

@ -1,23 +1,70 @@
#![warn(clippy::iter_filter_is_some)]
#![allow(
clippy::map_identity,
clippy::result_filter_map,
clippy::needless_borrow,
clippy::option_filter_map,
clippy::redundant_closure
)]
use std::collections::HashMap;
fn main() {
let _ = vec![Some(1)].into_iter().filter(Option::is_some);
//~^ HELP: consider using `flatten` instead
let _ = vec![Some(1)].into_iter().filter(|o| o.is_some());
//~^ HELP: consider using `flatten` instead
{
let _ = vec![Some(1), None, Some(3)].into_iter().filter(Option::is_some);
//~^ HELP: consider using `flatten` instead
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| a.is_some());
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| { o.is_some() });
//~^ HELP: consider using `flatten` instead
}
#[rustfmt::skip]
let _ = vec![Some(1)].into_iter().filter(|o| { o.is_some() });
//~^ HELP: consider using `flatten` instead
{
let _ = vec![Some(1), None, Some(3)]
.into_iter()
.filter(std::option::Option::is_some);
//~^ HELP: consider using `flatten` instead
let _ = vec![Some(1), None, Some(3)]
.into_iter()
.filter(|a| std::option::Option::is_some(a));
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| { std::option::Option::is_some(a) });
//~^ HELP: consider using `flatten` instead
}
{
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&a| a.is_some());
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&o| { o.is_some() });
//~^ HELP: consider using `flatten` instead
}
{
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref a| a.is_some());
//~^ HELP: consider using `flatten` instead
#[rustfmt::skip]
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref o| { o.is_some() });
//~^ HELP: consider using `flatten` instead
}
}
fn avoid_linting_when_filter_has_side_effects() {
// Don't lint below
let mut counter = 0;
let _ = vec![Some(1)].into_iter().filter(|o| {
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| {
counter += 1;
o.is_some()
});
}
let _ = vec![Some(1)].into_iter().filter(|o| {
fn avoid_linting_when_commented() {
let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| {
// Roses are red,
// Violets are blue,
// `Err` is not an `Option`,
@ -25,3 +72,169 @@ fn main() {
o.is_some()
});
}
fn ice_12058() {
// check that checking the parent node doesn't cause an ICE
// by indexing the parameters of a closure without parameters
Some(1).or_else(|| {
vec![Some(1), None, Some(3)].into_iter().filter(|z| *z != Some(2));
None
});
}
fn avoid_linting_map() {
// should not lint
let _ = vec![Some(1), None, Some(3)]
.into_iter()
.filter(|o| o.is_some())
.map(|o| o.unwrap());
// should not lint
let _ = vec![Some(1), None, Some(3)]
.into_iter()
.filter(|o| o.is_some())
.map(|o| o);
}
fn avoid_false_positive_due_to_is_some_and_iterator_impl() {
#[derive(Default, Clone)]
struct Foo {}
impl Foo {
fn is_some(&self) -> bool {
true
}
}
impl Iterator for Foo {
type Item = Foo;
fn next(&mut self) -> Option<Self::Item> {
Some(Foo::default())
}
}
let data = vec![Foo::default()];
// should not lint
let _ = data.clone().into_iter().filter(Foo::is_some);
// should not lint
let _ = data.clone().into_iter().filter(|f| f.is_some());
}
fn avoid_false_positive_due_to_is_some_and_into_iterator_impl() {
#[derive(Default, Clone)]
struct Foo {}
impl Foo {
fn is_some(&self) -> bool {
true
}
}
let data = vec![Foo::default()];
// should not lint
let _ = data.clone().into_iter().filter(Foo::is_some);
// should not lint
let _ = data.clone().into_iter().filter(|f| f.is_some());
}
fn avoid_unpack_fp() {
let _ = vec![(Some(1), None), (None, Some(3))]
.into_iter()
// should not lint
.filter(|(a, _)| a.is_some());
let _ = vec![(Some(1), None), (None, Some(3))]
.into_iter()
// should not lint
.filter(|(a, _)| a.is_some())
.collect::<Vec<_>>();
let m = HashMap::from([(1, 1)]);
let _ = vec![1, 2, 4].into_iter().filter(|a| m.get(a).is_some());
// should not lint
}
fn avoid_fp_for_external() {
let value = HashMap::from([(1, 1)]);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| value.get(&1).is_some());
let value = Option::Some(1);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| value.is_some());
}
fn avoid_fp_for_trivial() {
let value = HashMap::from([(1, 1)]);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| Some(1).is_some());
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| None::<i32>.is_some());
}
fn avoid_false_positive_due_to_method_name() {
fn is_some(x: &Option<i32>) -> bool {
x.is_some()
}
vec![Some(1), None, Some(3)].into_iter().filter(is_some);
// should not lint
}
fn avoid_fp_due_to_trait_type() {
struct Foo {
bar: i32,
}
impl Foo {
fn is_some(obj: &Option<i32>) -> bool {
obj.is_some()
}
}
vec![Some(1), None, Some(3)].into_iter().filter(Foo::is_some);
// should not lint
}
fn avoid_fp_with_call_to_outside_var() {
let outside = Some(1);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| outside.is_some());
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| Option::is_some(&outside));
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| std::option::Option::is_some(&outside));
}
fn avoid_fp_with_call_to_outside_var_mix_match_types() {
let outside: Result<i32, ()> = Ok(1);
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| outside.is_ok());
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| Result::is_ok(&outside));
let _ = vec![Some(1), None, Some(3)]
.into_iter()
// should not lint
.filter(|o| std::result::Result::is_ok(&outside));
}

View file

@ -1,23 +1,65 @@
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:4:39
--> $DIR/iter_filter_is_some.rs:14:58
|
LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(Option::is_some);
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
|
= note: `-D clippy::iter-filter-is-some` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_some)]`
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:6:39
--> $DIR/iter_filter_is_some.rs:16:58
|
LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some());
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| a.is_some());
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:10:39
--> $DIR/iter_filter_is_some.rs:19:58
|
LL | let _ = vec![Some(1)].into_iter().filter(|o| { o.is_some() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| { o.is_some() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: aborting due to 3 previous errors
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:26:14
|
LL | .filter(std::option::Option::is_some);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:31:14
|
LL | .filter(|a| std::option::Option::is_some(a));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:34:58
|
LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| { std::option::Option::is_some(a) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:39:58
|
LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&a| a.is_some());
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:43:58
|
LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&o| { o.is_some() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:48:58
|
LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref a| a.is_some());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: `filter` for `is_some` on iterator over `Option`
--> $DIR/iter_filter_is_some.rs:52:58
|
LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref o| { o.is_some() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()`
error: aborting due to 10 previous errors

View file

@ -1,5 +1,7 @@
//@no-rustfix
//@aux-build:proc_macros.rs
#![warn(clippy::iter_without_into_iter)]
extern crate proc_macros;
pub struct S1;
impl S1 {
@ -121,4 +123,33 @@ impl S12 {
}
}
pub struct Issue12037;
macro_rules! generate_impl {
() => {
impl Issue12037 {
fn iter(&self) -> std::slice::Iter<'_, u8> {
todo!()
}
}
};
}
generate_impl!();
proc_macros::external! {
pub struct ImplWithForeignSpan;
impl ImplWithForeignSpan {
fn iter(&self) -> std::slice::Iter<'_, u8> {
todo!()
}
}
}
pub struct Allowed;
impl Allowed {
#[allow(clippy::iter_without_into_iter)]
pub fn iter(&self) -> std::slice::Iter<'_, u8> {
todo!()
}
}
fn main() {}

View file

@ -1,5 +1,5 @@
error: `iter` method without an `IntoIterator` impl for `&S1`
--> $DIR/iter_without_into_iter.rs:6:5
--> $DIR/iter_without_into_iter.rs:8:5
|
LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> {
LL | |
@ -22,7 +22,7 @@ LL + }
|
error: `iter_mut` method without an `IntoIterator` impl for `&mut S1`
--> $DIR/iter_without_into_iter.rs:10:5
--> $DIR/iter_without_into_iter.rs:12:5
|
LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
LL | |
@ -43,7 +43,7 @@ LL + }
|
error: `iter` method without an `IntoIterator` impl for `&S3<'a>`
--> $DIR/iter_without_into_iter.rs:26:5
--> $DIR/iter_without_into_iter.rs:28:5
|
LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> {
LL | |
@ -64,7 +64,7 @@ LL + }
|
error: `iter_mut` method without an `IntoIterator` impl for `&mut S3<'a>`
--> $DIR/iter_without_into_iter.rs:30:5
--> $DIR/iter_without_into_iter.rs:32:5
|
LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
LL | |
@ -85,7 +85,7 @@ LL + }
|
error: `iter` method without an `IntoIterator` impl for `&S8<T>`
--> $DIR/iter_without_into_iter.rs:67:5
--> $DIR/iter_without_into_iter.rs:69:5
|
LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> {
LL | | todo!()
@ -105,7 +105,7 @@ LL + }
|
error: `iter` method without an `IntoIterator` impl for `&S9<T>`
--> $DIR/iter_without_into_iter.rs:75:5
--> $DIR/iter_without_into_iter.rs:77:5
|
LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> {
LL | |
@ -126,7 +126,7 @@ LL + }
|
error: `iter_mut` method without an `IntoIterator` impl for `&mut S9<T>`
--> $DIR/iter_without_into_iter.rs:79:5
--> $DIR/iter_without_into_iter.rs:81:5
|
LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
LL | |
@ -146,5 +146,29 @@ LL + }
LL + }
|
error: aborting due to 7 previous errors
error: `iter` method without an `IntoIterator` impl for `&Issue12037`
--> $DIR/iter_without_into_iter.rs:130:13
|
LL | / fn iter(&self) -> std::slice::Iter<'_, u8> {
LL | | todo!()
LL | | }
| |_____________^
...
LL | generate_impl!();
| ---------------- in this macro invocation
|
= note: this error originates in the macro `generate_impl` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider implementing `IntoIterator` for `&Issue12037`
|
LL ~
LL + impl IntoIterator for &Issue12037 {
LL + type IntoIter = std::slice::Iter<'_, u8>;
LL + type Item = &u8;
LL + fn into_iter(self) -> Self::IntoIter {
LL + self.iter()
LL + }
LL + }
|
error: aborting due to 8 previous errors

View file

@ -13,7 +13,14 @@ fn main() {
let _y = 1; // this is fine
let _z = ((), 1); // this as well
if true {
();
// do not lint this, since () is explicit
let _a = ();
let () = dummy();
let () = ();
() = dummy();
() = ();
let _a: () = ();
let _a: () = dummy();
}
consume_units_with_for_loop(); // should be fine as well
@ -23,6 +30,8 @@ fn main() {
let_and_return!(()) // should be fine
}
fn dummy() {}
// Related to issue #1964
fn consume_units_with_for_loop() {
// `for_let_unit` lint should not be triggered by consuming them using for loop.
@ -74,40 +83,29 @@ fn _returns_generic() {
x.then(|| T::default())
}
let _: () = f(); // Ok
let _: () = f(); // Lint.
let _: () = f();
let x: () = f();
let _: () = f2(0i32); // Ok
let _: () = f2(0i32); // Lint.
let _: () = f2(0i32);
let x: () = f2(0i32);
f3(()); // Lint
f3(()); // Lint
let _: () = f3(());
let x: () = f3(());
// Should lint:
// fn f4<T>(mut x: Vec<T>) -> T {
// x.pop().unwrap()
// }
// let _: () = f4(vec![()]);
// let x: () = f4(vec![()]);
fn f4<T>(mut x: Vec<T>) -> T {
x.pop().unwrap()
}
let _: () = f4(vec![()]);
let x: () = f4(vec![()]);
// Ok
let _: () = {
let x = 5;
f2(x)
};
let _: () = if true { f() } else { f2(0) }; // Ok
let _: () = if true { f() } else { f2(0) }; // Lint
let _: () = if true { f() } else { f2(0) };
let x: () = if true { f() } else { f2(0) };
// Ok
let _: () = match Some(0) {
None => f2(1),
Some(0) => f(),
Some(1) => f2(3),
Some(_) => f2('x'),
};
// Lint
match Some(0) {
None => f2(1),
Some(0) => f(),
@ -155,7 +153,7 @@ fn _returns_generic() {
{
let _: () = x;
let _: () = y;
z;
let _: () = z;
let _: () = x1;
let _: () = x2;
let _: () = opt;

View file

@ -13,7 +13,14 @@ fn main() {
let _y = 1; // this is fine
let _z = ((), 1); // this as well
if true {
// do not lint this, since () is explicit
let _a = ();
let () = dummy();
let () = ();
() = dummy();
() = ();
let _a: () = ();
let _a: () = dummy();
}
consume_units_with_for_loop(); // should be fine as well
@ -23,6 +30,8 @@ fn main() {
let_and_return!(()) // should be fine
}
fn dummy() {}
// Related to issue #1964
fn consume_units_with_for_loop() {
// `for_let_unit` lint should not be triggered by consuming them using for loop.
@ -74,41 +83,30 @@ fn _returns_generic() {
x.then(|| T::default())
}
let _: () = f(); // Ok
let x: () = f(); // Lint.
let _: () = f();
let x: () = f();
let _: () = f2(0i32); // Ok
let x: () = f2(0i32); // Lint.
let _: () = f2(0i32);
let x: () = f2(0i32);
let _: () = f3(()); // Lint
let x: () = f3(()); // Lint
let _: () = f3(());
let x: () = f3(());
// Should lint:
// fn f4<T>(mut x: Vec<T>) -> T {
// x.pop().unwrap()
// }
// let _: () = f4(vec![()]);
// let x: () = f4(vec![()]);
fn f4<T>(mut x: Vec<T>) -> T {
x.pop().unwrap()
}
let _: () = f4(vec![()]);
let x: () = f4(vec![()]);
// Ok
let _: () = {
let x = 5;
f2(x)
};
let _: () = if true { f() } else { f2(0) }; // Ok
let x: () = if true { f() } else { f2(0) }; // Lint
let _: () = if true { f() } else { f2(0) };
let x: () = if true { f() } else { f2(0) };
// Ok
let _: () = match Some(0) {
None => f2(1),
Some(0) => f(),
Some(1) => f2(3),
Some(_) => f2('x'),
};
// Lint
let _: () = match Some(0) {
let x = match Some(0) {
None => f2(1),
Some(0) => f(),
Some(1) => f2(3),

View file

@ -8,13 +8,7 @@ LL | let _x = println!("x");
= help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]`
error: this let-binding has unit value
--> $DIR/let_unit.rs:16:9
|
LL | let _a = ();
| ^^^^^^^^^^^^ help: omit the `let` binding: `();`
error: this let-binding has unit value
--> $DIR/let_unit.rs:51:5
--> $DIR/let_unit.rs:60:5
|
LL | / let _ = v
LL | | .into_iter()
@ -37,45 +31,9 @@ LL + .unwrap();
|
error: this let-binding has unit value
--> $DIR/let_unit.rs:78:5
--> $DIR/let_unit.rs:109:5
|
LL | let x: () = f(); // Lint.
| ^^^^-^^^^^^^^^^^
| |
| help: use a wild (`_`) binding: `_`
error: this let-binding has unit value
--> $DIR/let_unit.rs:81:5
|
LL | let x: () = f2(0i32); // Lint.
| ^^^^-^^^^^^^^^^^^^^^^
| |
| help: use a wild (`_`) binding: `_`
error: this let-binding has unit value
--> $DIR/let_unit.rs:83:5
|
LL | let _: () = f3(()); // Lint
| ^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `f3(());`
error: this let-binding has unit value
--> $DIR/let_unit.rs:84:5
|
LL | let x: () = f3(()); // Lint
| ^^^^^^^^^^^^^^^^^^^ help: omit the `let` binding: `f3(());`
error: this let-binding has unit value
--> $DIR/let_unit.rs:100:5
|
LL | let x: () = if true { f() } else { f2(0) }; // Lint
| ^^^^-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: use a wild (`_`) binding: `_`
error: this let-binding has unit value
--> $DIR/let_unit.rs:111:5
|
LL | / let _: () = match Some(0) {
LL | / let x = match Some(0) {
LL | | None => f2(1),
LL | | Some(0) => f(),
LL | | Some(1) => f2(3),
@ -93,11 +51,5 @@ LL + Some(_) => (),
LL + };
|
error: this let-binding has unit value
--> $DIR/let_unit.rs:158:13
|
LL | let _: () = z;
| ^^^^^^^^^^^^^^ help: omit the `let` binding: `z;`
error: aborting due to 10 previous errors
error: aborting due to 3 previous errors

View file

@ -0,0 +1,51 @@
//@aux-build:option_helpers.rs
#![warn(clippy::manual_is_variant_and)]
#[macro_use]
extern crate option_helpers;
#[rustfmt::skip]
fn option_methods() {
let opt = Some(1);
// Check for `option.map(_).unwrap_or_default()` use.
// Single line case.
let _ = opt.is_some_and(|x| x > 1);
// Multi-line cases.
let _ = opt.is_some_and(|x| {
x > 1
});
let _ = opt.is_some_and(|x| x > 1);
let _ = opt
.is_some_and(|x| x > 1);
// won't fix because the return type of the closure is not `bool`
let _ = opt.map(|x| x + 1).unwrap_or_default();
let opt2 = Some('a');
let _ = opt2.is_some_and(char::is_alphanumeric); // should lint
let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
}
#[rustfmt::skip]
fn result_methods() {
let res: Result<i32, ()> = Ok(1);
// multi line cases
let _ = res.is_ok_and(|x| {
x > 1
});
let _ = res.is_ok_and(|x| x > 1);
// won't fix because the return type of the closure is not `bool`
let _ = res.map(|x| x + 1).unwrap_or_default();
let res2: Result<char, ()> = Ok('a');
let _ = res2.is_ok_and(char::is_alphanumeric); // should lint
let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint
}
fn main() {
option_methods();
result_methods();
}

View file

@ -0,0 +1,57 @@
//@aux-build:option_helpers.rs
#![warn(clippy::manual_is_variant_and)]
#[macro_use]
extern crate option_helpers;
#[rustfmt::skip]
fn option_methods() {
let opt = Some(1);
// Check for `option.map(_).unwrap_or_default()` use.
// Single line case.
let _ = opt.map(|x| x > 1)
// Should lint even though this call is on a separate line.
.unwrap_or_default();
// Multi-line cases.
let _ = opt.map(|x| {
x > 1
}
).unwrap_or_default();
let _ = opt.map(|x| x > 1).unwrap_or_default();
let _ = opt
.map(|x| x > 1)
.unwrap_or_default();
// won't fix because the return type of the closure is not `bool`
let _ = opt.map(|x| x + 1).unwrap_or_default();
let opt2 = Some('a');
let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint
}
#[rustfmt::skip]
fn result_methods() {
let res: Result<i32, ()> = Ok(1);
// multi line cases
let _ = res.map(|x| {
x > 1
}
).unwrap_or_default();
let _ = res.map(|x| x > 1)
.unwrap_or_default();
// won't fix because the return type of the closure is not `bool`
let _ = res.map(|x| x + 1).unwrap_or_default();
let res2: Result<char, ()> = Ok('a');
let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint
}
fn main() {
option_methods();
result_methods();
}

View file

@ -0,0 +1,82 @@
error: called `map(<f>).unwrap_or_default()` on an `Option` value
--> $DIR/manual_is_variant_and.rs:13:17
|
LL | let _ = opt.map(|x| x > 1)
| _________________^
LL | | // Should lint even though this call is on a separate line.
LL | | .unwrap_or_default();
| |____________________________^ help: use: `is_some_and(|x| x > 1)`
|
= note: `-D clippy::manual-is-variant-and` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::manual_is_variant_and)]`
error: called `map(<f>).unwrap_or_default()` on an `Option` value
--> $DIR/manual_is_variant_and.rs:17:17
|
LL | let _ = opt.map(|x| {
| _________________^
LL | | x > 1
LL | | }
LL | | ).unwrap_or_default();
| |_________________________^
|
help: use
|
LL ~ let _ = opt.is_some_and(|x| {
LL + x > 1
LL ~ });
|
error: called `map(<f>).unwrap_or_default()` on an `Option` value
--> $DIR/manual_is_variant_and.rs:21:17
|
LL | let _ = opt.map(|x| x > 1).unwrap_or_default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(|x| x > 1)`
error: called `map(<f>).unwrap_or_default()` on an `Option` value
--> $DIR/manual_is_variant_and.rs:23:10
|
LL | .map(|x| x > 1)
| __________^
LL | | .unwrap_or_default();
| |____________________________^ help: use: `is_some_and(|x| x > 1)`
error: called `map(<f>).unwrap_or_default()` on an `Option` value
--> $DIR/manual_is_variant_and.rs:30:18
|
LL | let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(char::is_alphanumeric)`
error: called `map(<f>).unwrap_or_default()` on a `Result` value
--> $DIR/manual_is_variant_and.rs:39:17
|
LL | let _ = res.map(|x| {
| _________________^
LL | | x > 1
LL | | }
LL | | ).unwrap_or_default();
| |_________________________^
|
help: use
|
LL ~ let _ = res.is_ok_and(|x| {
LL + x > 1
LL ~ });
|
error: called `map(<f>).unwrap_or_default()` on a `Result` value
--> $DIR/manual_is_variant_and.rs:43:17
|
LL | let _ = res.map(|x| x > 1)
| _________________^
LL | | .unwrap_or_default();
| |____________________________^ help: use: `is_ok_and(|x| x > 1)`
error: called `map(<f>).unwrap_or_default()` on a `Result` value
--> $DIR/manual_is_variant_and.rs:50:18
|
LL | let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_ok_and(char::is_alphanumeric)`
error: aborting due to 8 previous errors

View file

@ -4,6 +4,8 @@
clippy::iter_cloned_collect,
clippy::many_single_char_names,
clippy::redundant_clone,
clippy::redundant_closure,
clippy::useless_asref,
clippy::useless_vec
)]
@ -60,4 +62,26 @@ fn main() {
let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
}
let x = Some(String::new());
let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint.
let y = x.cloned();
//~^ ERROR: you are explicitly cloning with `.map()`
let y = x.cloned();
//~^ ERROR: you are explicitly cloning with `.map()`
let y = x.cloned();
//~^ ERROR: you are explicitly cloning with `.map()`
// Testing with `Result` now.
let x: Result<String, ()> = Ok(String::new());
let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint.
let y = x.cloned();
//~^ ERROR: you are explicitly cloning with `.map()`
let y = x.cloned();
// We ensure that no warning is emitted here because `useless_asref` is taking over.
let x = Some(String::new());
let y = x.as_ref().map(|x| String::clone(x));
let x: Result<String, ()> = Ok(String::new());
let y = x.as_ref().map(|x| String::clone(x));
}

View file

@ -4,6 +4,8 @@
clippy::iter_cloned_collect,
clippy::many_single_char_names,
clippy::redundant_clone,
clippy::redundant_closure,
clippy::useless_asref,
clippy::useless_vec
)]
@ -60,4 +62,26 @@ fn main() {
let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone());
}
let x = Some(String::new());
let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint.
let y = x.map(|x| String::clone(x));
//~^ ERROR: you are explicitly cloning with `.map()`
let y = x.map(Clone::clone);
//~^ ERROR: you are explicitly cloning with `.map()`
let y = x.map(String::clone);
//~^ ERROR: you are explicitly cloning with `.map()`
// Testing with `Result` now.
let x: Result<String, ()> = Ok(String::new());
let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint.
let y = x.map(|x| String::clone(x));
//~^ ERROR: you are explicitly cloning with `.map()`
let y = x.map(|x| String::clone(x));
// We ensure that no warning is emitted here because `useless_asref` is taking over.
let x = Some(String::new());
let y = x.as_ref().map(|x| String::clone(x));
let x: Result<String, ()> = Ok(String::new());
let y = x.as_ref().map(|x| String::clone(x));
}

View file

@ -1,5 +1,5 @@
error: you are using an explicit closure for copying elements
--> $DIR/map_clone.rs:11:22
--> $DIR/map_clone.rs:13:22
|
LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()`
@ -8,34 +8,64 @@ LL | let _: Vec<i8> = vec![5_i8; 6].iter().map(|x| *x).collect();
= help: to override `-D warnings` add `#[allow(clippy::map_clone)]`
error: you are using an explicit closure for cloning elements
--> $DIR/map_clone.rs:12:26
--> $DIR/map_clone.rs:14:26
|
LL | let _: Vec<String> = vec![String::new()].iter().map(|x| x.clone()).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()`
error: you are using an explicit closure for copying elements
--> $DIR/map_clone.rs:13:23
--> $DIR/map_clone.rs:15:23
|
LL | let _: Vec<u32> = vec![42, 43].iter().map(|&x| x).collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()`
error: you are using an explicit closure for copying elements
--> $DIR/map_clone.rs:15:26
--> $DIR/map_clone.rs:17:26
|
LL | let _: Option<u64> = Some(&16).map(|b| *b);
| ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()`
error: you are using an explicit closure for copying elements
--> $DIR/map_clone.rs:16:25
--> $DIR/map_clone.rs:18:25
|
LL | let _: Option<u8> = Some(&1).map(|x| x.clone());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()`
error: you are needlessly cloning iterator elements
--> $DIR/map_clone.rs:27:29
--> $DIR/map_clone.rs:29:29
|
LL | let _ = std::env::args().map(|v| v.clone());
| ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call
error: aborting due to 6 previous errors
error: you are explicitly cloning with `.map()`
--> $DIR/map_clone.rs:68:13
|
LL | let y = x.map(|x| String::clone(x));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
error: you are explicitly cloning with `.map()`
--> $DIR/map_clone.rs:70:13
|
LL | let y = x.map(Clone::clone);
| ^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
error: you are explicitly cloning with `.map()`
--> $DIR/map_clone.rs:72:13
|
LL | let y = x.map(String::clone);
| ^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
error: you are explicitly cloning with `.map()`
--> $DIR/map_clone.rs:78:13
|
LL | let y = x.map(|x| String::clone(x));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
error: you are explicitly cloning with `.map()`
--> $DIR/map_clone.rs:80:13
|
LL | let y = x.map(|x| String::clone(x));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()`
error: aborting due to 11 previous errors

View file

@ -1,9 +1,5 @@
#![feature(never_type)]
#![allow(
unused_mut,
clippy::redundant_allocation,
clippy::needless_pass_by_ref_mut
)]
#![allow(unused_mut, clippy::redundant_allocation, clippy::needless_pass_by_ref_mut)]
#![warn(clippy::must_use_candidate)]
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};

View file

@ -1,9 +1,5 @@
#![feature(never_type)]
#![allow(
unused_mut,
clippy::redundant_allocation,
clippy::needless_pass_by_ref_mut
)]
#![allow(unused_mut, clippy::redundant_allocation, clippy::needless_pass_by_ref_mut)]
#![warn(clippy::must_use_candidate)]
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};

View file

@ -1,5 +1,5 @@
error: this function could have a `#[must_use]` attribute
--> $DIR/must_use_candidates.rs:15:1
--> $DIR/must_use_candidates.rs:11:1
|
LL | pub fn pure(i: u8) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn pure(i: u8) -> u8`
@ -8,25 +8,25 @@ LL | pub fn pure(i: u8) -> u8 {
= help: to override `-D warnings` add `#[allow(clippy::must_use_candidate)]`
error: this method could have a `#[must_use]` attribute
--> $DIR/must_use_candidates.rs:20:5
--> $DIR/must_use_candidates.rs:16:5
|
LL | pub fn inherent_pure(&self) -> u8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8`
error: this function could have a `#[must_use]` attribute
--> $DIR/must_use_candidates.rs:51:1
--> $DIR/must_use_candidates.rs:47:1
|
LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool`
error: this function could have a `#[must_use]` attribute
--> $DIR/must_use_candidates.rs:63:1
--> $DIR/must_use_candidates.rs:59:1
|
LL | pub fn rcd(_x: Rc<u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc<u32>) -> bool`
error: this function could have a `#[must_use]` attribute
--> $DIR/must_use_candidates.rs:71:1
--> $DIR/must_use_candidates.rs:67:1
|
LL | pub fn arcd(_x: Arc<u32>) -> bool {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc<u32>) -> bool`

View file

@ -18,9 +18,24 @@ fn main() {
Mutex::new(&mut x as *mut u32);
//~^ ERROR: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want
Mutex::new(0u32);
//~^ ERROR: consider using an `AtomicUsize` instead of a `Mutex` here; if you just wan
//~^ ERROR: consider using an `AtomicU32` instead of a `Mutex` here; if you just wan
//~| NOTE: `-D clippy::mutex-integer` implied by `-D warnings`
Mutex::new(0i32);
//~^ ERROR: consider using an `AtomicIsize` instead of a `Mutex` here; if you just wan
//~^ ERROR: consider using an `AtomicI32` instead of a `Mutex` here; if you just wan
Mutex::new(0f32); // there are no float atomics, so this should not lint
Mutex::new(0u8);
//~^ ERROR: consider using an `AtomicU8` instead of a `Mutex` here; if you just wan
Mutex::new(0i16);
//~^ ERROR: consider using an `AtomicI16` instead of a `Mutex` here; if you just wan
let _x: Mutex<i8> = Mutex::new(0);
//~^ ERROR: consider using an `AtomicI8` instead of a `Mutex` here; if you just wan
const X: i64 = 0;
Mutex::new(X);
//~^ ERROR: consider using an `AtomicI64` instead of a `Mutex` here; if you just wan
// there are no 128 atomics, so these two should not lint
{
Mutex::new(0u128);
let _x: Mutex<i128> = Mutex::new(0);
}
}

View file

@ -31,7 +31,7 @@ error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want
LL | Mutex::new(&mut x as *mut u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
error: consider using an `AtomicU32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
--> $DIR/mutex_atomic.rs:20:5
|
LL | Mutex::new(0u32);
@ -40,11 +40,35 @@ LL | Mutex::new(0u32);
= note: `-D clippy::mutex-integer` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]`
error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
error: consider using an `AtomicI32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
--> $DIR/mutex_atomic.rs:23:5
|
LL | Mutex::new(0i32);
| ^^^^^^^^^^^^^^^^
error: aborting due to 7 previous errors
error: consider using an `AtomicU8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
--> $DIR/mutex_atomic.rs:26:5
|
LL | Mutex::new(0u8);
| ^^^^^^^^^^^^^^^
error: consider using an `AtomicI16` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
--> $DIR/mutex_atomic.rs:28:5
|
LL | Mutex::new(0i16);
| ^^^^^^^^^^^^^^^^
error: consider using an `AtomicI8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
--> $DIR/mutex_atomic.rs:30:25
|
LL | let _x: Mutex<i8> = Mutex::new(0);
| ^^^^^^^^^^^^^
error: consider using an `AtomicI64` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
--> $DIR/mutex_atomic.rs:33:5
|
LL | Mutex::new(X);
| ^^^^^^^^^^^^^
error: aborting due to 11 previous errors

View file

@ -10,7 +10,7 @@
/// unimplemented!();
/// }
/// ```
///
///
/// With an explicit return type it should lint too
/// ```edition2015
/// fn main() -> () {
@ -18,7 +18,7 @@
/// unimplemented!();
/// }
/// ```
///
///
/// This should, too.
/// ```rust
/// fn main() {
@ -26,7 +26,7 @@
/// unimplemented!();
/// }
/// ```
///
///
/// This one too.
/// ```no_run
/// // the fn is not always the first line

View file

@ -25,9 +25,13 @@ fn main() {
permissions.set_mode(0o644);
permissions.set_mode(0o704);
// no error
permissions.set_mode(0b111_000_100);
// DirBuilderExt::mode
let mut builder = DirBuilder::new();
builder.mode(0o755);
builder.mode(0o406);
// no error
permissions.set_mode(0b111000100);
}

View file

@ -25,9 +25,13 @@ fn main() {
permissions.set_mode(644);
permissions.set_mode(0o704);
// no error
permissions.set_mode(0b111_000_100);
// DirBuilderExt::mode
let mut builder = DirBuilder::new();
builder.mode(755);
builder.mode(0o406);
// no error
permissions.set_mode(0b111000100);
}

View file

@ -20,7 +20,7 @@ LL | permissions.set_mode(644);
| ^^^ help: consider using an octal literal instead: `0o644`
error: using a non-octal value to set unix file permissions
--> $DIR/non_octal_unix_permissions.rs:31:18
--> $DIR/non_octal_unix_permissions.rs:33:18
|
LL | builder.mode(755);
| ^^^ help: consider using an octal literal instead: `0o755`

View file

@ -0,0 +1,21 @@
#![warn(clippy::option_as_ref_cloned)]
#![allow(clippy::clone_on_copy)]
fn main() {
let mut x = Some(String::new());
let _: Option<String> = x.clone();
let _: Option<String> = x.clone();
let y = x.as_ref();
let _: Option<&String> = y.clone();
macro_rules! cloned_recv {
() => {
x.as_ref()
};
}
// Don't lint when part of the expression is from a macro
let _: Option<String> = cloned_recv!().cloned();
}

View file

@ -0,0 +1,21 @@
#![warn(clippy::option_as_ref_cloned)]
#![allow(clippy::clone_on_copy)]
fn main() {
let mut x = Some(String::new());
let _: Option<String> = x.as_ref().cloned();
let _: Option<String> = x.as_mut().cloned();
let y = x.as_ref();
let _: Option<&String> = y.as_ref().cloned();
macro_rules! cloned_recv {
() => {
x.as_ref()
};
}
// Don't lint when part of the expression is from a macro
let _: Option<String> = cloned_recv!().cloned();
}

View file

@ -0,0 +1,37 @@
error: cloning an `Option<_>` using `.as_ref().cloned()`
--> $DIR/option_as_ref_cloned.rs:7:31
|
LL | let _: Option<String> = x.as_ref().cloned();
| ^^^^^^^^^^^^^^^
|
= note: `-D clippy::option-as-ref-cloned` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::option_as_ref_cloned)]`
help: this can be written more concisely by cloning the `Option<_>` directly
|
LL | let _: Option<String> = x.clone();
| ~~~~~
error: cloning an `Option<_>` using `.as_mut().cloned()`
--> $DIR/option_as_ref_cloned.rs:8:31
|
LL | let _: Option<String> = x.as_mut().cloned();
| ^^^^^^^^^^^^^^^
|
help: this can be written more concisely by cloning the `Option<_>` directly
|
LL | let _: Option<String> = x.clone();
| ~~~~~
error: cloning an `Option<_>` using `.as_ref().cloned()`
--> $DIR/option_as_ref_cloned.rs:11:32
|
LL | let _: Option<&String> = y.as_ref().cloned();
| ^^^^^^^^^^^^^^^
|
help: this can be written more concisely by cloning the `Option<_>` directly
|
LL | let _: Option<&String> = y.clone();
| ~~~~~
error: aborting due to 3 previous errors

View file

@ -11,7 +11,7 @@ fn main() {
let _no_as_str = string.as_bytes();
let _no_as_str = string.is_empty();
// These methods are not redundant, and are equivelant to
// These methods are not redundant, and are equivalent to
// doing dereferencing the string and applying the method
let _not_redundant = string.as_str().escape_unicode();
let _not_redundant = string.as_str().trim();

View file

@ -11,7 +11,7 @@ fn main() {
let _no_as_str = string.as_bytes();
let _no_as_str = string.is_empty();
// These methods are not redundant, and are equivelant to
// These methods are not redundant, and are equivalent to
// doing dereferencing the string and applying the method
let _not_redundant = string.as_str().escape_unicode();
let _not_redundant = string.as_str().trim();

View file

@ -113,7 +113,7 @@ fn trivial_regex() {
// #6005: unicode classes in bytes::Regex
let a_byte_of_unicode = BRegex::new(r"\p{C}");
// start and end word boundry, introduced in regex 0.10
// start and end word boundary, introduced in regex 0.10
let _ = BRegex::new(r"\<word\>");
let _ = BRegex::new(r"\b{start}word\b{end}");
}

View file

@ -42,6 +42,8 @@ fn main() {
x.split('\n');
x.split('\'');
x.split('\'');
// Issue #11973: Don't escape `"` in `'"'`
x.split('"');
let h = HashSet::<String>::new();
h.contains("X"); // should not warn

View file

@ -42,6 +42,8 @@ fn main() {
x.split("\n");
x.split("'");
x.split("\'");
// Issue #11973: Don't escape `"` in `'"'`
x.split("\"");
let h = HashSet::<String>::new();
h.contains("X"); // should not warn

View file

@ -182,58 +182,64 @@ LL | x.split("\'");
| ^^^^ help: try using a `char` instead: `'\''`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:49:31
--> $DIR/single_char_pattern.rs:46:13
|
LL | x.split("\"");
| ^^^^ help: try using a `char` instead: `'"'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:51:31
|
LL | x.replace(';', ",").split(","); // issue #2978
| ^^^ help: try using a `char` instead: `','`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:50:19
--> $DIR/single_char_pattern.rs:52:19
|
LL | x.starts_with("\x03"); // issue #2996
| ^^^^^^ help: try using a `char` instead: `'\x03'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:57:13
--> $DIR/single_char_pattern.rs:59:13
|
LL | x.split(r"a");
| ^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:58:13
--> $DIR/single_char_pattern.rs:60:13
|
LL | x.split(r#"a"#);
| ^^^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:59:13
--> $DIR/single_char_pattern.rs:61:13
|
LL | x.split(r###"a"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'a'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:60:13
--> $DIR/single_char_pattern.rs:62:13
|
LL | x.split(r###"'"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'\''`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:61:13
--> $DIR/single_char_pattern.rs:63:13
|
LL | x.split(r###"#"###);
| ^^^^^^^^^^ help: try using a `char` instead: `'#'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:63:13
--> $DIR/single_char_pattern.rs:65:13
|
LL | x.split(r#"\"#);
| ^^^^^^ help: try using a `char` instead: `'\\'`
error: single-character string constant used as pattern
--> $DIR/single_char_pattern.rs:64:13
--> $DIR/single_char_pattern.rs:66:13
|
LL | x.split(r"\");
| ^^^^ help: try using a `char` instead: `'\\'`
error: aborting due to 39 previous errors
error: aborting due to 40 previous errors

145
tests/ui/str_split.fixed Normal file
View file

@ -0,0 +1,145 @@
#![warn(clippy::str_split_at_newline)]
use core::str::Split;
use std::ops::Deref;
struct NotStr<'a> {
s: &'a str,
}
impl<'a> NotStr<'a> {
fn trim(&'a self) -> &'a str {
self.s
}
}
struct DerefsIntoNotStr<'a> {
not_str: &'a NotStr<'a>,
}
impl<'a> Deref for DerefsIntoNotStr<'a> {
type Target = NotStr<'a>;
fn deref(&self) -> &Self::Target {
self.not_str
}
}
struct DerefsIntoStr<'a> {
s: &'a str,
}
impl<'a> Deref for DerefsIntoStr<'a> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.s
}
}
macro_rules! trim_split {
( $x:expr, $y:expr ) => {
$x.trim().split($y);
};
}
macro_rules! make_str {
( $x: expr ) => {
format!("x={}", $x)
};
}
fn main() {
let s1 = "hello\nworld\n";
let s2 = s1.to_owned();
// CASES THAT SHOULD EMIT A LINT
// Splitting a `str` variable at "\n" or "\r\n" after trimming should warn
let _ = s1.lines();
#[allow(clippy::single_char_pattern)]
let _ = s1.lines();
let _ = s1.lines();
// Splitting a `String` variable at "\n" or "\r\n" after trimming should warn
let _ = s2.lines();
#[allow(clippy::single_char_pattern)]
let _ = s2.lines();
let _ = s2.lines();
// Splitting a variable that derefs into `str` at "\n" or "\r\n" after trimming should warn.
let s3 = DerefsIntoStr { s: s1 };
let _ = s3.lines();
#[allow(clippy::single_char_pattern)]
let _ = s3.lines();
let _ = s3.lines();
// If the `&str` is generated by a macro then the macro should not be expanded in the suggested fix.
let _ = make_str!(s1).lines();
// CASES THAT SHOULD NOT EMIT A LINT
// Splitting a `str` constant at "\n" or "\r\n" after trimming should not warn
let _ = "hello\nworld\n".trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = "hello\nworld\n".trim().split("\n");
let _ = "hello\nworld\n".trim().split("\r\n");
// Splitting a `str` variable at "\n" or "\r\n" without trimming should not warn, since it is not
// equivalent
let _ = s1.split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s1.split("\n");
let _ = s1.split("\r\n");
// Splitting a `String` variable at "\n" or "\r\n" without trimming should not warn.
let _ = s2.split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s2.split("\n");
// Splitting a variable that derefs into `str` at "\n" or "\r\n" without trimming should not warn.
let _ = s3.split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s3.split("\n");
let _ = s3.split("\r\n");
let _ = s2.split("\r\n");
// Splitting a `str` variable at other separators should not warn
let _ = s1.trim().split('\r');
#[allow(clippy::single_char_pattern)]
let _ = s1.trim().split("\r");
let _ = s1.trim().split("\n\r");
let _ = s1.trim().split("\r \n");
// Splitting a `String` variable at other separators should not warn
let _ = s2.trim().split('\r');
#[allow(clippy::single_char_pattern)]
let _ = s2.trim().split("\r");
let _ = s2.trim().split("\n\r");
// Splitting a variable that derefs into `str` at other separators should not warn
let _ = s3.trim().split('\r');
#[allow(clippy::single_char_pattern)]
let _ = s3.trim().split("\r");
let _ = s3.trim().split("\n\r");
let _ = s3.trim().split("\r \n");
let _ = s2.trim().split("\r \n");
// Using `trim` and `split` on other types should not warn
let not_str = NotStr { s: s1 };
let _ = not_str.trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = not_str.trim().split("\n");
let _ = not_str.trim().split("\r\n");
let derefs_into_not_str = DerefsIntoNotStr { not_str: &not_str };
let _ = derefs_into_not_str.trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = derefs_into_not_str.trim().split("\n");
let _ = derefs_into_not_str.trim().split("\r\n");
// Code generated by macros should not create a warning
trim_split!(s1, "\r\n");
trim_split!("hello\nworld\n", "\r\n");
trim_split!(s2, "\r\n");
trim_split!(s3, "\r\n");
}

145
tests/ui/str_split.rs Normal file
View file

@ -0,0 +1,145 @@
#![warn(clippy::str_split_at_newline)]
use core::str::Split;
use std::ops::Deref;
struct NotStr<'a> {
s: &'a str,
}
impl<'a> NotStr<'a> {
fn trim(&'a self) -> &'a str {
self.s
}
}
struct DerefsIntoNotStr<'a> {
not_str: &'a NotStr<'a>,
}
impl<'a> Deref for DerefsIntoNotStr<'a> {
type Target = NotStr<'a>;
fn deref(&self) -> &Self::Target {
self.not_str
}
}
struct DerefsIntoStr<'a> {
s: &'a str,
}
impl<'a> Deref for DerefsIntoStr<'a> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.s
}
}
macro_rules! trim_split {
( $x:expr, $y:expr ) => {
$x.trim().split($y);
};
}
macro_rules! make_str {
( $x: expr ) => {
format!("x={}", $x)
};
}
fn main() {
let s1 = "hello\nworld\n";
let s2 = s1.to_owned();
// CASES THAT SHOULD EMIT A LINT
// Splitting a `str` variable at "\n" or "\r\n" after trimming should warn
let _ = s1.trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s1.trim().split("\n");
let _ = s1.trim().split("\r\n");
// Splitting a `String` variable at "\n" or "\r\n" after trimming should warn
let _ = s2.trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s2.trim().split("\n");
let _ = s2.trim().split("\r\n");
// Splitting a variable that derefs into `str` at "\n" or "\r\n" after trimming should warn.
let s3 = DerefsIntoStr { s: s1 };
let _ = s3.trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s3.trim().split("\n");
let _ = s3.trim().split("\r\n");
// If the `&str` is generated by a macro then the macro should not be expanded in the suggested fix.
let _ = make_str!(s1).trim().split('\n');
// CASES THAT SHOULD NOT EMIT A LINT
// Splitting a `str` constant at "\n" or "\r\n" after trimming should not warn
let _ = "hello\nworld\n".trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = "hello\nworld\n".trim().split("\n");
let _ = "hello\nworld\n".trim().split("\r\n");
// Splitting a `str` variable at "\n" or "\r\n" without trimming should not warn, since it is not
// equivalent
let _ = s1.split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s1.split("\n");
let _ = s1.split("\r\n");
// Splitting a `String` variable at "\n" or "\r\n" without trimming should not warn.
let _ = s2.split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s2.split("\n");
// Splitting a variable that derefs into `str` at "\n" or "\r\n" without trimming should not warn.
let _ = s3.split('\n');
#[allow(clippy::single_char_pattern)]
let _ = s3.split("\n");
let _ = s3.split("\r\n");
let _ = s2.split("\r\n");
// Splitting a `str` variable at other separators should not warn
let _ = s1.trim().split('\r');
#[allow(clippy::single_char_pattern)]
let _ = s1.trim().split("\r");
let _ = s1.trim().split("\n\r");
let _ = s1.trim().split("\r \n");
// Splitting a `String` variable at other separators should not warn
let _ = s2.trim().split('\r');
#[allow(clippy::single_char_pattern)]
let _ = s2.trim().split("\r");
let _ = s2.trim().split("\n\r");
// Splitting a variable that derefs into `str` at other separators should not warn
let _ = s3.trim().split('\r');
#[allow(clippy::single_char_pattern)]
let _ = s3.trim().split("\r");
let _ = s3.trim().split("\n\r");
let _ = s3.trim().split("\r \n");
let _ = s2.trim().split("\r \n");
// Using `trim` and `split` on other types should not warn
let not_str = NotStr { s: s1 };
let _ = not_str.trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = not_str.trim().split("\n");
let _ = not_str.trim().split("\r\n");
let derefs_into_not_str = DerefsIntoNotStr { not_str: &not_str };
let _ = derefs_into_not_str.trim().split('\n');
#[allow(clippy::single_char_pattern)]
let _ = derefs_into_not_str.trim().split("\n");
let _ = derefs_into_not_str.trim().split("\r\n");
// Code generated by macros should not create a warning
trim_split!(s1, "\r\n");
trim_split!("hello\nworld\n", "\r\n");
trim_split!(s2, "\r\n");
trim_split!(s3, "\r\n");
}

65
tests/ui/str_split.stderr Normal file
View file

@ -0,0 +1,65 @@
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:59:13
|
LL | let _ = s1.trim().split('\n');
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
|
= note: `-D clippy::str-split-at-newline` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::str_split_at_newline)]`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:61:13
|
LL | let _ = s1.trim().split("\n");
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:62:13
|
LL | let _ = s1.trim().split("\r\n");
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:65:13
|
LL | let _ = s2.trim().split('\n');
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:67:13
|
LL | let _ = s2.trim().split("\n");
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:68:13
|
LL | let _ = s2.trim().split("\r\n");
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:72:13
|
LL | let _ = s3.trim().split('\n');
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:74:13
|
LL | let _ = s3.trim().split("\n");
| ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:75:13
|
LL | let _ = s3.trim().split("\r\n");
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()`
error: using `str.trim().split()` with hard-coded newlines
--> $DIR/str_split.rs:78:13
|
LL | let _ = make_str!(s1).trim().split('\n');
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `make_str!(s1).lines()`
error: aborting due to 10 previous errors

View file

@ -39,14 +39,14 @@ struct DataStruct {
struct DoublePrefix {
//~^ ERROR: all fields have the same prefix: `some_data`
some_data_a: bool,
some_data_b: bool,
some_data_b: i8,
some_data_c: bool,
}
struct DoublePostfix {
//~^ ERROR: all fields have the same postfix: `some_data`
a_some_data: bool,
b_some_data: bool,
b_some_data: i8,
c_some_data: bool,
}
@ -54,18 +54,18 @@ struct DoublePostfix {
struct NotSnakeCase {
//~^ ERROR: all fields have the same postfix: `someData`
a_someData: bool,
b_someData: bool,
b_someData: i8,
c_someData: bool,
}
#[allow(non_snake_case)]
struct NotSnakeCase2 {
//~^ ERROR: all fields have the same prefix: `someData`
someData_c: bool,
someData_b: bool,
someData_b: i8,
someData_a_b: bool,
}
// no error, threshold is 3 fiels by default
// no error, threshold is 3 fields by default
struct Fooo {
foo: u8,
bar: u8,
@ -328,4 +328,18 @@ external! {
}
// Should not warn
struct Config {
use_foo: bool,
use_bar: bool,
use_baz: bool,
}
struct Use {
use_foo: bool,
//~^ ERROR: field name starts with the struct's name
use_bar: bool,
use_baz: bool,
}
fn main() {}

View file

@ -45,7 +45,7 @@ error: all fields have the same prefix: `some_data`
LL | / struct DoublePrefix {
LL | |
LL | | some_data_a: bool,
LL | | some_data_b: bool,
LL | | some_data_b: i8,
LL | | some_data_c: bool,
LL | | }
| |_^
@ -58,7 +58,7 @@ error: all fields have the same postfix: `some_data`
LL | / struct DoublePostfix {
LL | |
LL | | a_some_data: bool,
LL | | b_some_data: bool,
LL | | b_some_data: i8,
LL | | c_some_data: bool,
LL | | }
| |_^
@ -71,7 +71,7 @@ error: all fields have the same postfix: `someData`
LL | / struct NotSnakeCase {
LL | |
LL | | a_someData: bool,
LL | | b_someData: bool,
LL | | b_someData: i8,
LL | | c_someData: bool,
LL | | }
| |_^
@ -84,7 +84,7 @@ error: all fields have the same prefix: `someData`
LL | / struct NotSnakeCase2 {
LL | |
LL | | someData_c: bool,
LL | | someData_b: bool,
LL | | someData_b: i8,
LL | | someData_a_b: bool,
LL | | }
| |_^
@ -261,5 +261,23 @@ LL | mk_struct_full_def!(PrefixData, some_data, some_meta, some_other);
= help: remove the prefixes
= note: this error originates in the macro `mk_struct_full_def` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 21 previous errors
error: field name starts with the struct's name
--> $DIR/struct_fields.rs:339:5
|
LL | use_foo: bool,
| ^^^^^^^^^^^^^
error: field name starts with the struct's name
--> $DIR/struct_fields.rs:341:5
|
LL | use_bar: bool,
| ^^^^^^^^^^^^^
error: field name starts with the struct's name
--> $DIR/struct_fields.rs:342:5
|
LL | use_baz: bool,
| ^^^^^^^^^^^^^
error: aborting due to 24 previous errors

View file

@ -1,5 +1,4 @@
#![warn(clippy::temporary_assignment)]
#![allow(const_item_mutation)]
use std::ops::{Deref, DerefMut};

View file

@ -1,5 +1,5 @@
error: assignment to temporary
--> $DIR/temporary_assignment.rs:48:5
--> $DIR/temporary_assignment.rs:47:5
|
LL | Struct { field: 0 }.field = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -8,7 +8,7 @@ LL | Struct { field: 0 }.field = 1;
= help: to override `-D warnings` add `#[allow(clippy::temporary_assignment)]`
error: assignment to temporary
--> $DIR/temporary_assignment.rs:51:5
--> $DIR/temporary_assignment.rs:50:5
|
LL | / MultiStruct {
LL | |
@ -19,13 +19,13 @@ LL | | .field = 1;
| |______________^
error: assignment to temporary
--> $DIR/temporary_assignment.rs:57:5
--> $DIR/temporary_assignment.rs:56:5
|
LL | ArrayStruct { array: [0] }.array[0] = 1;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: assignment to temporary
--> $DIR/temporary_assignment.rs:59:5
--> $DIR/temporary_assignment.rs:58:5
|
LL | (0, 0).0 = 1;
| ^^^^^^^^^^^^

View file

@ -0,0 +1,30 @@
#![warn(clippy::thread_local_initializer_can_be_made_const)]
use std::cell::RefCell;
fn main() {
// lint and suggest const
thread_local! {
static BUF_1: RefCell<String> = const { RefCell::new(String::new()) };
}
//~^^ ERROR: initializer for `thread_local` value can be made `const`
// don't lint
thread_local! {
static BUF_2: RefCell<String> = const { RefCell::new(String::new()) };
}
thread_local! {
static SIMPLE:i32 = const { 1 };
}
//~^^ ERROR: initializer for `thread_local` value can be made `const`
// lint and suggest const for all non const items
thread_local! {
static BUF_3_CAN_BE_MADE_CONST: RefCell<String> = const { RefCell::new(String::new()) };
static CONST_MIXED_WITH:i32 = const { 1 };
static BUF_4_CAN_BE_MADE_CONST: RefCell<String> = const { RefCell::new(String::new()) };
}
//~^^^^ ERROR: initializer for `thread_local` value can be made `const`
//~^^^ ERROR: initializer for `thread_local` value can be made `const`
}

View file

@ -0,0 +1,30 @@
#![warn(clippy::thread_local_initializer_can_be_made_const)]
use std::cell::RefCell;
fn main() {
// lint and suggest const
thread_local! {
static BUF_1: RefCell<String> = RefCell::new(String::new());
}
//~^^ ERROR: initializer for `thread_local` value can be made `const`
// don't lint
thread_local! {
static BUF_2: RefCell<String> = const { RefCell::new(String::new()) };
}
thread_local! {
static SIMPLE:i32 = 1;
}
//~^^ ERROR: initializer for `thread_local` value can be made `const`
// lint and suggest const for all non const items
thread_local! {
static BUF_3_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
static CONST_MIXED_WITH:i32 = const { 1 };
static BUF_4_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
}
//~^^^^ ERROR: initializer for `thread_local` value can be made `const`
//~^^^ ERROR: initializer for `thread_local` value can be made `const`
}

View file

@ -0,0 +1,29 @@
error: initializer for `thread_local` value can be made `const`
--> $DIR/thread_local_initializer_can_be_made_const.rs:8:41
|
LL | static BUF_1: RefCell<String> = RefCell::new(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
|
= note: `-D clippy::thread-local-initializer-can-be-made-const` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::thread_local_initializer_can_be_made_const)]`
error: initializer for `thread_local` value can be made `const`
--> $DIR/thread_local_initializer_can_be_made_const.rs:18:29
|
LL | static SIMPLE:i32 = 1;
| ^ help: replace with: `const { 1 }`
error: initializer for `thread_local` value can be made `const`
--> $DIR/thread_local_initializer_can_be_made_const.rs:24:59
|
LL | static BUF_3_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
error: initializer for `thread_local` value can be made `const`
--> $DIR/thread_local_initializer_can_be_made_const.rs:26:59
|
LL | static BUF_4_CAN_BE_MADE_CONST: RefCell<String> = RefCell::new(String::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }`
error: aborting due to 4 previous errors

View file

@ -0,0 +1,8 @@
//@compile-flags: -C incremental=target/debug/test/incr
// see https://github.com/rust-lang/rust-clippy/issues/10969
fn main() {
let s = "Hello, world!";
println!("{}", s.to_string());
}

View file

@ -0,0 +1,11 @@
error: `to_string` applied to a type that implements `Display` in `println!` args
--> $DIR/to_string_in_format_args_incremental.rs:7:21
|
LL | println!("{}", s.to_string());
| ^^^^^^^^^^^^ help: remove this
|
= note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::to_string_in_format_args)]`
error: aborting due to 1 previous error

View file

@ -1,7 +1,7 @@
//@no-rustfix
#![warn(clippy::unconditional_recursion)]
#![allow(clippy::partialeq_ne_impl)]
#![allow(clippy::partialeq_ne_impl, clippy::default_constructed_unit_structs)]
enum Foo {
A,
@ -158,6 +158,112 @@ struct S5;
impl_partial_eq!(S5);
//~^ ERROR: function cannot return without recursing
struct S6 {
field: String,
}
impl PartialEq for S6 {
fn eq(&self, other: &Self) -> bool {
let mine = &self.field;
let theirs = &other.field;
mine == theirs // Should not warn!
}
}
struct S7<'a> {
field: &'a S7<'a>,
}
impl<'a> PartialEq for S7<'a> {
fn eq(&self, other: &Self) -> bool {
//~^ ERROR: function cannot return without recursing
let mine = &self.field;
let theirs = &other.field;
mine == theirs
}
}
struct S8 {
num: i32,
field: Option<Box<S8>>,
}
impl PartialEq for S8 {
fn eq(&self, other: &Self) -> bool {
if self.num != other.num {
return false;
}
let (this, other) = match (self.field.as_deref(), other.field.as_deref()) {
(Some(x1), Some(x2)) => (x1, x2),
(None, None) => return true,
_ => return false,
};
this == other
}
}
struct S9;
impl std::string::ToString for S9 {
fn to_string(&self) -> String {
//~^ ERROR: function cannot return without recursing
self.to_string()
}
}
struct S10;
impl std::string::ToString for S10 {
fn to_string(&self) -> String {
//~^ ERROR: function cannot return without recursing
let x = self;
x.to_string()
}
}
struct S11;
impl std::string::ToString for S11 {
fn to_string(&self) -> String {
//~^ ERROR: function cannot return without recursing
(self as &Self).to_string()
}
}
struct S12;
impl std::default::Default for S12 {
fn default() -> Self {
Self::new()
}
}
impl S12 {
fn new() -> Self {
//~^ ERROR: function cannot return without recursing
Self::default()
}
fn bar() -> Self {
// Should not warn!
Self::default()
}
}
#[derive(Default)]
struct S13 {
f: u32,
}
impl S13 {
fn new() -> Self {
// Shoud not warn!
Self::default()
}
}
fn main() {
// test code goes here
}

View file

@ -22,6 +22,39 @@ LL | self.eq(other)
|
= help: a `loop` may express intention better if this is on purpose
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:210:5
|
LL | fn to_string(&self) -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
LL |
LL | self.to_string()
| ---------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:219:5
|
LL | fn to_string(&self) -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
...
LL | x.to_string()
| ------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:229:5
|
LL | fn to_string(&self) -> String {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
LL |
LL | (self as &Self).to_string()
| --------------------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:12:5
|
@ -54,6 +87,34 @@ note: recursive call site
LL | self == other
| ^^^^^^^^^^^^^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:28:5
|
LL | / fn ne(&self, other: &Self) -> bool {
LL | | self != &Foo2::B // no error here
LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:29:9
|
LL | self != &Foo2::B // no error here
| ^^^^^^^^^^^^^^^^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:31:5
|
LL | / fn eq(&self, other: &Self) -> bool {
LL | | self == &Foo2::B // no error here
LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:32:9
|
LL | self == &Foo2::B // no error here
| ^^^^^^^^^^^^^^^^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:42:5
|
@ -247,5 +308,37 @@ LL | impl_partial_eq!(S5);
| -------------------- in this macro invocation
= note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 19 previous errors
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:178:5
|
LL | / fn eq(&self, other: &Self) -> bool {
LL | |
LL | | let mine = &self.field;
LL | | let theirs = &other.field;
LL | | mine == theirs
LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:182:9
|
LL | mine == theirs
| ^^^^^^^^^^^^^^
error: function cannot return without recursing
--> $DIR/unconditional_recursion.rs:244:5
|
LL | / fn new() -> Self {
LL | |
LL | | Self::default()
LL | | }
| |_____^
|
note: recursive call site
--> $DIR/unconditional_recursion.rs:246:9
|
LL | Self::default()
| ^^^^^^^^^^^^^^^
error: aborting due to 26 previous errors

View file

@ -47,6 +47,18 @@ impl Drop for Issue9427FollowUp {
}
}
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) {}
}
struct Issue10437;
impl Deref for Issue10437 {
type Target = u32;
@ -128,6 +140,7 @@ fn main() {
// Should not lint - bool
let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop
let _ = false.then(|| Issue9427Followup2 { ptr: std::ptr::null() });
// should not lint, bind_instead_of_map takes priority
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));

View file

@ -47,6 +47,18 @@ impl Drop for Issue9427FollowUp {
}
}
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) {}
}
struct Issue10437;
impl Deref for Issue10437 {
type Target = u32;
@ -128,6 +140,7 @@ fn main() {
// Should not lint - bool
let _ = (0 == 1).then(|| Issue9427(0)); // Issue9427 has a significant drop
let _ = false.then(|| Issue9427FollowUp); // Issue9427FollowUp has a significant drop
let _ = false.then(|| Issue9427Followup2 { ptr: std::ptr::null() });
// should not lint, bind_instead_of_map takes priority
let _ = Some(10).and_then(|idx| Some(ext_arr[idx]));

View file

@ -1,5 +1,5 @@
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:71:13
--> $DIR/unnecessary_lazy_eval.rs:83:13
|
LL | let _ = opt.unwrap_or_else(|| 2);
| ^^^^--------------------
@ -10,7 +10,7 @@ LL | let _ = opt.unwrap_or_else(|| 2);
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:72:13
--> $DIR/unnecessary_lazy_eval.rs:84:13
|
LL | let _ = opt.unwrap_or_else(|| astronomers_pi);
| ^^^^---------------------------------
@ -18,7 +18,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi);
| help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:73:13
--> $DIR/unnecessary_lazy_eval.rs:85:13
|
LL | let _ = opt.unwrap_or_else(|| ext_str.some_field);
| ^^^^-------------------------------------
@ -26,7 +26,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field);
| help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:75:13
--> $DIR/unnecessary_lazy_eval.rs:87:13
|
LL | let _ = opt.and_then(|_| ext_opt);
| ^^^^---------------------
@ -34,7 +34,7 @@ LL | let _ = opt.and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:76:13
--> $DIR/unnecessary_lazy_eval.rs:88:13
|
LL | let _ = opt.or_else(|| ext_opt);
| ^^^^-------------------
@ -42,7 +42,7 @@ LL | let _ = opt.or_else(|| ext_opt);
| help: use `or(..)` instead: `or(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:77:13
--> $DIR/unnecessary_lazy_eval.rs:89:13
|
LL | let _ = opt.or_else(|| None);
| ^^^^----------------
@ -50,7 +50,7 @@ LL | let _ = opt.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:78:13
--> $DIR/unnecessary_lazy_eval.rs:90:13
|
LL | let _ = opt.get_or_insert_with(|| 2);
| ^^^^------------------------
@ -58,7 +58,7 @@ LL | let _ = opt.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:79:13
--> $DIR/unnecessary_lazy_eval.rs:91:13
|
LL | let _ = opt.ok_or_else(|| 2);
| ^^^^----------------
@ -66,7 +66,7 @@ LL | let _ = opt.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:80:13
--> $DIR/unnecessary_lazy_eval.rs:92:13
|
LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
| ^^^^^^^^^^^^^^^^^-------------------------------
@ -74,7 +74,7 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
| help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:81:13
--> $DIR/unnecessary_lazy_eval.rs:93:13
|
LL | let _ = cond.then(|| astronomers_pi);
| ^^^^^-----------------------
@ -82,7 +82,7 @@ LL | let _ = cond.then(|| astronomers_pi);
| help: use `then_some(..)` instead: `then_some(astronomers_pi)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:82:13
--> $DIR/unnecessary_lazy_eval.rs:94:13
|
LL | let _ = true.then(|| -> _ {});
| ^^^^^----------------
@ -90,7 +90,7 @@ LL | let _ = true.then(|| -> _ {});
| help: use `then_some(..)` instead: `then_some({})`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:83:13
--> $DIR/unnecessary_lazy_eval.rs:95:13
|
LL | let _ = true.then(|| {});
| ^^^^^-----------
@ -98,7 +98,7 @@ LL | let _ = true.then(|| {});
| help: use `then_some(..)` instead: `then_some({})`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:87:13
--> $DIR/unnecessary_lazy_eval.rs:99:13
|
LL | let _ = Some(1).unwrap_or_else(|| *r);
| ^^^^^^^^---------------------
@ -106,7 +106,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *r);
| help: use `unwrap_or(..)` instead: `unwrap_or(*r)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:89:13
--> $DIR/unnecessary_lazy_eval.rs:101:13
|
LL | let _ = Some(1).unwrap_or_else(|| *b);
| ^^^^^^^^---------------------
@ -114,7 +114,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *b);
| help: use `unwrap_or(..)` instead: `unwrap_or(*b)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:91:13
--> $DIR/unnecessary_lazy_eval.rs:103:13
|
LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r);
| ^^^^^^^^^^^^^^^^^---------------------
@ -122,7 +122,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r);
| help: use `unwrap_or(..)` instead: `unwrap_or(&r)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:92:13
--> $DIR/unnecessary_lazy_eval.rs:104:13
|
LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b);
| ^^^^^^^^^^^^^^^^^---------------------
@ -130,7 +130,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b);
| help: use `unwrap_or(..)` instead: `unwrap_or(&b)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:95:13
--> $DIR/unnecessary_lazy_eval.rs:107:13
|
LL | let _ = Some(10).unwrap_or_else(|| 2);
| ^^^^^^^^^--------------------
@ -138,7 +138,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:96:13
--> $DIR/unnecessary_lazy_eval.rs:108:13
|
LL | let _ = Some(10).and_then(|_| ext_opt);
| ^^^^^^^^^---------------------
@ -146,7 +146,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:97:28
--> $DIR/unnecessary_lazy_eval.rs:109:28
|
LL | let _: Option<usize> = None.or_else(|| ext_opt);
| ^^^^^-------------------
@ -154,7 +154,7 @@ LL | let _: Option<usize> = None.or_else(|| ext_opt);
| help: use `or(..)` instead: `or(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:98:13
--> $DIR/unnecessary_lazy_eval.rs:110:13
|
LL | let _ = None.get_or_insert_with(|| 2);
| ^^^^^------------------------
@ -162,7 +162,7 @@ LL | let _ = None.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:99:35
--> $DIR/unnecessary_lazy_eval.rs:111:35
|
LL | let _: Result<usize, usize> = None.ok_or_else(|| 2);
| ^^^^^----------------
@ -170,7 +170,7 @@ LL | let _: Result<usize, usize> = None.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:100:28
--> $DIR/unnecessary_lazy_eval.rs:112:28
|
LL | let _: Option<usize> = None.or_else(|| None);
| ^^^^^----------------
@ -178,7 +178,7 @@ LL | let _: Option<usize> = None.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:103:13
--> $DIR/unnecessary_lazy_eval.rs:115:13
|
LL | let _ = deep.0.unwrap_or_else(|| 2);
| ^^^^^^^--------------------
@ -186,7 +186,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:104:13
--> $DIR/unnecessary_lazy_eval.rs:116:13
|
LL | let _ = deep.0.and_then(|_| ext_opt);
| ^^^^^^^---------------------
@ -194,7 +194,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:105:13
--> $DIR/unnecessary_lazy_eval.rs:117:13
|
LL | let _ = deep.0.or_else(|| None);
| ^^^^^^^----------------
@ -202,7 +202,7 @@ LL | let _ = deep.0.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:106:13
--> $DIR/unnecessary_lazy_eval.rs:118:13
|
LL | let _ = deep.0.get_or_insert_with(|| 2);
| ^^^^^^^------------------------
@ -210,7 +210,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:107:13
--> $DIR/unnecessary_lazy_eval.rs:119:13
|
LL | let _ = deep.0.ok_or_else(|| 2);
| ^^^^^^^----------------
@ -218,7 +218,7 @@ LL | let _ = deep.0.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:137:28
--> $DIR/unnecessary_lazy_eval.rs:150:28
|
LL | let _: Option<usize> = None.or_else(|| Some(3));
| ^^^^^-------------------
@ -226,7 +226,7 @@ LL | let _: Option<usize> = None.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:138:13
--> $DIR/unnecessary_lazy_eval.rs:151:13
|
LL | let _ = deep.0.or_else(|| Some(3));
| ^^^^^^^-------------------
@ -234,7 +234,7 @@ LL | let _ = deep.0.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Option::None`
--> $DIR/unnecessary_lazy_eval.rs:139:13
--> $DIR/unnecessary_lazy_eval.rs:152:13
|
LL | let _ = opt.or_else(|| Some(3));
| ^^^^-------------------
@ -242,7 +242,7 @@ LL | let _ = opt.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:145:13
--> $DIR/unnecessary_lazy_eval.rs:158:13
|
LL | let _ = res2.unwrap_or_else(|_| 2);
| ^^^^^---------------------
@ -250,7 +250,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:146:13
--> $DIR/unnecessary_lazy_eval.rs:159:13
|
LL | let _ = res2.unwrap_or_else(|_| astronomers_pi);
| ^^^^^----------------------------------
@ -258,7 +258,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi);
| help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:147:13
--> $DIR/unnecessary_lazy_eval.rs:160:13
|
LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field);
| ^^^^^--------------------------------------
@ -266,7 +266,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field);
| help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:169:35
--> $DIR/unnecessary_lazy_eval.rs:182:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(2));
| ^^^^--------------------
@ -274,7 +274,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(2));
| help: use `and(..)` instead: `and(Err(2))`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:170:35
--> $DIR/unnecessary_lazy_eval.rs:183:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
| ^^^^---------------------------------
@ -282,7 +282,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
| help: use `and(..)` instead: `and(Err(astronomers_pi))`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:171:35
--> $DIR/unnecessary_lazy_eval.rs:184:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
| ^^^^-------------------------------------
@ -290,7 +290,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field))
| help: use `and(..)` instead: `and(Err(ext_str.some_field))`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:173:35
--> $DIR/unnecessary_lazy_eval.rs:186:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2));
| ^^^^------------------
@ -298,7 +298,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2));
| help: use `or(..)` instead: `or(Ok(2))`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:174:35
--> $DIR/unnecessary_lazy_eval.rs:187:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
| ^^^^-------------------------------
@ -306,7 +306,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
| help: use `or(..)` instead: `or(Ok(astronomers_pi))`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:175:35
--> $DIR/unnecessary_lazy_eval.rs:188:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
| ^^^^-----------------------------------
@ -314,7 +314,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
| help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
error: unnecessary closure used to substitute value for `Result::Err`
--> $DIR/unnecessary_lazy_eval.rs:176:35
--> $DIR/unnecessary_lazy_eval.rs:189:35
|
LL | let _: Result<usize, usize> = res.
| ___________________________________^
@ -329,7 +329,7 @@ LL | | or_else(|_| Ok(ext_str.some_field));
| help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:206:14
--> $DIR/unnecessary_lazy_eval.rs:219:14
|
LL | let _x = false.then(|| i32::MAX + 1);
| ^^^^^^---------------------
@ -337,7 +337,7 @@ LL | let _x = false.then(|| i32::MAX + 1);
| help: use `then_some(..)` instead: `then_some(i32::MAX + 1)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:208:14
--> $DIR/unnecessary_lazy_eval.rs:221:14
|
LL | let _x = false.then(|| i32::MAX * 2);
| ^^^^^^---------------------
@ -345,7 +345,7 @@ LL | let _x = false.then(|| i32::MAX * 2);
| help: use `then_some(..)` instead: `then_some(i32::MAX * 2)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:210:14
--> $DIR/unnecessary_lazy_eval.rs:223:14
|
LL | let _x = false.then(|| i32::MAX - 1);
| ^^^^^^---------------------
@ -353,7 +353,7 @@ LL | let _x = false.then(|| i32::MAX - 1);
| help: use `then_some(..)` instead: `then_some(i32::MAX - 1)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:212:14
--> $DIR/unnecessary_lazy_eval.rs:225:14
|
LL | let _x = false.then(|| i32::MIN - 1);
| ^^^^^^---------------------
@ -361,7 +361,7 @@ LL | let _x = false.then(|| i32::MIN - 1);
| help: use `then_some(..)` instead: `then_some(i32::MIN - 1)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:214:14
--> $DIR/unnecessary_lazy_eval.rs:227:14
|
LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2);
| ^^^^^^-------------------------------------
@ -369,7 +369,7 @@ LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2);
| help: use `then_some(..)` instead: `then_some((1 + 2 * 3 - 2 / 3 + 9) << 2)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:216:14
--> $DIR/unnecessary_lazy_eval.rs:229:14
|
LL | let _x = false.then(|| 255u8 << 7);
| ^^^^^^-------------------
@ -377,7 +377,7 @@ LL | let _x = false.then(|| 255u8 << 7);
| help: use `then_some(..)` instead: `then_some(255u8 << 7)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:218:14
--> $DIR/unnecessary_lazy_eval.rs:231:14
|
LL | let _x = false.then(|| 255u8 << 8);
| ^^^^^^-------------------
@ -385,7 +385,7 @@ LL | let _x = false.then(|| 255u8 << 8);
| help: use `then_some(..)` instead: `then_some(255u8 << 8)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:220:14
--> $DIR/unnecessary_lazy_eval.rs:233:14
|
LL | let _x = false.then(|| 255u8 >> 8);
| ^^^^^^-------------------
@ -393,7 +393,7 @@ LL | let _x = false.then(|| 255u8 >> 8);
| help: use `then_some(..)` instead: `then_some(255u8 >> 8)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:223:14
--> $DIR/unnecessary_lazy_eval.rs:236:14
|
LL | let _x = false.then(|| i32::MAX + -1);
| ^^^^^^----------------------
@ -401,7 +401,7 @@ LL | let _x = false.then(|| i32::MAX + -1);
| help: use `then_some(..)` instead: `then_some(i32::MAX + -1)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:225:14
--> $DIR/unnecessary_lazy_eval.rs:238:14
|
LL | let _x = false.then(|| -i32::MAX);
| ^^^^^^------------------
@ -409,7 +409,7 @@ LL | let _x = false.then(|| -i32::MAX);
| help: use `then_some(..)` instead: `then_some(-i32::MAX)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:227:14
--> $DIR/unnecessary_lazy_eval.rs:240:14
|
LL | let _x = false.then(|| -i32::MIN);
| ^^^^^^------------------
@ -417,7 +417,7 @@ LL | let _x = false.then(|| -i32::MIN);
| help: use `then_some(..)` instead: `then_some(-i32::MIN)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:230:14
--> $DIR/unnecessary_lazy_eval.rs:243:14
|
LL | let _x = false.then(|| 255 >> -7);
| ^^^^^^------------------
@ -425,7 +425,7 @@ LL | let _x = false.then(|| 255 >> -7);
| help: use `then_some(..)` instead: `then_some(255 >> -7)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:232:14
--> $DIR/unnecessary_lazy_eval.rs:245:14
|
LL | let _x = false.then(|| 255 << -1);
| ^^^^^^------------------
@ -433,7 +433,7 @@ LL | let _x = false.then(|| 255 << -1);
| help: use `then_some(..)` instead: `then_some(255 << -1)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:234:14
--> $DIR/unnecessary_lazy_eval.rs:247:14
|
LL | let _x = false.then(|| 1 / 0);
| ^^^^^^--------------
@ -441,7 +441,7 @@ LL | let _x = false.then(|| 1 / 0);
| help: use `then_some(..)` instead: `then_some(1 / 0)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:236:14
--> $DIR/unnecessary_lazy_eval.rs:249:14
|
LL | let _x = false.then(|| x << -1);
| ^^^^^^----------------
@ -449,7 +449,7 @@ LL | let _x = false.then(|| x << -1);
| help: use `then_some(..)` instead: `then_some(x << -1)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:238:14
--> $DIR/unnecessary_lazy_eval.rs:251:14
|
LL | let _x = false.then(|| x << 2);
| ^^^^^^---------------
@ -457,7 +457,7 @@ LL | let _x = false.then(|| x << 2);
| help: use `then_some(..)` instead: `then_some(x << 2)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:248:14
--> $DIR/unnecessary_lazy_eval.rs:261:14
|
LL | let _x = false.then(|| x / 0);
| ^^^^^^--------------
@ -465,7 +465,7 @@ LL | let _x = false.then(|| x / 0);
| help: use `then_some(..)` instead: `then_some(x / 0)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:250:14
--> $DIR/unnecessary_lazy_eval.rs:263:14
|
LL | let _x = false.then(|| x % 0);
| ^^^^^^--------------
@ -473,7 +473,7 @@ LL | let _x = false.then(|| x % 0);
| help: use `then_some(..)` instead: `then_some(x % 0)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:253:14
--> $DIR/unnecessary_lazy_eval.rs:266:14
|
LL | let _x = false.then(|| 1 / -1);
| ^^^^^^---------------
@ -481,7 +481,7 @@ LL | let _x = false.then(|| 1 / -1);
| help: use `then_some(..)` instead: `then_some(1 / -1)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:255:14
--> $DIR/unnecessary_lazy_eval.rs:268:14
|
LL | let _x = false.then(|| i32::MIN / -1);
| ^^^^^^----------------------
@ -489,7 +489,7 @@ LL | let _x = false.then(|| i32::MIN / -1);
| help: use `then_some(..)` instead: `then_some(i32::MIN / -1)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:258:14
--> $DIR/unnecessary_lazy_eval.rs:271:14
|
LL | let _x = false.then(|| i32::MIN / 0);
| ^^^^^^---------------------
@ -497,7 +497,7 @@ LL | let _x = false.then(|| i32::MIN / 0);
| help: use `then_some(..)` instead: `then_some(i32::MIN / 0)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:260:14
--> $DIR/unnecessary_lazy_eval.rs:273:14
|
LL | let _x = false.then(|| 4 / 2);
| ^^^^^^--------------
@ -505,7 +505,7 @@ LL | let _x = false.then(|| 4 / 2);
| help: use `then_some(..)` instead: `then_some(4 / 2)`
error: unnecessary closure used with `bool::then`
--> $DIR/unnecessary_lazy_eval.rs:268:14
--> $DIR/unnecessary_lazy_eval.rs:281:14
|
LL | let _x = false.then(|| f1 + f2);
| ^^^^^^----------------

View file

@ -73,4 +73,25 @@ mod issue_10084 {
}
}
mod issue_12048 {
pub const X: u8 = 0;
/// Returns a pointer to five.
///
/// # Examples
///
/// ```
/// use foo::point_to_five;
///
/// let five_pointer = point_to_five();
/// // Safety: this pointer always points to a valid five.
/// let five = unsafe { *five_pointer };
/// assert_eq!(five, 5);
/// ```
pub fn point_to_five() -> *const u8 {
static FIVE: u8 = 5;
&FIVE
}
}
fn main() {}

View file

@ -1,4 +1,18 @@
#[allow(clippy::single_char_pattern)]
#![allow(clippy::single_char_pattern)]
struct Issue12068;
impl AsRef<str> for Issue12068 {
fn as_ref(&self) -> &str {
""
}
}
impl ToString for Issue12068 {
fn to_string(&self) -> String {
String::new()
}
}
fn main() {
let _ = "a".split('a').next().unwrap();
@ -9,6 +23,8 @@ fn main() {
//~^ ERROR: unnecessary use of `to_owned`
let _ = "a".split("a").next().unwrap();
//~^ ERROR: unnecessary use of `to_owned`
let _ = Issue12068.as_ref().split('a').next().unwrap();
//~^ ERROR: unnecessary use of `to_string`
let _ = [1].split(|x| *x == 2).next().unwrap();
//~^ ERROR: unnecessary use of `to_vec`

View file

@ -1,4 +1,18 @@
#[allow(clippy::single_char_pattern)]
#![allow(clippy::single_char_pattern)]
struct Issue12068;
impl AsRef<str> for Issue12068 {
fn as_ref(&self) -> &str {
""
}
}
impl ToString for Issue12068 {
fn to_string(&self) -> String {
String::new()
}
}
fn main() {
let _ = "a".to_string().split('a').next().unwrap();
@ -9,6 +23,8 @@ fn main() {
//~^ ERROR: unnecessary use of `to_owned`
let _ = "a".to_owned().split("a").next().unwrap();
//~^ ERROR: unnecessary use of `to_owned`
let _ = Issue12068.to_string().split('a').next().unwrap();
//~^ ERROR: unnecessary use of `to_string`
let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
//~^ ERROR: unnecessary use of `to_vec`

View file

@ -1,5 +1,5 @@
error: unnecessary use of `to_string`
--> $DIR/unnecessary_to_owned_on_split.rs:4:13
--> $DIR/unnecessary_to_owned_on_split.rs:18:13
|
LL | let _ = "a".to_string().split('a').next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')`
@ -8,46 +8,52 @@ LL | let _ = "a".to_string().split('a').next().unwrap();
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]`
error: unnecessary use of `to_string`
--> $DIR/unnecessary_to_owned_on_split.rs:6:13
--> $DIR/unnecessary_to_owned_on_split.rs:20:13
|
LL | let _ = "a".to_string().split("a").next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")`
error: unnecessary use of `to_owned`
--> $DIR/unnecessary_to_owned_on_split.rs:8:13
--> $DIR/unnecessary_to_owned_on_split.rs:22:13
|
LL | let _ = "a".to_owned().split('a').next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')`
error: unnecessary use of `to_owned`
--> $DIR/unnecessary_to_owned_on_split.rs:10:13
--> $DIR/unnecessary_to_owned_on_split.rs:24:13
|
LL | let _ = "a".to_owned().split("a").next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")`
error: unnecessary use of `to_string`
--> $DIR/unnecessary_to_owned_on_split.rs:26:13
|
LL | let _ = Issue12068.to_string().split('a').next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Issue12068.as_ref().split('a')`
error: unnecessary use of `to_vec`
--> $DIR/unnecessary_to_owned_on_split.rs:13:13
--> $DIR/unnecessary_to_owned_on_split.rs:29:13
|
LL | let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
error: unnecessary use of `to_vec`
--> $DIR/unnecessary_to_owned_on_split.rs:15:13
--> $DIR/unnecessary_to_owned_on_split.rs:31:13
|
LL | let _ = [1].to_vec().split(|x| *x == 2).next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
error: unnecessary use of `to_owned`
--> $DIR/unnecessary_to_owned_on_split.rs:17:13
--> $DIR/unnecessary_to_owned_on_split.rs:33:13
|
LL | let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
error: unnecessary use of `to_owned`
--> $DIR/unnecessary_to_owned_on_split.rs:19:13
--> $DIR/unnecessary_to_owned_on_split.rs:35:13
|
LL | let _ = [1].to_owned().split(|x| *x == 2).next().unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)`
error: aborting due to 8 previous errors
error: aborting due to 9 previous errors

View file

@ -2,7 +2,9 @@
#![allow(
clippy::explicit_auto_deref,
clippy::uninlined_format_args,
clippy::needless_pass_by_ref_mut
clippy::map_clone,
clippy::needless_pass_by_ref_mut,
clippy::redundant_closure
)]
use std::fmt::Debug;
@ -132,6 +134,16 @@ fn generic_ok<U: AsMut<T> + AsRef<T> + ?Sized, T: Debug + ?Sized>(mru: &mut U) {
foo_rt(mru.as_ref());
}
fn foo() {
let x = Some(String::new());
let z = x.clone();
//~^ ERROR: this call to `as_ref.map(...)` does nothing
let z = x.clone();
//~^ ERROR: this call to `as_ref.map(...)` does nothing
let z = x.clone();
//~^ ERROR: this call to `as_ref.map(...)` does nothing
}
fn main() {
not_ok();
ok();

View file

@ -2,7 +2,9 @@
#![allow(
clippy::explicit_auto_deref,
clippy::uninlined_format_args,
clippy::needless_pass_by_ref_mut
clippy::map_clone,
clippy::needless_pass_by_ref_mut,
clippy::redundant_closure
)]
use std::fmt::Debug;
@ -132,6 +134,16 @@ fn generic_ok<U: AsMut<T> + AsRef<T> + ?Sized, T: Debug + ?Sized>(mru: &mut U) {
foo_rt(mru.as_ref());
}
fn foo() {
let x = Some(String::new());
let z = x.as_ref().map(String::clone);
//~^ ERROR: this call to `as_ref.map(...)` does nothing
let z = x.as_ref().map(|z| z.clone());
//~^ ERROR: this call to `as_ref.map(...)` does nothing
let z = x.as_ref().map(|z| String::clone(z));
//~^ ERROR: this call to `as_ref.map(...)` does nothing
}
fn main() {
not_ok();
ok();

View file

@ -1,5 +1,5 @@
error: this call to `as_ref` does nothing
--> $DIR/useless_asref.rs:46:18
--> $DIR/useless_asref.rs:48:18
|
LL | foo_rstr(rstr.as_ref());
| ^^^^^^^^^^^^^ help: try: `rstr`
@ -11,64 +11,82 @@ LL | #![deny(clippy::useless_asref)]
| ^^^^^^^^^^^^^^^^^^^^^
error: this call to `as_ref` does nothing
--> $DIR/useless_asref.rs:48:20
--> $DIR/useless_asref.rs:50:20
|
LL | foo_rslice(rslice.as_ref());
| ^^^^^^^^^^^^^^^ help: try: `rslice`
error: this call to `as_mut` does nothing
--> $DIR/useless_asref.rs:52:21
--> $DIR/useless_asref.rs:54:21
|
LL | foo_mrslice(mrslice.as_mut());
| ^^^^^^^^^^^^^^^^ help: try: `mrslice`
error: this call to `as_ref` does nothing
--> $DIR/useless_asref.rs:54:20
--> $DIR/useless_asref.rs:56:20
|
LL | foo_rslice(mrslice.as_ref());
| ^^^^^^^^^^^^^^^^ help: try: `mrslice`
error: this call to `as_ref` does nothing
--> $DIR/useless_asref.rs:61:20
--> $DIR/useless_asref.rs:63:20
|
LL | foo_rslice(rrrrrslice.as_ref());
| ^^^^^^^^^^^^^^^^^^^ help: try: `rrrrrslice`
error: this call to `as_ref` does nothing
--> $DIR/useless_asref.rs:63:18
--> $DIR/useless_asref.rs:65:18
|
LL | foo_rstr(rrrrrstr.as_ref());
| ^^^^^^^^^^^^^^^^^ help: try: `rrrrrstr`
error: this call to `as_mut` does nothing
--> $DIR/useless_asref.rs:68:21
--> $DIR/useless_asref.rs:70:21
|
LL | foo_mrslice(mrrrrrslice.as_mut());
| ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice`
error: this call to `as_ref` does nothing
--> $DIR/useless_asref.rs:70:20
--> $DIR/useless_asref.rs:72:20
|
LL | foo_rslice(mrrrrrslice.as_ref());
| ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice`
error: this call to `as_ref` does nothing
--> $DIR/useless_asref.rs:74:16
--> $DIR/useless_asref.rs:76:16
|
LL | foo_rrrrmr((&&&&MoreRef).as_ref());
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&&&&MoreRef)`
error: this call to `as_mut` does nothing
--> $DIR/useless_asref.rs:124:13
--> $DIR/useless_asref.rs:126:13
|
LL | foo_mrt(mrt.as_mut());
| ^^^^^^^^^^^^ help: try: `mrt`
error: this call to `as_ref` does nothing
--> $DIR/useless_asref.rs:126:12
--> $DIR/useless_asref.rs:128:12
|
LL | foo_rt(mrt.as_ref());
| ^^^^^^^^^^^^ help: try: `mrt`
error: aborting due to 11 previous errors
error: this call to `as_ref.map(...)` does nothing
--> $DIR/useless_asref.rs:139:13
|
LL | let z = x.as_ref().map(String::clone);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
error: this call to `as_ref.map(...)` does nothing
--> $DIR/useless_asref.rs:141:13
|
LL | let z = x.as_ref().map(|z| z.clone());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
error: this call to `as_ref.map(...)` does nothing
--> $DIR/useless_asref.rs:143:13
|
LL | let z = x.as_ref().map(|z| String::clone(z));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.clone()`
error: aborting due to 14 previous errors

View file

@ -241,7 +241,7 @@ mod issue11300 {
foo2::<(), _>([1, 2, 3].into_iter());
// This should lint. Removing the `.into_iter()` means that `I` gets substituted with `[i32; 3]`,
// and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unncessary.
// and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unnecessary.
foo3([1, 2, 3]);
}
@ -253,7 +253,7 @@ mod issue11300 {
S1.foo([1, 2]);
// ICE that occured in itertools
// ICE that occurred in itertools
trait Itertools {
fn interleave_shortest<J>(self, other: J)
where

View file

@ -241,7 +241,7 @@ mod issue11300 {
foo2::<(), _>([1, 2, 3].into_iter());
// This should lint. Removing the `.into_iter()` means that `I` gets substituted with `[i32; 3]`,
// and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unncessary.
// and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unnecessary.
foo3([1, 2, 3].into_iter());
}
@ -253,7 +253,7 @@ mod issue11300 {
S1.foo([1, 2].into_iter());
// ICE that occured in itertools
// ICE that occurred in itertools
trait Itertools {
fn interleave_shortest<J>(self, other: J)
where

View file

@ -210,3 +210,10 @@ fn issue11861() {
// should not lint
m!(vec![1]);
}
fn issue_11958() {
fn f(_s: &[String]) {}
// should not lint, `String` is not `Copy`
f(&vec!["test".to_owned(); 2]);
}

View file

@ -210,3 +210,10 @@ fn issue11861() {
// should not lint
m!(vec![1]);
}
fn issue_11958() {
fn f(_s: &[String]) {}
// should not lint, `String` is not `Copy`
f(&vec!["test".to_owned(); 2]);
}