From be8160878ab7a8e1367acecc173f92e6f509e033 Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 1 Oct 2020 10:34:53 +1300 Subject: [PATCH 001/118] split `interior_mutable_const` tests and clean it * remove a 'ERROR' comment from `borrow` `Vec` itself is `Freeze` as it holds the atomic in heap * remove `ONCE_INIT` from `declare` it seems like an artifact from previous spliting --- .../others.rs} | 33 +-- .../others.stderr} | 56 ++--- .../borrow_interior_mutable_const/traits.rs | 202 ++++++++++++++++++ .../traits.stderr | 123 +++++++++++ .../declare_interior_mutable_const/others.rs | 34 +++ .../others.stderr | 39 ++++ .../traits.rs} | 24 --- .../traits.stderr} | 63 ++---- 8 files changed, 430 insertions(+), 144 deletions(-) rename tests/ui/{borrow_interior_mutable_const.rs => borrow_interior_mutable_const/others.rs} (81%) rename tests/ui/{borrow_interior_mutable_const.stderr => borrow_interior_mutable_const/others.stderr} (68%) create mode 100644 tests/ui/borrow_interior_mutable_const/traits.rs create mode 100644 tests/ui/borrow_interior_mutable_const/traits.stderr create mode 100644 tests/ui/declare_interior_mutable_const/others.rs create mode 100644 tests/ui/declare_interior_mutable_const/others.stderr rename tests/ui/{declare_interior_mutable_const.rs => declare_interior_mutable_const/traits.rs} (84%) rename tests/ui/{declare_interior_mutable_const.stderr => declare_interior_mutable_const/traits.stderr} (56%) diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const/others.rs similarity index 81% rename from tests/ui/borrow_interior_mutable_const.rs rename to tests/ui/borrow_interior_mutable_const/others.rs index 9fcc9ece49bb7..ea25729d11d4d 100644 --- a/tests/ui/borrow_interior_mutable_const.rs +++ b/tests/ui/borrow_interior_mutable_const/others.rs @@ -19,33 +19,7 @@ const NO_ANN: &dyn Display = &70; static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); const ONCE_INIT: Once = Once::new(); -trait Trait { - type AssocType; - - const ATOMIC: AtomicUsize; - const INPUT: T; - const ASSOC: Self::AssocType; - - fn function() { - let _ = &Self::INPUT; - let _ = &Self::ASSOC; - } -} - -impl Trait for u64 { - type AssocType = AtomicUsize; - - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const INPUT: u32 = 10; - const ASSOC: Self::AssocType = AtomicUsize::new(11); - - fn function() { - let _ = &Self::INPUT; - let _ = &Self::ASSOC; //~ ERROR interior mutability - } -} - -// This is just a pointer that can be safely dereferended, +// This is just a pointer that can be safely dereferenced, // it's semantically the same as `&'static T`; // but it isn't allowed to make a static reference from an arbitrary integer value at the moment. // For more information, please see the issue #5918. @@ -100,7 +74,7 @@ fn main() { let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability - let _ = &*ATOMIC_TUPLE.1; //~ ERROR interior mutability + let _ = &*ATOMIC_TUPLE.1; let _ = &ATOMIC_TUPLE.2; let _ = (&&&&ATOMIC_TUPLE).0; let _ = (&&&&ATOMIC_TUPLE).2; @@ -124,9 +98,6 @@ fn main() { assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3); assert!(STATIC_TUPLE.1.is_empty()); - u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability - assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability - assert_eq!(NO_ANN.to_string(), "70"); // should never lint this. let _ = &CELL_REF.0; diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr similarity index 68% rename from tests/ui/borrow_interior_mutable_const.stderr rename to tests/ui/borrow_interior_mutable_const/others.stderr index ed726a6b46e64..9a908cf30e945 100644 --- a/tests/ui/borrow_interior_mutable_const.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,22 +1,14 @@ error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:44:18 - | -LL | let _ = &Self::ASSOC; //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:80:5 + --> $DIR/others.rs:54:5 | LL | ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^ | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:81:16 + --> $DIR/others.rs:55:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability | ^^^^^^ @@ -24,7 +16,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:84:22 + --> $DIR/others.rs:58:22 | LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -32,7 +24,7 @@ LL | let _once_ref = &ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:85:25 + --> $DIR/others.rs:59:25 | LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -40,7 +32,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:86:27 + --> $DIR/others.rs:60:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -48,7 +40,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:87:26 + --> $DIR/others.rs:61:26 | LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | ^^^^^^^^^ @@ -56,7 +48,7 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:98:14 + --> $DIR/others.rs:72:14 | LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -64,7 +56,7 @@ LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:99:14 + --> $DIR/others.rs:73:14 | LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -72,7 +64,7 @@ LL | let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:100:19 + --> $DIR/others.rs:74:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -80,7 +72,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:101:14 + --> $DIR/others.rs:75:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -88,7 +80,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:102:13 + --> $DIR/others.rs:76:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -96,7 +88,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:108:13 + --> $DIR/others.rs:82:13 | LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | ^^^^^^^^^^^^ @@ -104,7 +96,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:113:5 + --> $DIR/others.rs:87:5 | LL | CELL.set(2); //~ ERROR interior mutability | ^^^^ @@ -112,28 +104,12 @@ LL | CELL.set(2); //~ ERROR interior mutability = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:114:16 + --> $DIR/others.rs:88:16 | LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | ^^^^ | = help: assign this const to a local or static variable, and use the variable here -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:127:5 - | -LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: a `const` item with interior mutability should not be borrowed - --> $DIR/borrow_interior_mutable_const.rs:128:16 - | -LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability - | ^^^^^^^^^^^ - | - = help: assign this const to a local or static variable, and use the variable here - -error: aborting due to 17 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs new file mode 100644 index 0000000000000..06b5d62e8f9a8 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/traits.rs @@ -0,0 +1,202 @@ +#![warn(clippy::borrow_interior_mutable_const)] +#![allow(clippy::declare_interior_mutable_const)] + +// this file replicates its `declare` counterpart. Please see it for more discussions. + +use std::borrow::Cow; +use std::cell::Cell; +use std::sync::atomic::{AtomicUsize, Ordering}; + +trait ConcreteTypes { + const ATOMIC: AtomicUsize; + const STRING: String; + + fn function() { + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::STRING; + } +} + +impl ConcreteTypes for u64 { + const ATOMIC: AtomicUsize = AtomicUsize::new(9); + const STRING: String = String::new(); + + fn function() { + // Lint this again since implementers can choose not to borrow it. + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::STRING; + } +} + +// a helper trait used below +trait ConstDefault { + const DEFAULT: Self; +} + +trait GenericTypes { + const TO_REMAIN_GENERIC: T; + const TO_BE_CONCRETE: U; + + fn function() { + let _ = &Self::TO_REMAIN_GENERIC; + } +} + +impl GenericTypes for Vec { + const TO_REMAIN_GENERIC: T = T::DEFAULT; + const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); + + fn function() { + let _ = &Self::TO_REMAIN_GENERIC; + let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable + } +} + +// a helper type used below +pub struct Wrapper(T); + +trait AssocTypes { + type ToBeFrozen; + type ToBeUnfrozen; + type ToBeGenericParam; + + const TO_BE_FROZEN: Self::ToBeFrozen; + const TO_BE_UNFROZEN: Self::ToBeUnfrozen; + const WRAPPED_TO_BE_UNFROZEN: Wrapper; + const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; + + fn function() { + let _ = &Self::TO_BE_FROZEN; + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; + } +} + +impl AssocTypes for Vec { + type ToBeFrozen = u16; + type ToBeUnfrozen = AtomicUsize; + type ToBeGenericParam = T; + + const TO_BE_FROZEN: Self::ToBeFrozen = 12; + const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); + const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); + const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); + + fn function() { + let _ = &Self::TO_BE_FROZEN; + let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable + let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM; + } +} + +// a helper trait used below +trait AssocTypesHelper { + type NotToBeBounded; + type ToBeBounded; + + const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; +} + +trait AssocTypesFromGenericParam +where + T: AssocTypesHelper, +{ + const NOT_BOUNDED: T::NotToBeBounded; + const BOUNDED: T::ToBeBounded; + + fn function() { + let _ = &Self::NOT_BOUNDED; + let _ = &Self::BOUNDED; //~ ERROR interior mutable + } +} + +impl AssocTypesFromGenericParam for Vec +where + T: AssocTypesHelper, +{ + const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; + const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); + + fn function() { + let _ = &Self::NOT_BOUNDED; + let _ = &Self::BOUNDED; //~ ERROR interior mutable + } +} + +trait SelfType: Sized { + const SELF: Self; + const WRAPPED_SELF: Option; + + fn function() { + let _ = &Self::SELF; + let _ = &Self::WRAPPED_SELF; + } +} + +impl SelfType for u64 { + const SELF: Self = 16; + const WRAPPED_SELF: Option = Some(20); + + fn function() { + let _ = &Self::SELF; + let _ = &Self::WRAPPED_SELF; + } +} + +impl SelfType for AtomicUsize { + const SELF: Self = AtomicUsize::new(17); + const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); + + fn function() { + let _ = &Self::SELF; //~ ERROR interior mutable + let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable + } +} + +trait BothOfCellAndGeneric { + const DIRECT: Cell; + const INDIRECT: Cell<*const T>; + + fn function() { + let _ = &Self::DIRECT; + let _ = &Self::INDIRECT; //~ ERROR interior mutable + } +} + +impl BothOfCellAndGeneric for Vec { + const DIRECT: Cell = Cell::new(T::DEFAULT); + const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); + + fn function() { + let _ = &Self::DIRECT; + let _ = &Self::INDIRECT; //~ ERROR interior mutable + } +} + +struct Local(T); + +impl Local +where + T: ConstDefault + AssocTypesHelper, +{ + const ATOMIC: AtomicUsize = AtomicUsize::new(18); + const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); + + const GENERIC_TYPE: T = T::DEFAULT; + + const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; + const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); + + fn function() { + let _ = &Self::ATOMIC; //~ ERROR interior mutable + let _ = &Self::COW; + let _ = &Self::GENERIC_TYPE; + let _ = &Self::ASSOC_TYPE; + let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable + } +} + +fn main() { + u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability + assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability +} diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr new file mode 100644 index 0000000000000..8f26403abd3ee --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -0,0 +1,123 @@ +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:15:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:26:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:51:18 + | +LL | let _ = &Self::TO_BE_CONCRETE; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:86:18 + | +LL | let _ = &Self::TO_BE_UNFROZEN; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:87:18 + | +LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:109:18 + | +LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable + | ^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:122:18 + | +LL | let _ = &Self::BOUNDED; //~ ERROR interior mutable + | ^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:151:18 + | +LL | let _ = &Self::SELF; //~ ERROR interior mutable + | ^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:152:18 + | +LL | let _ = &Self::WRAPPED_SELF; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:162:18 + | +LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:172:18 + | +LL | let _ = &Self::INDIRECT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:191:18 + | +LL | let _ = &Self::ATOMIC; //~ ERROR interior mutable + | ^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:195:18 + | +LL | let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:200:5 + | +LL | u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR interior mutability + | ^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/traits.rs:201:16 + | +LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR interior mutability + | ^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 15 previous errors + diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs new file mode 100644 index 0000000000000..48c5e9537d6d0 --- /dev/null +++ b/tests/ui/declare_interior_mutable_const/others.rs @@ -0,0 +1,34 @@ +#![warn(clippy::declare_interior_mutable_const)] + +use std::borrow::Cow; +use std::cell::Cell; +use std::fmt::Display; +use std::sync::atomic::AtomicUsize; +use std::sync::Once; + +const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable +const CELL: Cell = Cell::new(6); //~ ERROR interior mutable +const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); +//~^ ERROR interior mutable + +macro_rules! declare_const { + ($name:ident: $ty:ty = $e:expr) => { + const $name: $ty = $e; + }; +} +declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable + +// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. + +const INTEGER: u8 = 8; +const STRING: String = String::new(); +const STR: &str = "012345"; +const COW: Cow = Cow::Borrowed("abcdef"); +//^ note: a const item of Cow is used in the `postgres` package. + +const NO_ANN: &dyn Display = &70; + +static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); +//^ there should be no lints on this line + +fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr new file mode 100644 index 0000000000000..6153c96edc4f4 --- /dev/null +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -0,0 +1,39 @@ +error: a `const` item should never be interior mutable + --> $DIR/others.rs:9:1 + | +LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:10:1 + | +LL | const CELL: Cell = Cell::new(6); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:11:1 + | +LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/others.rs:16:9 + | +LL | const $name: $ty = $e; + | ^^^^^^^^^^^^^^^^^^^^^^ +... +LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable + | ------------------------------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const/traits.rs similarity index 84% rename from tests/ui/declare_interior_mutable_const.rs rename to tests/ui/declare_interior_mutable_const/traits.rs index 3afcdca2f04dd..535147ccc6451 100644 --- a/tests/ui/declare_interior_mutable_const.rs +++ b/tests/ui/declare_interior_mutable_const/traits.rs @@ -2,37 +2,13 @@ use std::borrow::Cow; use std::cell::Cell; -use std::fmt::Display; use std::sync::atomic::AtomicUsize; -use std::sync::Once; - -const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable -const CELL: Cell = Cell::new(6); //~ ERROR interior mutable -const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); -//~^ ERROR interior mutable macro_rules! declare_const { ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; }; } -declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable - -// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. - -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -//^ note: a const item of Cow is used in the `postgres` package. - -const NO_ANN: &dyn Display = &70; - -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -//^ there should be no lints on this line - -#[allow(clippy::declare_interior_mutable_const)] -const ONCE_INIT: Once = Once::new(); // a constant whose type is a concrete type should be linted at the definition site. trait ConcreteTypes { diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr similarity index 56% rename from tests/ui/declare_interior_mutable_const.stderr rename to tests/ui/declare_interior_mutable_const/traits.stderr index 5cb10be88d89c..bb77f39b62c1f 100644 --- a/tests/ui/declare_interior_mutable_const.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,48 +1,13 @@ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:9:1 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR interior mutable - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - | - = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:10:1 - | -LL | const CELL: Cell = Cell::new(6); //~ ERROR interior mutable - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:11:1 - | -LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | make this a static item (maybe with lazy_static) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:16:9 - | -LL | const $name: $ty = $e; - | ^^^^^^^^^^^^^^^^^^^^^^ -... -LL | declare_const!(_ONCE: Once = Once::new()); //~ ERROR interior mutable - | ------------------------------------------ in this macro invocation - | - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - -error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:39:5 + --> $DIR/traits.rs:15:5 | LL | const ATOMIC: AtomicUsize; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:16:9 + --> $DIR/traits.rs:9:9 | LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -53,58 +18,58 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ ERROR i = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:67:5 + --> $DIR/traits.rs:43:5 | LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:92:5 + --> $DIR/traits.rs:68:5 | LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:93:5 + --> $DIR/traits.rs:69:5 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:112:5 + --> $DIR/traits.rs:88:5 | LL | const BOUNDED: T::ToBeBounded; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:140:5 + --> $DIR/traits.rs:116:5 | LL | const SELF: Self = AtomicUsize::new(17); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:141:5 + --> $DIR/traits.rs:117:5 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:149:5 + --> $DIR/traits.rs:125:5 | LL | const INDIRECT: Cell<*const T>; //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:165:5 + --> $DIR/traits.rs:141:5 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should never be interior mutable - --> $DIR/declare_interior_mutable_const.rs:171:5 + --> $DIR/traits.rs:147:5 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR interior mutable | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 15 previous errors +error: aborting due to 11 previous errors From f58a1695a67e2db741b7237992e696ff9a14d0ab Mon Sep 17 00:00:00 2001 From: rail <12975677+rail-rain@users.noreply.github.com> Date: Thu, 1 Oct 2020 10:51:49 +1300 Subject: [PATCH 002/118] fix a FP in `interior_mutable_const` fix a false positive in two `interior_mutable_const` lints where a constant with enums gets linted even if it uses a clearly unfrozen variant. Note that the code uses the MIR interpreter, which the author of #3962 thought unlikely to be a solution. This might be over-engineering; but, I think it's important to be able to work with the 'http' crate (#3825). --- clippy_lints/src/non_copy_const.rs | 170 ++++++++++++++---- .../auxiliary/helper.rs | 16 ++ .../ui/borrow_interior_mutable_const/enums.rs | 101 +++++++++++ .../enums.stderr | 75 ++++++++ .../declare_interior_mutable_const/enums.rs | 123 +++++++++++++ .../enums.stderr | 89 +++++++++ 6 files changed, 539 insertions(+), 35 deletions(-) create mode 100644 tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs create mode 100644 tests/ui/borrow_interior_mutable_const/enums.rs create mode 100644 tests/ui/borrow_interior_mutable_const/enums.stderr create mode 100644 tests/ui/declare_interior_mutable_const/enums.rs create mode 100644 tests/ui/declare_interior_mutable_const/enums.stderr diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 7b662eae7753e..6b0d198edcffa 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -5,11 +5,15 @@ use std::ptr; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp}; +use rustc_hir::def_id::DefId; +use rustc_hir::{ + BodyId, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, +}; use rustc_infer::traits::specialization_graph; use rustc_lint::{LateContext, LateLintPass, Lint}; +use rustc_middle::mir::interpret::{ConstValue, ErrorHandled}; use rustc_middle::ty::adjustment::Adjust; -use rustc_middle::ty::{AssocKind, Ty}; +use rustc_middle::ty::{self, AssocKind, Const, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{InnerSpan, Span, DUMMY_SP}; use rustc_typeck::hir_ty_to_ty; @@ -36,14 +40,17 @@ declare_clippy_lint! { /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, /// and this lint should be suppressed. /// - /// When an enum has variants with interior mutability, use of its non interior mutable - /// variants can generate false positives. See issue - /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) + /// Even though the lint avoids triggering on a constant whose type has enums that have variants + /// with interior mutability, and its value uses non interior mutable variants (see + /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and + /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples); + /// it complains about associated constants without default values only based on its types; + /// which might not be preferable. + /// There're other enums plus associated constants cases that the lint cannot handle. /// /// Types that have underlying or potential interior mutability trigger the lint whether /// the interior mutable field is used or not. See issues /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and - /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) /// /// **Example:** /// ```rust @@ -105,6 +112,79 @@ declare_clippy_lint! { "referencing `const` with interior mutability" } +fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, + // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is + // 'unfrozen'. However, this code causes a false negative in which + // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell`. + // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` + // since it works when a pointer indirection involves (`Cell<*const T>`). + // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; + // but I'm not sure whether it's a decent way, if possible. + cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) +} + +fn is_value_unfrozen_raw<'tcx>( + cx: &LateContext<'tcx>, + result: Result, ErrorHandled>, + ty: Ty<'tcx>, +) -> bool { + fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool { + match val.ty.kind() { + // the fact that we have to dig into every structs to search enums + // leads us to the point checking `UnsafeCell` directly is the only option. + ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true, + ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { + let val = cx.tcx.destructure_const(cx.param_env.and(val)); + val.fields.iter().any(|field| inner(cx, field)) + }, + _ => false, + } + } + + result.map_or_else( + |err| { + // Consider `TooGeneric` cases as being unfrozen. + // This causes a false positive where an assoc const whose type is unfrozen + // have a value that is a frozen variant with a generic param (an example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`). + // However, it prevents a number of false negatives that is, I think, important: + // 1. assoc consts in trait defs referring to consts of themselves + // (an example is `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`). + // 2. a path expr referring to assoc consts whose type is doesn't have + // any frozen variants in trait defs (i.e. without substitute for `Self`). + // (e.g. borrowing `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`) + // 3. similar to the false positive above; + // but the value is an unfrozen variant, or the type has no enums. (An example is + // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` + // and `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`). + // One might be able to prevent these FNs correctly, and replace this with `false`; + // e.g. implementing `has_frozen_variant` described above, and not running this function + // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd + // case (that actually removes another suboptimal behavior (I won't say 'false positive') where, + // similar to 2., but with the a frozen variant) (e.g. borrowing + // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). + // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). + err == ErrorHandled::TooGeneric + }, + |val| inner(cx, Const::from_value(cx.tcx, val, ty)), + ) +} + +fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { + let result = cx.tcx.const_eval_poly(body_id.hir_id.owner.to_def_id()); + is_value_unfrozen_raw(cx, result, ty) +} + +fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { + let substs = cx.typeck_results().node_substs(hir_id); + + let result = cx + .tcx + .const_eval_resolve(cx.param_env, ty::WithOptConstParam::unknown(def_id), substs, None, None); + is_value_unfrozen_raw(cx, result, ty) +} + #[derive(Copy, Clone)] enum Source { Item { item: Span }, @@ -130,19 +210,7 @@ impl Source { } } -fn verify_ty_bound<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, source: Source) { - // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`, - // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is - // 'unfrozen'. However, this code causes a false negative in which - // a type contains a layout-unknown type, but also a unsafe cell like `const CELL: Cell`. - // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)` - // since it works when a pointer indirection involves (`Cell<*const T>`). - // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option; - // but I'm not sure whether it's a decent way, if possible. - if cx.tcx.layout_of(cx.param_env.and(ty)).is_err() || ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env) { - return; - } - +fn lint(cx: &LateContext<'_>, source: Source) { let (lint, msg, span) = source.lint(); span_lint_and_then(cx, lint, span, msg, |diag| { if span.from_expansion() { @@ -165,24 +233,44 @@ declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTER impl<'tcx> LateLintPass<'tcx> for NonCopyConst { fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) { - if let ItemKind::Const(hir_ty, ..) = &it.kind { + if let ItemKind::Const(hir_ty, body_id) = it.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); - verify_ty_bound(cx, ty, Source::Item { item: it.span }); + + if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) { + lint(cx, Source::Item { item: it.span }); + } } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) { - if let TraitItemKind::Const(hir_ty, ..) = &trait_item.kind { + if let TraitItemKind::Const(hir_ty, body_id_opt) = &trait_item.kind { let ty = hir_ty_to_ty(cx.tcx, hir_ty); + // Normalize assoc types because ones originated from generic params // bounded other traits could have their bound. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound(cx, normalized, Source::Assoc { item: trait_item.span }); + if is_unfrozen(cx, normalized) + // When there's no default value, lint it only according to its type; + // in other words, lint consts whose value *could* be unfrozen, not definitely is. + // This feels inconsistent with how the lint treats generic types, + // which avoids linting types which potentially become unfrozen. + // One could check whether a unfrozen type have a *frozen variant* + // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`), + // and do the same as the case of generic types at impl items. + // Note that it isn't sufficient to check if it has an enum + // since all of that enum's variants can be unfrozen: + // i.e. having an enum doesn't necessary mean a type has a frozen variant. + // And, implementing it isn't a trivial task; it'll probably end up + // re-implementing the trait predicate evaluation specific to `Freeze`. + && body_id_opt.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized)) + { + lint(cx, Source::Assoc { item: trait_item.span }); + } } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { - if let ImplItemKind::Const(hir_ty, ..) = &impl_item.kind { + if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind { let item_hir_id = cx.tcx.hir().get_parent_node(impl_item.hir_id); let item = cx.tcx.hir().expect_item(item_hir_id); @@ -209,16 +297,23 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { ), )) .is_err(); + // If there were a function like `has_frozen_variant` described above, + // we should use here as a frozen variant is a potential to be frozen + // similar to unknown layouts. + // e.g. `layout_of(...).is_err() || has_frozen_variant(...);` then { let ty = hir_ty_to_ty(cx.tcx, hir_ty); let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound( - cx, - normalized, - Source::Assoc { - item: impl_item.span, - }, - ); + if is_unfrozen(cx, normalized) + && is_value_unfrozen_poly(cx, *body_id, normalized) + { + lint( + cx, + Source::Assoc { + item: impl_item.span, + }, + ); + } } } }, @@ -226,7 +321,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { let ty = hir_ty_to_ty(cx.tcx, hir_ty); // Normalize assoc types originated from generic params. let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - verify_ty_bound(cx, normalized, Source::Assoc { item: impl_item.span }); + + if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) { + lint(cx, Source::Assoc { item: impl_item.span }); + } }, _ => (), } @@ -241,8 +339,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { } // Make sure it is a const item. - match qpath_res(cx, qpath, expr.hir_id) { - Res::Def(DefKind::Const | DefKind::AssocConst, _) => {}, + let item_def_id = match qpath_res(cx, qpath, expr.hir_id) { + Res::Def(DefKind::Const | DefKind::AssocConst, did) => did, _ => return, }; @@ -319,7 +417,9 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst { cx.typeck_results().expr_ty(dereferenced_expr) }; - verify_ty_bound(cx, ty, Source::Expr { expr: expr.span }); + if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) { + lint(cx, Source::Expr { expr: expr.span }); + } } } } diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs new file mode 100644 index 0000000000000..2289f7875f04c --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs @@ -0,0 +1,16 @@ +// this file solely exists to test constants defined in foreign crates. +// As the most common case is the `http` crate, it replicates `http::HeadewrName`'s structure. + +#![allow(clippy::declare_interior_mutable_const)] + +use std::sync::atomic::AtomicUsize; + +enum Private { + ToBeUnfrozen(T), + Frozen(usize), +} + +pub struct Wrapper(Private); + +pub const WRAPPED_PRIVATE_UNFROZEN_VARIANT: Wrapper = Wrapper(Private::ToBeUnfrozen(AtomicUsize::new(6))); +pub const WRAPPED_PRIVATE_FROZEN_VARIANT: Wrapper = Wrapper(Private::Frozen(7)); diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs new file mode 100644 index 0000000000000..5027db4456179 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/enums.rs @@ -0,0 +1,101 @@ +// aux-build:helper.rs + +#![warn(clippy::borrow_interior_mutable_const)] +#![allow(clippy::declare_interior_mutable_const)] + +// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions. + +extern crate helper; + +use std::cell::Cell; +use std::sync::atomic::AtomicUsize; + +enum OptionalCell { + Unfrozen(Cell), + Frozen, +} + +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); +const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + +fn borrow_optional_cell() { + let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &FROZEN_VARIANT; +} + +trait AssocConsts { + const TO_BE_UNFROZEN_VARIANT: OptionalCell; + const TO_BE_FROZEN_VARIANT: OptionalCell; + + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + fn function() { + // This is the "suboptimal behavior" mentioned in `is_value_unfrozen` + // caused by a similar reason to unfrozen types without any default values + // get linted even if it has frozen variants'. + let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable + + // The lint ignores default values because an impl of this trait can set + // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`. + let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable + } +} + +impl AssocConsts for u64 { + const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + fn function() { + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &::TO_BE_FROZEN_VARIANT; + let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; + } +} + +trait AssocTypes { + type ToBeUnfrozen; + + const TO_BE_UNFROZEN_VARIANT: Option; + const TO_BE_FROZEN_VARIANT: Option; + + // there's no need to test here because it's the exactly same as `trait::AssocTypes` + fn function(); +} + +impl AssocTypes for u64 { + type ToBeUnfrozen = AtomicUsize; + + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: Option = None; + + fn function() { + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + let _ = &::TO_BE_FROZEN_VARIANT; + } +} + +enum BothOfCellAndGeneric { + Unfrozen(Cell<*const T>), + Generic(*const T), + Frozen(usize), +} + +impl BothOfCellAndGeneric { + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); + + fn function() { + let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability + let _ = &Self::FROZEN_VARIANT; + } +} + +fn main() { + // constants defined in foreign crates + let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability + let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT; +} diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr new file mode 100644 index 0000000000000..654a1ee7df659 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/enums.stderr @@ -0,0 +1,75 @@ +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:22:14 + | +LL | let _ = &UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::borrow-interior-mutable-const` implied by `-D warnings` + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:37:18 + | +LL | let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:41:18 + | +LL | let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:50:18 + | +LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:52:18 + | +LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:74:18 + | +LL | let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:91:18 + | +LL | let _ = &Self::UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:92:18 + | +LL | let _ = &Self::GENERIC_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: a `const` item with interior mutability should not be borrowed + --> $DIR/enums.rs:99:14 + | +LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 9 previous errors + diff --git a/tests/ui/declare_interior_mutable_const/enums.rs b/tests/ui/declare_interior_mutable_const/enums.rs new file mode 100644 index 0000000000000..f44518694b89c --- /dev/null +++ b/tests/ui/declare_interior_mutable_const/enums.rs @@ -0,0 +1,123 @@ +#![warn(clippy::declare_interior_mutable_const)] + +use std::cell::Cell; +use std::sync::atomic::AtomicUsize; + +enum OptionalCell { + Unfrozen(Cell), + Frozen, +} + +// a constant with enums should be linted only when the used variant is unfrozen (#3962). +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable +const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + +const fn unfrozen_variant() -> OptionalCell { + OptionalCell::Unfrozen(Cell::new(false)) +} + +const fn frozen_variant() -> OptionalCell { + OptionalCell::Frozen +} + +const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable +const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); + +enum NestedInnermost { + Unfrozen(AtomicUsize), + Frozen, +} + +struct NestedInner { + inner: NestedInnermost, +} + +enum NestedOuter { + NestedInner(NestedInner), + NotNested(usize), +} + +struct NestedOutermost { + outer: NestedOuter, +} + +// a constant with enums should be linted according to its value, no matter how structs involve. +const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { + outer: NestedOuter::NestedInner(NestedInner { + inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), + }), +}; //~ ERROR interior mutable +const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { + outer: NestedOuter::NestedInner(NestedInner { + inner: NestedInnermost::Frozen, + }), +}; + +trait AssocConsts { + // When there's no default value, lint it only according to its type. + // Further details are on the corresponding code (`NonCopyConst::check_trait_item`). + const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + + // Lint default values accordingly. + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; +} + +// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it +// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'. +impl AssocConsts for u64 { + const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; + + // even if this sets an unfrozen variant, the lint ignores it. + const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); +} + +// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters +// here are values; and I think substituted generics at definitions won't appear in MIR. +trait AssocTypes { + type ToBeUnfrozen; + + const TO_BE_UNFROZEN_VARIANT: Option; + const TO_BE_FROZEN_VARIANT: Option; +} + +impl AssocTypes for u64 { + type ToBeUnfrozen = AtomicUsize; + + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + const TO_BE_FROZEN_VARIANT: Option = None; +} + +// Use raw pointers since direct generics have a false negative at the type level. +enum BothOfCellAndGeneric { + Unfrozen(Cell<*const T>), + Generic(*const T), + Frozen(usize), +} + +impl BothOfCellAndGeneric { + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + + // This is a false positive. The argument about this is on `is_value_unfrozen_raw` + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); + + // This is what is likely to be a false negative when one tries to fix + // the `GENERIC_VARIANT` false positive. + const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable +} + +// associated types here is basically the same as the one above. +trait BothOfCellAndGenericWithAssocType { + type AssocType; + + const UNFROZEN_VARIANT: BothOfCellAndGeneric = + BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); +} + +fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr new file mode 100644 index 0000000000000..84198d5461578 --- /dev/null +++ b/tests/ui/declare_interior_mutable_const/enums.stderr @@ -0,0 +1,89 @@ +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:12:1 + | +LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + | + = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings` + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:23:1 + | +LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable + | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | make this a static item (maybe with lazy_static) + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:45:1 + | +LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { + | ^---- + | | + | _make this a static item (maybe with lazy_static) + | | +LL | | outer: NestedOuter::NestedInner(NestedInner { +LL | | inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), +LL | | }), +LL | | }; //~ ERROR interior mutable + | |__^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:59:5 + | +LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:60:5 + | +LL | const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:63:5 + | +LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:89:5 + | +LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:101:5 + | +LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mut... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:104:5 + | +LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:110:5 + | +LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:117:5 + | +LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = +LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable + | |____________________________________________________________________^ + +error: a `const` item should never be interior mutable + --> $DIR/enums.rs:119:5 + | +LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mu... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + From 7c74d870b5978fb100f8947850d0da3f38dd5c1c Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 30 Oct 2020 13:01:34 -0500 Subject: [PATCH 003/118] Fix vec_box scope error Fixes #6236 --- clippy_lints/src/types.rs | 2 +- tests/ui/vec_box_sized.fixed | 14 ++++++++++++++ tests/ui/vec_box_sized.rs | 14 ++++++++++++++ tests/ui/vec_box_sized.stderr | 8 +++++++- 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 45f3bc3ea858a..1bb81bbc9a32e 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -553,7 +553,7 @@ impl Types { hir_ty.span, "`Vec` is already on the heap, the boxing is unnecessary.", "try", - format!("Vec<{}>", ty_ty), + format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), Applicability::MachineApplicable, ); return; // don't recurse into the type diff --git a/tests/ui/vec_box_sized.fixed b/tests/ui/vec_box_sized.fixed index d0bee2460dd84..4fa28b525c3c2 100644 --- a/tests/ui/vec_box_sized.fixed +++ b/tests/ui/vec_box_sized.fixed @@ -35,4 +35,18 @@ mod should_not_trigger { } } +mod inner_mod { + mod inner { + pub struct S; + } + + mod inner2 { + use super::inner::S; + + pub fn f() -> Vec { + vec![] + } + } +} + fn main() {} diff --git a/tests/ui/vec_box_sized.rs b/tests/ui/vec_box_sized.rs index 500a0ae263ea5..7dc735cd90be7 100644 --- a/tests/ui/vec_box_sized.rs +++ b/tests/ui/vec_box_sized.rs @@ -35,4 +35,18 @@ mod should_not_trigger { } } +mod inner_mod { + mod inner { + pub struct S; + } + + mod inner2 { + use super::inner::S; + + pub fn f() -> Vec> { + vec![] + } + } +} + fn main() {} diff --git a/tests/ui/vec_box_sized.stderr b/tests/ui/vec_box_sized.stderr index 29bf7069e8adb..57e2f1fdf9a74 100644 --- a/tests/ui/vec_box_sized.stderr +++ b/tests/ui/vec_box_sized.stderr @@ -18,5 +18,11 @@ error: `Vec` is already on the heap, the boxing is unnecessary. LL | struct B(Vec>>); | ^^^^^^^^^^^^^^^ help: try: `Vec` -error: aborting due to 3 previous errors +error: `Vec` is already on the heap, the boxing is unnecessary. + --> $DIR/vec_box_sized.rs:46:23 + | +LL | pub fn f() -> Vec> { + | ^^^^^^^^^^^ help: try: `Vec` + +error: aborting due to 4 previous errors From c0d1002d9328104808253b5cb680d0cd0ab70c1a Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 30 Oct 2020 16:06:27 -0500 Subject: [PATCH 004/118] Fix unnecessary_lazy_eval suggestion applicability Fixes #6240 --- .../src/methods/unnecessary_lazy_eval.rs | 12 +++++++++- tests/ui/unnecessary_lazy_eval_unfixable.rs | 18 +++++++++++++++ .../ui/unnecessary_lazy_eval_unfixable.stderr | 22 +++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/ui/unnecessary_lazy_eval_unfixable.rs create mode 100644 tests/ui/unnecessary_lazy_eval_unfixable.stderr diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 08b3eab9b7cdf..aec1b7e2e46f9 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -32,6 +32,16 @@ pub(super) fn lint<'tcx>( } else { "unnecessary closure used to substitute value for `Result::Err`" }; + let applicability = if body + .params + .iter() + .all(|param| matches!(param.pat.kind, hir::PatKind::Wild)) + { + Applicability::MachineApplicable + } else { + // replacing the lambda may break type inference + Applicability::MaybeIncorrect + }; span_lint_and_sugg( cx, @@ -45,7 +55,7 @@ pub(super) fn lint<'tcx>( simplify_using, snippet(cx, body_expr.span, ".."), ), - Applicability::MachineApplicable, + applicability, ); } } diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.rs b/tests/ui/unnecessary_lazy_eval_unfixable.rs new file mode 100644 index 0000000000000..2e923bc97a2ef --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -0,0 +1,18 @@ +#![warn(clippy::unnecessary_lazy_evaluations)] + +struct Deep(Option); + +#[derive(Copy, Clone)] +struct SomeStruct { + some_field: usize, +} + +fn main() { + // fix will break type inference + let _ = Ok(1).unwrap_or_else(|()| 2); + mod e { + pub struct E; + } + let _ = Ok(1).unwrap_or_else(|e::E| 2); + let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); +} diff --git a/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/tests/ui/unnecessary_lazy_eval_unfixable.stderr new file mode 100644 index 0000000000000..581d641cbf54b --- /dev/null +++ b/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -0,0 +1,22 @@ +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:12:13 + | +LL | let _ = Ok(1).unwrap_or_else(|()| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + | + = note: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:16:13 + | +LL | let _ = Ok(1).unwrap_or_else(|e::E| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + +error: unnecessary closure used to substitute value for `Result::Err` + --> $DIR/unnecessary_lazy_eval_unfixable.rs:17:13 + | +LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: Use `unwrap_or` instead: `Ok(1).unwrap_or(2)` + +error: aborting due to 3 previous errors + From 158bf9aa443c5ea93ff4b3def8c7220632e45442 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sat, 31 Oct 2020 19:56:51 +0100 Subject: [PATCH 005/118] Fix incorrect suggestion for macro expansion in `deref_addrof` lint --- clippy_lints/src/reference.rs | 8 +++++++- tests/ui/deref_addrof.fixed | 15 ++++++++++++++- tests/ui/deref_addrof.rs | 15 ++++++++++++++- tests/ui/deref_addrof.stderr | 13 ++++++++++++- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 3fda00403c611..f1555ab3ec187 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -46,13 +46,19 @@ impl EarlyLintPass for DerefAddrOf { if !in_macro(addrof_target.span); then { let mut applicability = Applicability::MachineApplicable; + let sugg = if e.span.from_expansion() { + let snip = snippet_with_applicability(cx, e.span, "_", &mut applicability); + snip.trim_start_matches(|c| c == '&' || c == '*').to_string() + } else { + snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability).to_string() + }; span_lint_and_sugg( cx, DEREF_ADDROF, e.span, "immediately dereferencing a reference", "try this", - format!("{}", snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)), + sugg, applicability, ); } diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 9e5b51d6d5e6d..8cdec4201fefc 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -1,4 +1,5 @@ // run-rustfix +#![warn(clippy::deref_addrof)] fn get_number() -> usize { 10 @@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize { #[allow(clippy::many_single_char_names, clippy::double_parens)] #[allow(unused_variables, unused_parens)] -#[warn(clippy::deref_addrof)] fn main() { let a = 10; let aref = &a; @@ -37,3 +37,16 @@ fn main() { let b = *aref; } + +macro_rules! m { + ($visitor: expr) => { + $visitor + }; +} + +pub struct S; +impl S { + pub fn f(&self) -> &Self { + m!(self) + } +} diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 5641a73cbc1cb..6433e63ca5901 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -1,4 +1,5 @@ // run-rustfix +#![warn(clippy::deref_addrof)] fn get_number() -> usize { 10 @@ -10,7 +11,6 @@ fn get_reference(n: &usize) -> &usize { #[allow(clippy::many_single_char_names, clippy::double_parens)] #[allow(unused_variables, unused_parens)] -#[warn(clippy::deref_addrof)] fn main() { let a = 10; let aref = &a; @@ -37,3 +37,16 @@ fn main() { let b = **&aref; } + +macro_rules! m { + ($visitor: expr) => { + *&$visitor + }; +} + +pub struct S; +impl S { + pub fn f(&self) -> &Self { + m!(self) + } +} diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index bc51719e8a7a0..1fe49ad49cd6b 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -48,5 +48,16 @@ error: immediately dereferencing a reference LL | let b = **&aref; | ^^^^^^ help: try this: `aref` -error: aborting due to 8 previous errors +error: immediately dereferencing a reference + --> $DIR/deref_addrof.rs:43:9 + | +LL | *&$visitor + | ^^^^^^^^^^ help: try this: `$visitor` +... +LL | m!(self) + | -------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 9 previous errors From 343bdb33647627a6a001be039a107e7ef3362707 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 2 Nov 2020 17:56:54 +0100 Subject: [PATCH 006/118] Give better suggestion by working on span on `deref_addrof` lint --- clippy_lints/src/reference.rs | 36 ++++++++++++++++++++++++++++++----- tests/ui/deref_addrof.fixed | 10 ++++++++++ tests/ui/deref_addrof.rs | 12 +++++++++++- tests/ui/deref_addrof.stderr | 17 ++++++++++++++--- 4 files changed, 66 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index f1555ab3ec187..8646d61673516 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,9 +1,11 @@ -use crate::utils::{in_macro, snippet_with_applicability, span_lint_and_sugg}; +use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use rustc_ast::ast::{Expr, ExprKind, UnOp}; +use rustc_ast::ast::{Expr, ExprKind, UnOp, Mutability}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::BytePos; +// use rustc_span::source_map::{BytePos, Span}; declare_clippy_lint! { /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. @@ -42,13 +44,37 @@ impl EarlyLintPass for DerefAddrOf { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { if_chain! { if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind; - if let ExprKind::AddrOf(_, _, ref addrof_target) = without_parens(deref_target).kind; + if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind; if !in_macro(addrof_target.span); then { let mut applicability = Applicability::MachineApplicable; let sugg = if e.span.from_expansion() { - let snip = snippet_with_applicability(cx, e.span, "_", &mut applicability); - snip.trim_start_matches(|c| c == '&' || c == '*').to_string() + if let Ok(macro_source) = cx.sess.source_map().span_to_snippet(e.span) { + // Remove leading whitespace from the given span + // e.g: ` $visitor` turns into `$visitor` + let trim_leading_whitespaces = |span| { + if let Some(start_no_whitespace) = snippet_opt(cx, span).and_then(|snip| { + snip.find(|c: char| !c.is_whitespace()).map(|pos| { + span.lo() + BytePos(pos as u32) + }) + }) { + e.span.with_lo(start_no_whitespace) + } else { + span + } + }; + + let rpos = if *mutability == Mutability::Mut { + macro_source.rfind("mut").expect("already checked this is a mutable reference") + "mut".len() + } else { + macro_source.rfind("&").expect("already checked this is a reference") + "&".len() + }; + let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); + let span = trim_leading_whitespaces(span_after_ref); + snippet_with_applicability(cx, span, "_", &mut applicability).to_string() + } else { + snippet_with_applicability(cx, e.span, "_", &mut applicability).to_string() + } } else { snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability).to_string() }; diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 8cdec4201fefc..689e9d552234e 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -44,9 +44,19 @@ macro_rules! m { }; } +#[rustfmt::skip] +macro_rules! m_mut { + ($visitor: expr) => { + $visitor + }; +} + pub struct S; impl S { pub fn f(&self) -> &Self { m!(self) } + pub fn f_mut(&self) -> &Self { + m_mut!(self) + } } diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 6433e63ca5901..57effce5d129d 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -40,7 +40,14 @@ fn main() { macro_rules! m { ($visitor: expr) => { - *&$visitor + *& $visitor + }; +} + +#[rustfmt::skip] +macro_rules! m_mut { + ($visitor: expr) => { + *& mut $visitor }; } @@ -49,4 +56,7 @@ impl S { pub fn f(&self) -> &Self { m!(self) } + pub fn f_mut(&self) -> &Self { + m_mut!(self) + } } diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index 1fe49ad49cd6b..52c1f7d1da8fe 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -51,13 +51,24 @@ LL | let b = **&aref; error: immediately dereferencing a reference --> $DIR/deref_addrof.rs:43:9 | -LL | *&$visitor - | ^^^^^^^^^^ help: try this: `$visitor` +LL | *& $visitor + | ^^^^^^^^^^^ help: try this: `$visitor` ... LL | m!(self) | -------- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 9 previous errors +error: immediately dereferencing a reference + --> $DIR/deref_addrof.rs:50:9 + | +LL | *& mut $visitor + | ^^^^^^^^^^^^^^^ help: try this: `$visitor` +... +LL | m_mut!(self) + | ------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors From ce98468158318a47f6bab3707d348e116451ad39 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 2 Nov 2020 17:59:47 +0100 Subject: [PATCH 007/118] Fix incorrect suggestion when from expansion in `try_err` lint --- clippy_lints/src/try_err.rs | 10 ++++++++-- tests/ui/try_err.fixed | 16 ++++++++++++++++ tests/ui/try_err.rs | 16 ++++++++++++++++ tests/ui/try_err.stderr | 21 ++++++++++++++++----- 4 files changed, 56 insertions(+), 7 deletions(-) diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 3e747ec4ad9e2..e6d8e7521a8c4 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,5 +1,5 @@ use crate::utils::{ - is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, + in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, span_lint_and_sugg, }; use if_chain::if_chain; @@ -92,9 +92,13 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { let expr_err_ty = cx.typeck_results().expr_ty(err_arg); - let origin_snippet = if err_arg.span.from_expansion() { + // println!("\n\n{:?}", in_macro(expr.span)); + // println!("{:#?}", snippet(cx, err_arg.span, "_")); + let origin_snippet = if err_arg.span.from_expansion() && !in_macro(expr.span) { + // println!("from expansion"); snippet_with_macro_callsite(cx, err_arg.span, "_") } else { + // println!("just a snippet"); snippet(cx, err_arg.span, "_") }; let suggestion = if err_ty == expr_err_ty { @@ -102,6 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { } else { format!("return {}{}.into(){}", prefix, origin_snippet, suffix) }; + // println!("origin_snippet: {:#?}", origin_snippet); + // println!("suggestion: {:#?}", suggestion); span_lint_and_sugg( cx, diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index 9e77dcd873164..053dd45f23e1a 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -78,12 +78,28 @@ fn nested_error() -> Result { Ok(1) } +// Bad suggestion when in macro (see #6242) +macro_rules! try_validation { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => return Err(1), + } + }}; +} + +fn calling_macro() -> Result { + try_validation!(Ok::<_, i32>(5)); + Ok(5) +} + fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); + calling_macro().unwrap(); // We don't want to lint in external macros try_err!(); diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 41bcb0a189e76..215ca6a07e62d 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -78,12 +78,28 @@ fn nested_error() -> Result { Ok(1) } +// Bad suggestion when in macro (see #6242) +macro_rules! try_validation { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => Err(1)?, + } + }}; +} + +fn calling_macro() -> Result { + try_validation!(Ok::<_, i32>(5)); + Ok(5) +} + fn main() { basic_test().unwrap(); into_test().unwrap(); negative_test().unwrap(); closure_matches_test().unwrap(); closure_into_test().unwrap(); + calling_macro().unwrap(); // We don't want to lint in external macros try_err!(); diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 3f1cbc17e72d0..443c8d0847218 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -29,28 +29,39 @@ LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:106:9 + --> $DIR/try_err.rs:86:23 + | +LL | Err(_) => Err(1)?, + | ^^^^^^^ help: try this: `return Err(1)` +... +LL | try_validation!(Ok::<_, i32>(5)); + | --------------------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: returning an `Err(_)` with the `?` operator + --> $DIR/try_err.rs:122:9 | LL | Err(foo!())?; | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:113:9 + --> $DIR/try_err.rs:129:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:115:9 + --> $DIR/try_err.rs:131:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:123:9 + --> $DIR/try_err.rs:139:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors From a6611de75a9c6cf8b0ccfa371491a646a743667f Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Mon, 2 Nov 2020 12:55:05 -0600 Subject: [PATCH 008/118] Include bindings as machine applicable --- clippy_lints/src/methods/unnecessary_lazy_eval.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index aec1b7e2e46f9..fe54a238aa449 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -35,7 +35,8 @@ pub(super) fn lint<'tcx>( let applicability = if body .params .iter() - .all(|param| matches!(param.pat.kind, hir::PatKind::Wild)) + // bindings are checked to be unused above + .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild)) { Applicability::MachineApplicable } else { From 89fa373059984c6ba0bf157d949d03cee103333d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 3 Nov 2020 20:26:17 +0300 Subject: [PATCH 009/118] rustc_ast: Do not panic by default when visiting macro calls --- clippy_lints/src/non_expressive_names.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 603440c0f8376..6b56380edf8c0 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -149,9 +149,6 @@ impl<'a, 'tcx, 'b> Visitor<'tcx> for SimilarNamesNameVisitor<'a, 'tcx, 'b> { _ => walk_pat(self, pat), } } - fn visit_mac(&mut self, _mac: &MacCall) { - // do not check macs - } } #[must_use] @@ -356,9 +353,6 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> { fn visit_item(&mut self, _: &Item) { // do not recurse into inner items } - fn visit_mac(&mut self, _mac: &MacCall) { - // do not check macs - } } impl EarlyLintPass for NonExpressiveNames { From c2a769f84c8b1347a93a23cb9a6704cdd1a4a77d Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 3 Nov 2020 20:34:57 +0300 Subject: [PATCH 010/118] rustc_ast: `visit_mac` -> `visit_mac_call` --- clippy_lints/src/non_expressive_names.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 6b56380edf8c0..c5f38c1f08025 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -1,6 +1,6 @@ use crate::utils::{span_lint, span_lint_and_then}; use rustc_ast::ast::{ - Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, MacCall, Pat, PatKind, + Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, }; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass}; From a4acb3164ad93d8fe444783ad588a8b5d71dacd9 Mon Sep 17 00:00:00 2001 From: Urcra Date: Wed, 4 Nov 2020 23:39:52 +0100 Subject: [PATCH 011/118] Fix example for cargo common data --- clippy_lints/src/cargo_common_metadata.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/clippy_lints/src/cargo_common_metadata.rs b/clippy_lints/src/cargo_common_metadata.rs index 76a000157df03..0d294761af5ab 100644 --- a/clippy_lints/src/cargo_common_metadata.rs +++ b/clippy_lints/src/cargo_common_metadata.rs @@ -23,6 +23,21 @@ declare_clippy_lint! { /// [package] /// name = "clippy" /// version = "0.0.212" + /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" + /// repository = "https://github.com/rust-lang/rust-clippy" + /// readme = "README.md" + /// license = "MIT OR Apache-2.0" + /// keywords = ["clippy", "lint", "plugin"] + /// categories = ["development-tools", "development-tools::cargo-plugins"] + /// ``` + /// + /// Should include an authors field like: + /// + /// ```toml + /// # This `Cargo.toml` includes all common metadata + /// [package] + /// name = "clippy" + /// version = "0.0.212" /// authors = ["Someone "] /// description = "A bunch of helpful lints to avoid common pitfalls in Rust" /// repository = "https://github.com/rust-lang/rust-clippy" From fd8decee6ac64caf05e35974e652a625d6105eed Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Tue, 3 Nov 2020 11:44:26 -0600 Subject: [PATCH 012/118] Readme improvements Format lint categories as a table with the default lint level. --- README.md | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8a5975e1f9711..1da626b505dfb 100644 --- a/README.md +++ b/README.md @@ -7,28 +7,22 @@ A collection of lints to catch common mistakes and improve your [Rust](https://g [There are over 400 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html) -We have a bunch of lint categories to allow you to choose how much Clippy is supposed to ~~annoy~~ help you: - -* `clippy::all` (everything that is on by default: all the categories below except for `nursery`, `pedantic`, and `cargo`) -* `clippy::correctness` (code that is just **outright wrong** or **very very useless**, causes hard errors by default) -* `clippy::style` (code that should be written in a more idiomatic way) -* `clippy::complexity` (code that does something simple but in a complex way) -* `clippy::perf` (code that can be written in a faster way) -* `clippy::pedantic` (lints which are rather strict, off by default) -* `clippy::nursery` (new lints that aren't quite ready yet, off by default) -* `clippy::cargo` (checks against the cargo manifest, off by default) +Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html). +You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category. + +Category | Description | Default level +-- | -- | -- +`clippy::all` | all lints that are on by default (correctness, style, complexity, perf) | **warn/deny** +`clippy::correctness` | code that is outright wrong or very useless | **deny** +`clippy::style` | code that should be written in a more idiomatic way | **warn** +`clippy::complexity` | code that does something simple but in a complex way | **warn** +`clippy::perf` | code that can be written to run faster | **warn** +`clippy::pedantic` | lints which are rather strict or might have false positives | allow +`clippy::nursery` | new lints that are still under development | allow +`clippy::cargo` | lints for the cargo manifest | allow More to come, please [file an issue](https://github.com/rust-lang/rust-clippy/issues) if you have ideas! -Only the following of those categories are enabled by default: - -* `clippy::style` -* `clippy::correctness` -* `clippy::complexity` -* `clippy::perf` - -Other categories need to be enabled in order for their lints to be executed. - The [lint list](https://rust-lang.github.io/rust-clippy/master/index.html) also contains "restriction lints", which are for things which are usually not considered "bad", but may be useful to turn on in specific cases. These should be used very selectively, if at all. From bc27d1492d60ecfb0673629e28bc4bbe0b7fd886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Jos=C3=A9=20Pereira?= Date: Thu, 8 Oct 2020 00:19:56 -0300 Subject: [PATCH 013/118] Add string_from_utf8_as_bytes linter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Patrick José Pereira --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 3 + clippy_lints/src/strings.rs | 68 ++++++++++++++++++++++- clippy_lints/src/utils/paths.rs | 1 + src/lintlist/mod.rs | 7 +++ tests/ui/string_from_utf8_as_bytes.fixed | 6 ++ tests/ui/string_from_utf8_as_bytes.rs | 6 ++ tests/ui/string_from_utf8_as_bytes.stderr | 10 ++++ 8 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 tests/ui/string_from_utf8_as_bytes.fixed create mode 100644 tests/ui/string_from_utf8_as_bytes.rs create mode 100644 tests/ui/string_from_utf8_as_bytes.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b63dbb7eff54..aeccf6cf83b67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1952,6 +1952,7 @@ Released 2018-09-13 [`string_add`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add [`string_add_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_add_assign [`string_extend_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_extend_chars +[`string_from_utf8_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_from_utf8_as_bytes [`string_lit_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_lit_as_bytes [`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string [`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 5c3af014ee128..d29ba33064c6d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -826,6 +826,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &stable_sort_primitive::STABLE_SORT_PRIMITIVE, &strings::STRING_ADD, &strings::STRING_ADD_ASSIGN, + &strings::STRING_FROM_UTF8_AS_BYTES, &strings::STRING_LIT_AS_BYTES, &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL, &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL, @@ -1515,6 +1516,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), LintId::of(&slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(&stable_sort_primitive::STABLE_SORT_PRIMITIVE), + LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(&suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(&swap::ALMOST_SWAPPED), @@ -1738,6 +1740,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&reference::DEREF_ADDROF), LintId::of(&reference::REF_IN_DEREF), LintId::of(&repeat_once::REPEAT_ONCE), + LintId::of(&strings::STRING_FROM_UTF8_AS_BYTES), LintId::of(&swap::MANUAL_SWAP), LintId::of(&temporary_assignment::TEMPORARY_ASSIGNMENT), LintId::of(&transmute::CROSSPOINTER_TRANSMUTE), diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 3783bd78de25e..a55df1e55028d 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -1,5 +1,5 @@ use rustc_errors::Applicability; -use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -8,7 +8,10 @@ use rustc_span::source_map::Spanned; use if_chain::if_chain; use crate::utils::SpanlessEq; -use crate::utils::{get_parent_expr, is_allowed, is_type_diagnostic_item, span_lint, span_lint_and_sugg}; +use crate::utils::{ + get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint, + span_lint_and_sugg, +}; declare_clippy_lint! { /// **What it does:** Checks for string appends of the form `x = x + y` (without @@ -173,16 +176,75 @@ fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { } } +declare_clippy_lint! { + /// **What it does:** Check if the string is transformed to byte array and casted back to string. + /// + /// **Why is this bad?** It's unnecessary, the string can be used directly. + /// + /// **Known problems:** None + /// + /// **Example:** + /// ```rust + /// let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap(); + /// ``` + /// could be written as + /// ```rust + /// let _ = &"Hello World!"[6..11]; + /// ``` + pub STRING_FROM_UTF8_AS_BYTES, + complexity, + "casting string slices to byte slices and back" +} + // Max length a b"foo" string can take const MAX_LENGTH_BYTE_STRING_LIT: usize = 32; -declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES]); +declare_lint_pass!(StringLitAsBytes => [STRING_LIT_AS_BYTES, STRING_FROM_UTF8_AS_BYTES]); impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use crate::utils::{snippet, snippet_with_applicability}; use rustc_ast::LitKind; + if_chain! { + // Find std::str::converts::from_utf8 + if let Some(args) = match_function_call(cx, e, &paths::STR_FROM_UTF8); + + // Find string::as_bytes + if let ExprKind::AddrOf(BorrowKind::Ref, _, ref args) = args[0].kind; + if let ExprKind::Index(ref left, ref right) = args.kind; + let (method_names, expressions, _) = method_calls(left, 1); + if method_names.len() == 1; + if expressions.len() == 1; + if expressions[0].len() == 1; + if method_names[0] == sym!(as_bytes); + + // Check for slicer + if let ExprKind::Struct(ref path, _, _) = right.kind; + if let QPath::LangItem(LangItem::Range, _) = path; + + then { + let mut applicability = Applicability::MachineApplicable; + let string_expression = &expressions[0][0]; + + let snippet_app = snippet_with_applicability( + cx, + string_expression.span, "..", + &mut applicability, + ); + + span_lint_and_sugg( + cx, + STRING_FROM_UTF8_AS_BYTES, + e.span, + "calling a slice of `as_bytes()` with `from_utf8` should be not necessary", + "try", + format!("Some(&{}[{}])", snippet_app, snippet(cx, right.span, "..")), + applicability + ) + } + } + if_chain! { if let ExprKind::MethodCall(path, _, args, _) = &e.kind; if path.ident.name == sym!(as_bytes); diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index cd72fdd61fd3a..0d0ecf9ae9f69 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -120,6 +120,7 @@ pub const STRING: [&str; 3] = ["alloc", "string", "String"]; pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"]; pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"]; pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "", "ends_with"]; +pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"]; pub const STR_LEN: [&str; 4] = ["core", "str", "", "len"]; pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "", "starts_with"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 016bda77ef5e2..4d824cf94be28 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2230,6 +2230,13 @@ vec![ deprecation: None, module: "methods", }, + Lint { + name: "string_from_utf8_as_bytes", + group: "complexity", + desc: "casting string slices to byte slices and back", + deprecation: None, + module: "strings", + }, Lint { name: "string_lit_as_bytes", group: "nursery", diff --git a/tests/ui/string_from_utf8_as_bytes.fixed b/tests/ui/string_from_utf8_as_bytes.fixed new file mode 100644 index 0000000000000..6e665cdd56302 --- /dev/null +++ b/tests/ui/string_from_utf8_as_bytes.fixed @@ -0,0 +1,6 @@ +// run-rustfix +#![warn(clippy::string_from_utf8_as_bytes)] + +fn main() { + let _ = Some(&"Hello World!"[6..11]); +} diff --git a/tests/ui/string_from_utf8_as_bytes.rs b/tests/ui/string_from_utf8_as_bytes.rs new file mode 100644 index 0000000000000..670d206d3679c --- /dev/null +++ b/tests/ui/string_from_utf8_as_bytes.rs @@ -0,0 +1,6 @@ +// run-rustfix +#![warn(clippy::string_from_utf8_as_bytes)] + +fn main() { + let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); +} diff --git a/tests/ui/string_from_utf8_as_bytes.stderr b/tests/ui/string_from_utf8_as_bytes.stderr new file mode 100644 index 0000000000000..bf5e5d33e8f9a --- /dev/null +++ b/tests/ui/string_from_utf8_as_bytes.stderr @@ -0,0 +1,10 @@ +error: calling a slice of `as_bytes()` with `from_utf8` should be not necessary + --> $DIR/string_from_utf8_as_bytes.rs:5:13 + | +LL | let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&"Hello World!"[6..11])` + | + = note: `-D clippy::string-from-utf8-as-bytes` implied by `-D warnings` + +error: aborting due to previous error + From f83762b79cf23bfa91d77d6f04ec2b87b2159b07 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 2 Nov 2020 18:03:16 +0100 Subject: [PATCH 014/118] Skip rustfmt as it is wanted for this test --- clippy_lints/src/reference.rs | 23 ++++++++++------------- clippy_lints/src/try_err.rs | 6 ------ tests/ui/deref_addrof.fixed | 1 + tests/ui/deref_addrof.rs | 1 + tests/ui/deref_addrof.stderr | 4 ++-- 5 files changed, 14 insertions(+), 21 deletions(-) diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 8646d61673516..35a1310d68b84 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -1,11 +1,10 @@ use crate::utils::{in_macro, snippet_opt, snippet_with_applicability, span_lint_and_sugg}; use if_chain::if_chain; -use rustc_ast::ast::{Expr, ExprKind, UnOp, Mutability}; +use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::BytePos; -// use rustc_span::source_map::{BytePos, Span}; declare_clippy_lint! { /// **What it does:** Checks for usage of `*&` and `*&mut` in expressions. @@ -53,31 +52,29 @@ impl EarlyLintPass for DerefAddrOf { // Remove leading whitespace from the given span // e.g: ` $visitor` turns into `$visitor` let trim_leading_whitespaces = |span| { - if let Some(start_no_whitespace) = snippet_opt(cx, span).and_then(|snip| { + snippet_opt(cx, span).and_then(|snip| { + #[allow(clippy::cast_possible_truncation)] snip.find(|c: char| !c.is_whitespace()).map(|pos| { span.lo() + BytePos(pos as u32) }) - }) { - e.span.with_lo(start_no_whitespace) - } else { - span - } + }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) }; let rpos = if *mutability == Mutability::Mut { macro_source.rfind("mut").expect("already checked this is a mutable reference") + "mut".len() } else { - macro_source.rfind("&").expect("already checked this is a reference") + "&".len() + macro_source.rfind('&').expect("already checked this is a reference") + "&".len() }; + #[allow(clippy::cast_possible_truncation)] let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); let span = trim_leading_whitespaces(span_after_ref); - snippet_with_applicability(cx, span, "_", &mut applicability).to_string() + snippet_with_applicability(cx, span, "_", &mut applicability) } else { - snippet_with_applicability(cx, e.span, "_", &mut applicability).to_string() + snippet_with_applicability(cx, e.span, "_", &mut applicability) } } else { - snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability).to_string() - }; + snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability) + }.to_string(); span_lint_and_sugg( cx, DEREF_ADDROF, diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index e6d8e7521a8c4..9c1185d30f21d 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -92,13 +92,9 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { let expr_err_ty = cx.typeck_results().expr_ty(err_arg); - // println!("\n\n{:?}", in_macro(expr.span)); - // println!("{:#?}", snippet(cx, err_arg.span, "_")); let origin_snippet = if err_arg.span.from_expansion() && !in_macro(expr.span) { - // println!("from expansion"); snippet_with_macro_callsite(cx, err_arg.span, "_") } else { - // println!("just a snippet"); snippet(cx, err_arg.span, "_") }; let suggestion = if err_ty == expr_err_ty { @@ -106,8 +102,6 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { } else { format!("return {}{}.into(){}", prefix, origin_snippet, suffix) }; - // println!("origin_snippet: {:#?}", origin_snippet); - // println!("suggestion: {:#?}", suggestion); span_lint_and_sugg( cx, diff --git a/tests/ui/deref_addrof.fixed b/tests/ui/deref_addrof.fixed index 689e9d552234e..0795900558b69 100644 --- a/tests/ui/deref_addrof.fixed +++ b/tests/ui/deref_addrof.fixed @@ -38,6 +38,7 @@ fn main() { let b = *aref; } +#[rustfmt::skip] macro_rules! m { ($visitor: expr) => { $visitor diff --git a/tests/ui/deref_addrof.rs b/tests/ui/deref_addrof.rs index 57effce5d129d..60c4318601bc8 100644 --- a/tests/ui/deref_addrof.rs +++ b/tests/ui/deref_addrof.rs @@ -38,6 +38,7 @@ fn main() { let b = **&aref; } +#[rustfmt::skip] macro_rules! m { ($visitor: expr) => { *& $visitor diff --git a/tests/ui/deref_addrof.stderr b/tests/ui/deref_addrof.stderr index 52c1f7d1da8fe..e85b30fa56eb8 100644 --- a/tests/ui/deref_addrof.stderr +++ b/tests/ui/deref_addrof.stderr @@ -49,7 +49,7 @@ LL | let b = **&aref; | ^^^^^^ help: try this: `aref` error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:43:9 + --> $DIR/deref_addrof.rs:44:9 | LL | *& $visitor | ^^^^^^^^^^^ help: try this: `$visitor` @@ -60,7 +60,7 @@ LL | m!(self) = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: immediately dereferencing a reference - --> $DIR/deref_addrof.rs:50:9 + --> $DIR/deref_addrof.rs:51:9 | LL | *& mut $visitor | ^^^^^^^^^^^^^^^ help: try this: `$visitor` From 34244190d45d80bf66a0eec0d04f0254efd4c754 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 5 Nov 2020 14:29:48 +0100 Subject: [PATCH 015/118] Merge commit 'b20d4c155d2fe3a8391f86dcf9a8c49e17188703' into clippyup --- .github/driver.sh | 6 +- CHANGELOG.md | 10 +- CONTRIBUTING.md | 7 +- README.md | 15 +- clippy_dev/src/ra_setup.rs | 11 +- clippy_lints/src/arithmetic.rs | 25 +- clippy_lints/src/attrs.rs | 22 +- clippy_lints/src/booleans.rs | 5 +- clippy_lints/src/bytecount.rs | 3 +- clippy_lints/src/cognitive_complexity.rs | 6 +- clippy_lints/src/consts.rs | 6 +- clippy_lints/src/default.rs | 304 ++++++++++++++++++ clippy_lints/src/default_trait_access.rs | 62 ---- clippy_lints/src/doc.rs | 10 +- clippy_lints/src/explicit_write.rs | 3 +- clippy_lints/src/fallible_impl_from.rs | 8 +- clippy_lints/src/format.rs | 13 +- clippy_lints/src/functions.rs | 3 +- clippy_lints/src/get_last_with_len.rs | 3 +- clippy_lints/src/if_let_some_result.rs | 3 +- clippy_lints/src/inherent_to_string.rs | 3 +- clippy_lints/src/inline_fn_without_body.rs | 4 +- clippy_lints/src/items_after_statements.rs | 7 +- clippy_lints/src/len_zero.rs | 77 ++++- clippy_lints/src/lib.rs | 35 +- clippy_lints/src/lifetimes.rs | 10 +- clippy_lints/src/loops.rs | 22 +- clippy_lints/src/manual_non_exhaustive.rs | 10 +- clippy_lints/src/manual_ok_or.rs | 99 ++++++ clippy_lints/src/manual_unwrap_or.rs | 5 +- clippy_lints/src/map_clone.rs | 4 +- clippy_lints/src/map_identity.rs | 5 +- clippy_lints/src/map_unit_fn.rs | 5 +- clippy_lints/src/match_on_vec_items.rs | 3 +- clippy_lints/src/matches.rs | 9 +- .../src/methods/inefficient_to_string.rs | 3 +- clippy_lints/src/methods/mod.rs | 303 ++++++++++++----- .../src/methods/option_map_unwrap_or.rs | 12 +- .../src/methods/unnecessary_lazy_eval.rs | 5 +- clippy_lints/src/misc.rs | 15 +- clippy_lints/src/missing_doc.rs | 7 +- clippy_lints/src/missing_inline.rs | 3 +- clippy_lints/src/needless_borrow.rs | 3 +- clippy_lints/src/needless_pass_by_value.rs | 10 +- clippy_lints/src/new_without_default.rs | 3 +- clippy_lints/src/non_expressive_names.rs | 3 +- clippy_lints/src/option_if_let_else.rs | 3 +- clippy_lints/src/panic_in_result_fn.rs | 4 +- clippy_lints/src/partialeq_ne_impl.rs | 3 +- clippy_lints/src/pass_by_ref_or_value.rs | 6 +- clippy_lints/src/ptr.rs | 6 +- clippy_lints/src/ptr_offset_with_cast.rs | 3 +- clippy_lints/src/question_mark.rs | 3 +- clippy_lints/src/ranges.rs | 3 +- clippy_lints/src/redundant_clone.rs | 8 +- clippy_lints/src/ref_option_ref.rs | 66 ++++ clippy_lints/src/repeat_once.rs | 3 +- clippy_lints/src/returns.rs | 3 +- clippy_lints/src/strings.rs | 3 +- clippy_lints/src/swap.rs | 3 +- clippy_lints/src/try_err.rs | 9 +- clippy_lints/src/types.rs | 54 +++- clippy_lints/src/unnecessary_sort_by.rs | 3 +- clippy_lints/src/unused_unit.rs | 11 + clippy_lints/src/unwrap.rs | 9 +- clippy_lints/src/unwrap_in_result.rs | 14 +- clippy_lints/src/useless_conversion.rs | 5 +- clippy_lints/src/utils/internal_lints.rs | 4 +- clippy_lints/src/utils/mod.rs | 3 +- clippy_lints/src/utils/paths.rs | 2 + clippy_lints/src/write.rs | 5 +- doc/adding_lints.md | 2 +- src/lintlist/mod.rs | 56 +++- tests/ui/auxiliary/macro_rules.rs | 14 + tests/ui/borrow_box.rs | 16 + tests/ui/borrow_box.stderr | 50 ++- tests/ui/comparison_to_empty.fixed | 23 ++ tests/ui/comparison_to_empty.rs | 23 ++ tests/ui/comparison_to_empty.stderr | 28 ++ tests/ui/crashes/ice-6250.rs | 16 + tests/ui/crashes/ice-6250.stderr | 27 ++ tests/ui/crashes/ice-6251.rs | 6 + tests/ui/crashes/ice-6251.stderr | 43 +++ tests/ui/crashes/ice-6252.rs | 15 + tests/ui/crashes/ice-6252.stderr | 46 +++ tests/ui/crashes/ice-6254.rs | 15 + tests/ui/crashes/ice-6254.stderr | 12 + tests/ui/crashes/ice-6255.rs | 15 + tests/ui/crashes/ice-6255.stderr | 13 + tests/ui/crashes/ice-6256.rs | 13 + tests/ui/crashes/ice-6256.stderr | 18 ++ tests/ui/field_reassign_with_default.rs | 110 +++++++ tests/ui/field_reassign_with_default.stderr | 75 +++++ tests/ui/filter_map_next.rs | 3 - tests/ui/filter_map_next.stderr | 17 +- tests/ui/filter_map_next_fixable.fixed | 10 + tests/ui/filter_map_next_fixable.rs | 10 + tests/ui/filter_map_next_fixable.stderr | 10 + tests/ui/filter_methods.stderr | 8 +- tests/ui/find_map.stderr | 4 +- tests/ui/from_iter_instead_of_collect.rs | 13 + tests/ui/from_iter_instead_of_collect.stderr | 16 + tests/ui/get_unwrap.fixed | 2 +- tests/ui/get_unwrap.rs | 2 +- tests/ui/integer_arithmetic.rs | 10 + tests/ui/integer_arithmetic.stderr | 92 ++++-- tests/ui/item_after_statement.rs | 5 +- tests/ui/item_after_statement.stderr | 15 +- tests/ui/iter_skip_next.stderr | 8 +- tests/ui/manual_ok_or.fixed | 40 +++ tests/ui/manual_ok_or.rs | 44 +++ tests/ui/manual_ok_or.stderr | 41 +++ tests/ui/map_collect_result_unit.fixed | 16 + tests/ui/map_collect_result_unit.rs | 16 + tests/ui/map_collect_result_unit.stderr | 16 + tests/ui/map_unwrap_or.rs | 40 +-- tests/ui/map_unwrap_or.stderr | 99 +++--- tests/ui/map_unwrap_or_fixable.fixed | 54 ++++ tests/ui/map_unwrap_or_fixable.rs | 58 ++++ tests/ui/map_unwrap_or_fixable.stderr | 22 ++ tests/ui/match_type_on_diag_item.stderr | 8 +- tests/ui/methods.rs | 5 +- tests/ui/methods.stderr | 33 +- tests/ui/methods_fixable.fixed | 11 + tests/ui/methods_fixable.rs | 11 + tests/ui/methods_fixable.stderr | 10 + tests/ui/option_if_let_else.fixed | 1 + tests/ui/option_if_let_else.rs | 1 + tests/ui/option_if_let_else.stderr | 24 +- tests/ui/option_map_or_none.stderr | 4 +- tests/ui/ref_option_ref.rs | 47 +++ tests/ui/ref_option_ref.stderr | 70 ++++ tests/ui/single_char_add_str.fixed | 45 +++ tests/ui/single_char_add_str.rs | 45 +++ tests/ui/single_char_add_str.stderr | 94 ++++++ tests/ui/single_char_pattern.fixed | 12 +- tests/ui/single_char_pattern.rs | 6 - tests/ui/single_char_pattern.stderr | 72 +++-- tests/ui/single_char_push_str.fixed | 15 - tests/ui/single_char_push_str.rs | 15 - tests/ui/single_char_push_str.stderr | 34 -- tests/ui/skip_while_next.stderr | 8 +- tests/ui/toplevel_ref_arg.fixed | 21 ++ tests/ui/toplevel_ref_arg.rs | 21 ++ tests/ui/toplevel_ref_arg.stderr | 23 +- tests/ui/toplevel_ref_arg_non_rustfix.rs | 22 ++ tests/ui/toplevel_ref_arg_non_rustfix.stderr | 15 +- tests/ui/unused_unit.fixed | 31 +- tests/ui/unused_unit.rs | 9 + tests/ui/unused_unit.stderr | 68 ++-- 150 files changed, 2839 insertions(+), 675 deletions(-) create mode 100644 clippy_lints/src/default.rs delete mode 100644 clippy_lints/src/default_trait_access.rs create mode 100644 clippy_lints/src/manual_ok_or.rs create mode 100644 clippy_lints/src/ref_option_ref.rs create mode 100644 tests/ui/comparison_to_empty.fixed create mode 100644 tests/ui/comparison_to_empty.rs create mode 100644 tests/ui/comparison_to_empty.stderr create mode 100644 tests/ui/crashes/ice-6250.rs create mode 100644 tests/ui/crashes/ice-6250.stderr create mode 100644 tests/ui/crashes/ice-6251.rs create mode 100644 tests/ui/crashes/ice-6251.stderr create mode 100644 tests/ui/crashes/ice-6252.rs create mode 100644 tests/ui/crashes/ice-6252.stderr create mode 100644 tests/ui/crashes/ice-6254.rs create mode 100644 tests/ui/crashes/ice-6254.stderr create mode 100644 tests/ui/crashes/ice-6255.rs create mode 100644 tests/ui/crashes/ice-6255.stderr create mode 100644 tests/ui/crashes/ice-6256.rs create mode 100644 tests/ui/crashes/ice-6256.stderr create mode 100644 tests/ui/field_reassign_with_default.rs create mode 100644 tests/ui/field_reassign_with_default.stderr create mode 100644 tests/ui/filter_map_next_fixable.fixed create mode 100644 tests/ui/filter_map_next_fixable.rs create mode 100644 tests/ui/filter_map_next_fixable.stderr create mode 100644 tests/ui/from_iter_instead_of_collect.rs create mode 100644 tests/ui/from_iter_instead_of_collect.stderr create mode 100644 tests/ui/manual_ok_or.fixed create mode 100644 tests/ui/manual_ok_or.rs create mode 100644 tests/ui/manual_ok_or.stderr create mode 100644 tests/ui/map_collect_result_unit.fixed create mode 100644 tests/ui/map_collect_result_unit.rs create mode 100644 tests/ui/map_collect_result_unit.stderr create mode 100644 tests/ui/map_unwrap_or_fixable.fixed create mode 100644 tests/ui/map_unwrap_or_fixable.rs create mode 100644 tests/ui/map_unwrap_or_fixable.stderr create mode 100644 tests/ui/methods_fixable.fixed create mode 100644 tests/ui/methods_fixable.rs create mode 100644 tests/ui/methods_fixable.stderr create mode 100644 tests/ui/ref_option_ref.rs create mode 100644 tests/ui/ref_option_ref.stderr create mode 100644 tests/ui/single_char_add_str.fixed create mode 100644 tests/ui/single_char_add_str.rs create mode 100644 tests/ui/single_char_add_str.stderr delete mode 100644 tests/ui/single_char_push_str.fixed delete mode 100644 tests/ui/single_char_push_str.rs delete mode 100644 tests/ui/single_char_push_str.stderr diff --git a/.github/driver.sh b/.github/driver.sh index 321e00df153b6..6ff189fc85926 100644 --- a/.github/driver.sh +++ b/.github/driver.sh @@ -24,16 +24,16 @@ unset CARGO_MANIFEST_DIR # FIXME: How to match the clippy invocation in compile-test.rs? ./target/debug/clippy-driver -Dwarnings -Aunused -Zui-testing --emit metadata --crate-type bin tests/ui/double_neg.rs 2>double_neg.stderr && exit 1 sed -e "s,tests/ui,\$DIR," -e "/= help/d" double_neg.stderr >normalized.stderr -diff normalized.stderr tests/ui/double_neg.stderr +diff -u normalized.stderr tests/ui/double_neg.stderr # make sure "clippy-driver --rustc --arg" and "rustc --arg" behave the same SYSROOT=$(rustc --print sysroot) -diff <(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose) +diff -u <(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver --rustc --version --verbose) <(rustc --version --verbose) echo "fn main() {}" >target/driver_test.rs # we can't run 2 rustcs on the same file at the same time CLIPPY=$(LD_LIBRARY_PATH=${SYSROOT}/lib ./target/debug/clippy-driver ./target/driver_test.rs --rustc) RUSTC=$(rustc ./target/driver_test.rs) -diff <($CLIPPY) <($RUSTC) +diff -u <($CLIPPY) <($RUSTC) # TODO: CLIPPY_CONF_DIR / CARGO_MANIFEST_DIR diff --git a/CHANGELOG.md b/CHANGELOG.md index 25f3b5da198af..1b9b33803de26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ Current beta, release 2020-11-19 * [`map_err_ignore`] [#5998](https://github.com/rust-lang/rust-clippy/pull/5998) * [`rc_buffer`] [#6044](https://github.com/rust-lang/rust-clippy/pull/6044) * [`to_string_in_display`] [#5831](https://github.com/rust-lang/rust-clippy/pull/5831) -* [`single_char_push_str`] [#5881](https://github.com/rust-lang/rust-clippy/pull/5881) +* `single_char_push_str` [#5881](https://github.com/rust-lang/rust-clippy/pull/5881) ### Moves and Deprecations @@ -1665,6 +1665,7 @@ Released 2018-09-13 [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if [`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain +[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty [`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator [`create_dir`]: https://rust-lang.github.io/rust-clippy/master/index.html#create_dir [`crosspointer_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#crosspointer_transmute @@ -1713,6 +1714,7 @@ Released 2018-09-13 [`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice [`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from +[`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file [`filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map [`filter_map_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#filter_map_next @@ -1731,6 +1733,7 @@ Released 2018-09-13 [`for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles [`forget_copy`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_copy [`forget_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#forget_ref +[`from_iter_instead_of_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#from_iter_instead_of_collect [`future_not_send`]: https://rust-lang.github.io/rust-clippy/master/index.html#future_not_send [`get_last_with_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_last_with_len [`get_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#get_unwrap @@ -1795,6 +1798,7 @@ Released 2018-09-13 [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive +[`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip @@ -1802,6 +1806,7 @@ Released 2018-09-13 [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone +[`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry [`map_err_ignore`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_err_ignore [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten @@ -1917,6 +1922,7 @@ Released 2018-09-13 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref +[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts @@ -1937,8 +1943,8 @@ Released 2018-09-13 [`should_assert_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_assert_eq [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names +[`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern -[`single_char_push_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_push_str [`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6494695606c3a..a8e2123656e97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -63,9 +63,10 @@ To figure out how this syntax structure is encoded in the AST, it is recommended Usually the lint will end up to be a nested series of matches and ifs, [like so][deep-nesting]. But we can make it nest-less by using [if_chain] macro, [like this][nest-less]. -[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an E-easy issue first. -They are mostly classified as [`E-medium`], since they might be somewhat involved code wise, -but not difficult per-se. +[`E-medium`] issues are generally pretty easy too, though it's recommended you work on an [`good first issue`] +first. Sometimes they are only somewhat involved code wise, but not difficult per-se. +Note that [`E-medium`] issues may require some knowledge of Clippy internals or some +debugging to find the actual problem behind the issue. [`T-middle`] issues can be more involved and require verifying types. The [`ty`] module contains a lot of methods that are useful, though one of the most useful would be `expr_ty` (gives the type of diff --git a/README.md b/README.md index e1b3c84d6917d..8a5975e1f9711 100644 --- a/README.md +++ b/README.md @@ -167,18 +167,21 @@ You can add options to your code to `allow`/`warn`/`deny` Clippy lints: * `allow`/`warn`/`deny` can be limited to a single function or module using `#[allow(...)]`, etc. -Note: `deny` produces errors instead of warnings. +Note: `allow` means to suppress the lint for your code. With `warn` the lint +will only emit a warning, while with `deny` the lint will emit an error, when +triggering for your code. An error causes clippy to exit with an error code, so +is useful in scripts like CI/CD. -If you do not want to include your lint levels in your code, you can globally enable/disable lints -by passing extra flags to Clippy during the run: +If you do not want to include your lint levels in your code, you can globally +enable/disable lints by passing extra flags to Clippy during the run: -To disable `lint_name`, run +To allow `lint_name`, run ```terminal cargo clippy -- -A clippy::lint_name ``` -And to enable `lint_name`, run +And to warn on `lint_name`, run ```terminal cargo clippy -- -W clippy::lint_name @@ -190,7 +193,7 @@ can run Clippy with warnings for all lints enabled: cargo clippy -- -W clippy::pedantic ``` -If you care only about a single lint, you can allow all others and then explicitly reenable +If you care only about a single lint, you can allow all others and then explicitly warn on the lint(s) you are interested in: ```terminal cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::... diff --git a/clippy_dev/src/ra_setup.rs b/clippy_dev/src/ra_setup.rs index c67efc10f1578..9d9e836cc08a2 100644 --- a/clippy_dev/src/ra_setup.rs +++ b/clippy_dev/src/ra_setup.rs @@ -11,7 +11,7 @@ use std::path::PathBuf; // code. See https://github.com/rust-analyzer/rust-analyzer/issues/3517 and https://github.com/rust-lang/rust-clippy/issues/5514 for details pub fn run(rustc_path: Option<&str>) { - // we can unwrap here because the arg is required here + // we can unwrap here because the arg is required by clap let rustc_path = PathBuf::from(rustc_path.unwrap()); assert!(rustc_path.is_dir(), "path is not a directory"); let rustc_source_basedir = rustc_path.join("compiler"); @@ -49,6 +49,15 @@ fn inject_deps_into_manifest( cargo_toml: &str, lib_rs: &str, ) -> std::io::Result<()> { + // do not inject deps if we have aleady done so + if cargo_toml.contains("[target.'cfg(NOT_A_PLATFORM)'.dependencies]") { + eprintln!( + "cargo dev ra-setup: warning: deps already found inside {}, doing nothing.", + manifest_path + ); + return Ok(()); + } + let extern_crates = lib_rs .lines() // get the deps diff --git a/clippy_lints/src/arithmetic.rs b/clippy_lints/src/arithmetic.rs index e84481f9b5385..9861d8cfc4e5f 100644 --- a/clippy_lints/src/arithmetic.rs +++ b/clippy_lints/src/arithmetic.rs @@ -88,9 +88,28 @@ impl<'tcx> LateLintPass<'tcx> for Arithmetic { let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_span = Some(expr.span); - } else if l_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { + match op.node { + hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { + hir::ExprKind::Lit(_lit) => (), + hir::ExprKind::Unary(hir::UnOp::UnNeg, expr) => { + if let hir::ExprKind::Lit(lit) = &expr.kind { + if let rustc_ast::ast::LitKind::Int(1, _) = lit.node { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_span = Some(expr.span); + } + } + }, + _ => { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_span = Some(expr.span); + }, + }, + _ => { + span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); + self.expr_span = Some(expr.span); + }, + } + } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); self.expr_span = Some(expr.span); } diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index f6eadbdef0bb0..a004abb58b83e 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -16,6 +16,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; use rustc_span::symbol::{Symbol, SymbolStr}; use semver::Version; @@ -286,14 +287,14 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { }, _ => {}, } - if items.is_empty() || !attr.has_name(sym!(deprecated)) { + if items.is_empty() || !attr.has_name(sym::deprecated) { return; } for item in items { if_chain! { if let NestedMetaItem::MetaItem(mi) = &item; if let MetaItemKind::NameValue(lit) = &mi.kind; - if mi.has_name(sym!(since)); + if mi.has_name(sym::since); then { check_semver(cx, item.span(), lit); } @@ -309,7 +310,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { } match item.kind { ItemKind::ExternCrate(..) | ItemKind::Use(..) => { - let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym!(macro_use))); + let skip_unused_imports = item.attrs.iter().any(|attr| attr.has_name(sym::macro_use)); for attr in item.attrs { if in_external_macro(cx.sess(), attr.span) { @@ -326,7 +327,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { match item.kind { ItemKind::Use(..) => { if is_word(lint, sym!(unused_imports)) - || is_word(lint, sym!(deprecated)) + || is_word(lint, sym::deprecated) || is_word(lint, sym!(unreachable_pub)) || is_word(lint, sym!(unused)) || extract_clippy_lint(lint) @@ -411,8 +412,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMet let lint_store = cx.lints(); for lint in items { if let Some(lint_name) = extract_clippy_lint(lint) { - if let CheckLintNameResult::Tool(Err((None, _))) = - lint_store.check_lint_name(&lint_name, Some(sym!(clippy))) + if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(&lint_name, Some(sym::clippy)) { span_lint_and_then( cx, @@ -529,10 +529,10 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut for attr in attrs { if let Some(values) = attr.meta_item_list() { - if values.len() != 1 || !attr.has_name(sym!(inline)) { + if values.len() != 1 || !attr.has_name(sym::inline) { continue; } - if is_word(&values[0], sym!(always)) { + if is_word(&values[0], sym::always) { span_lint( cx, INLINE_ALWAYS, @@ -623,12 +623,12 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute) { if_chain! { // check cfg_attr - if attr.has_name(sym!(cfg_attr)); + if attr.has_name(sym::cfg_attr); if let Some(items) = attr.meta_item_list(); if items.len() == 2; // check for `rustfmt` if let Some(feature_item) = items[0].meta_item(); - if feature_item.has_name(sym!(rustfmt)); + if feature_item.has_name(sym::rustfmt); // check for `rustfmt_skip` and `rustfmt::skip` if let Some(skip_item) = &items[1].meta_item(); if skip_item.has_name(sym!(rustfmt_skip)) || @@ -690,7 +690,7 @@ fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { } if_chain! { - if attr.has_name(sym!(cfg)); + if attr.has_name(sym::cfg); if let Some(list) = attr.meta_item_list(); let mismatched = find_mismatched_target_os(&list); if !mismatched.is_empty(); diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs index 280a2c7fe6770..90bb0bd555f27 100644 --- a/clippy_lints/src/booleans.rs +++ b/clippy_lints/src/booleans.rs @@ -11,6 +11,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for boolean expressions that can be written more @@ -253,8 +254,8 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { }, ExprKind::MethodCall(path, _, args, _) if args.len() == 1 => { let type_of_receiver = cx.typeck_results().expr_ty(&args[0]); - if !is_type_diagnostic_item(cx, type_of_receiver, sym!(option_type)) - && !is_type_diagnostic_item(cx, type_of_receiver, sym!(result_type)) + if !is_type_diagnostic_item(cx, type_of_receiver, sym::option_type) + && !is_type_diagnostic_item(cx, type_of_receiver, sym::result_type) { return None; } diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs index d7d02ebf985c8..38a0e27c4cf5b 100644 --- a/clippy_lints/src/bytecount.rs +++ b/clippy_lints/src/bytecount.rs @@ -8,6 +8,7 @@ use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use rustc_span::Symbol; declare_clippy_lint! { @@ -68,7 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount { let haystack = if let ExprKind::MethodCall(ref path, _, ref args, _) = filter_args[0].kind { let p = path.ident.name; - if (p == sym!(iter) || p == sym!(iter_mut)) && args.len() == 1 { + if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 { &args[0] } else { &filter_args[0] diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index 14ef8c319eff1..b1bc2ec29e16e 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; -use rustc_span::BytePos; +use rustc_span::{sym, BytePos}; use crate::utils::{is_type_diagnostic_item, snippet_opt, span_lint_and_help, LimitStack}; @@ -61,7 +61,7 @@ impl CognitiveComplexity { helper.visit_expr(expr); let CCHelper { cc, returns } = helper; let ret_ty = cx.typeck_results().node_type(expr.hir_id); - let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym!(result_type)) { + let ret_adjust = if is_type_diagnostic_item(cx, ret_ty, sym::result_type) { returns } else { #[allow(clippy::integer_division)] @@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for CognitiveComplexity { hir_id: HirId, ) { let def_id = cx.tcx.hir().local_def_id(hir_id); - if !cx.tcx.has_attr(def_id.to_def_id(), sym!(test)) { + if !cx.tcx.has_attr(def_id.to_def_id(), sym::test) { self.check(cx, kind, decl, body, span); } } diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index c8bbc9ce2b028..0035ded9356cf 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -7,10 +7,10 @@ use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, QPath, UnOp}; use rustc_lint::LateContext; +use rustc_middle::mir::interpret::Scalar; use rustc_middle::ty::subst::{Subst, SubstsRef}; -use rustc_middle::ty::{self, Ty, TyCtxt, ScalarInt}; +use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; -use rustc_middle::mir::interpret::Scalar; use rustc_span::symbol::Symbol; use std::cmp::Ordering::{self, Equal}; use std::convert::TryInto; @@ -501,7 +501,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } pub fn miri_to_const(result: &ty::Const<'_>) -> Option { - use rustc_middle::mir::interpret::{ConstValue}; + use rustc_middle::mir::interpret::ConstValue; match result.val { ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => { match result.ty.kind() { diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs new file mode 100644 index 0000000000000..612c5355338a1 --- /dev/null +++ b/clippy_lints/src/default.rs @@ -0,0 +1,304 @@ +use crate::utils::{any_parent_is_automatically_derived, contains_name, match_def_path, paths, qpath_res, snippet}; +use crate::utils::{span_lint_and_note, span_lint_and_sugg}; +use if_chain::if_chain; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::Applicability; +use rustc_hir::def::Res; +use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, Adt, Ty}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::symbol::{Ident, Symbol}; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for literal calls to `Default::default()`. + /// + /// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is + /// being gotten than the generic `Default`. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// // Bad + /// let s: String = Default::default(); + /// + /// // Good + /// let s = String::default(); + /// ``` + pub DEFAULT_TRAIT_ACCESS, + pedantic, + "checks for literal calls to `Default::default()`" +} + +declare_clippy_lint! { + /// **What it does:** Checks for immediate reassignment of fields initialized + /// with Default::default(). + /// + /// **Why is this bad?**It's more idiomatic to use the [functional update syntax](https://doc.rust-lang.org/reference/expressions/struct-expr.html#functional-update-syntax). + /// + /// **Known problems:** Assignments to patterns that are of tuple type are not linted. + /// + /// **Example:** + /// Bad: + /// ``` + /// # #[derive(Default)] + /// # struct A { i: i32 } + /// let mut a: A = Default::default(); + /// a.i = 42; + /// ``` + /// Use instead: + /// ``` + /// # #[derive(Default)] + /// # struct A { i: i32 } + /// let a = A { + /// i: 42, + /// .. Default::default() + /// }; + /// ``` + pub FIELD_REASSIGN_WITH_DEFAULT, + style, + "binding initialized with Default should have its fields set in the initializer" +} + +#[derive(Default)] +pub struct Default { + // Spans linted by `field_reassign_with_default`. + reassigned_linted: FxHashSet, +} + +impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]); + +impl LateLintPass<'_> for Default { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { + if_chain! { + // Avoid cases already linted by `field_reassign_with_default` + if !self.reassigned_linted.contains(&expr.span); + if let ExprKind::Call(ref path, ..) = expr.kind; + if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); + if let ExprKind::Path(ref qpath) = path.kind; + if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); + if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); + // Detect and ignore ::default() because these calls do explicitly name the type. + if let QPath::Resolved(None, _path) = qpath; + then { + let expr_ty = cx.typeck_results().expr_ty(expr); + if let ty::Adt(def, ..) = expr_ty.kind() { + // TODO: Work out a way to put "whatever the imported way of referencing + // this type in this file" rather than a fully-qualified type. + let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); + span_lint_and_sugg( + cx, + DEFAULT_TRAIT_ACCESS, + expr.span, + &format!("calling `{}` is more clear than this expression", replacement), + "try", + replacement, + Applicability::Unspecified, // First resolve the TODO above + ); + } + } + } + } + + fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { + // find all binding statements like `let mut _ = T::default()` where `T::default()` is the + // `default` method of the `Default` trait, and store statement index in current block being + // checked and the name of the bound variable + let binding_statements_using_default = enumerate_bindings_using_default(cx, block); + + // start from the `let mut _ = _::default();` and look at all the following + // statements, see if they re-assign the fields of the binding + for (stmt_idx, binding_name, binding_type, span) in binding_statements_using_default { + // the last statement of a block cannot trigger the lint + if stmt_idx == block.stmts.len() - 1 { + break; + } + + // find all "later statement"'s where the fields of the binding set as + // Default::default() get reassigned, unless the reassignment refers to the original binding + let mut first_assign = None; + let mut assigned_fields = Vec::new(); + let mut cancel_lint = false; + for consecutive_statement in &block.stmts[stmt_idx + 1..] { + // interrupt if the statement is a let binding (`Local`) that shadows the original + // binding + if stmt_shadows_binding(consecutive_statement, binding_name) { + break; + } + // find out if and which field was set by this `consecutive_statement` + else if let Some((field_ident, assign_rhs)) = + field_reassigned_by_stmt(consecutive_statement, binding_name) + { + // interrupt and cancel lint if assign_rhs references the original binding + if contains_name(binding_name, assign_rhs) { + cancel_lint = true; + break; + } + + // if the field was previously assigned, replace the assignment, otherwise insert the assignment + if let Some(prev) = assigned_fields + .iter_mut() + .find(|(field_name, _)| field_name == &field_ident.name) + { + *prev = (field_ident.name, assign_rhs); + } else { + assigned_fields.push((field_ident.name, assign_rhs)); + } + + // also set first instance of error for help message + if first_assign.is_none() { + first_assign = Some(consecutive_statement); + } + } + // interrupt also if no field was assigned, since we only want to look at consecutive statements + else { + break; + } + } + + // if there are incorrectly assigned fields, do a span_lint_and_note to suggest + // construction using `Ty { fields, ..Default::default() }` + if !assigned_fields.is_empty() && !cancel_lint { + // take the original assignment as span + let stmt = &block.stmts[stmt_idx]; + + if let StmtKind::Local(preceding_local) = &stmt.kind { + // filter out fields like `= Default::default()`, because the FRU already covers them + let assigned_fields = assigned_fields + .into_iter() + .filter(|(_, rhs)| !is_expr_default(rhs, cx)) + .collect::)>>(); + + // if all fields of the struct are not assigned, add `.. Default::default()` to the suggestion. + let ext_with_default = !fields_of_type(binding_type) + .iter() + .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name)); + + let field_list = assigned_fields + .into_iter() + .map(|(field, rhs)| { + // extract and store the assigned value for help message + let value_snippet = snippet(cx, rhs.span, ".."); + format!("{}: {}", field, value_snippet) + }) + .collect::>() + .join(", "); + + let sugg = if ext_with_default { + if field_list.is_empty() { + format!("{}::default()", binding_type) + } else { + format!("{} {{ {}, ..Default::default() }}", binding_type, field_list) + } + } else { + format!("{} {{ {} }}", binding_type, field_list) + }; + + // span lint once per statement that binds default + span_lint_and_note( + cx, + FIELD_REASSIGN_WITH_DEFAULT, + first_assign.unwrap().span, + "field assignment outside of initializer for an instance created with Default::default()", + Some(preceding_local.span), + &format!( + "consider initializing the variable with `{}` and removing relevant reassignments", + sugg + ), + ); + self.reassigned_linted.insert(span); + } + } + } + } +} + +/// Checks if the given expression is the `default` method belonging to the `Default` trait. +fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool { + if_chain! { + if let ExprKind::Call(ref fn_expr, _) = &expr.kind; + if let ExprKind::Path(qpath) = &fn_expr.kind; + if let Res::Def(_, def_id) = qpath_res(cx, qpath, fn_expr.hir_id); + then { + // right hand side of assignment is `Default::default` + match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD) + } else { + false + } + } +} + +/// Returns the block indices, identifiers and types of bindings set as `Default::default()`, except +/// for when the pattern type is a tuple. +fn enumerate_bindings_using_default<'tcx>( + cx: &LateContext<'tcx>, + block: &Block<'tcx>, +) -> Vec<(usize, Symbol, Ty<'tcx>, Span)> { + block + .stmts + .iter() + .enumerate() + .filter_map(|(idx, stmt)| { + if_chain! { + // only take `let ...` statements + if let StmtKind::Local(ref local) = stmt.kind; + // only take bindings to identifiers + if let PatKind::Binding(_, _, ident, _) = local.pat.kind; + // that are not tuples + let ty = cx.typeck_results().pat_ty(local.pat); + if !matches!(ty.kind(), ty::Tuple(_)); + // only when assigning `... = Default::default()` + if let Some(ref expr) = local.init; + if is_expr_default(expr, cx); + then { + Some((idx, ident.name, ty, expr.span)) + } else { + None + } + } + }) + .collect() +} + +fn stmt_shadows_binding(this: &Stmt<'_>, shadowed: Symbol) -> bool { + if let StmtKind::Local(local) = &this.kind { + if let PatKind::Binding(_, _, ident, _) = local.pat.kind { + return ident.name == shadowed; + } + } + false +} + +/// Returns the reassigned field and the assigning expression (right-hand side of assign). +fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> { + if_chain! { + // only take assignments + if let StmtKind::Semi(ref later_expr) = this.kind; + if let ExprKind::Assign(ref assign_lhs, ref assign_rhs, _) = later_expr.kind; + // only take assignments to fields where the left-hand side field is a field of + // the same binding as the previous statement + if let ExprKind::Field(ref binding, field_ident) = assign_lhs.kind; + if let ExprKind::Path(ref qpath) = binding.kind; + if let QPath::Resolved(_, path) = qpath; + if let Some(second_binding_name) = path.segments.last(); + if second_binding_name.ident.name == binding_name; + then { + Some((field_ident, assign_rhs)) + } else { + None + } + } +} + +/// Returns the vec of fields for a struct and an empty vec for non-struct ADTs. +fn fields_of_type(ty: Ty<'_>) -> Vec { + if let Adt(adt, _) = ty.kind() { + if adt.is_struct() { + let variant = &adt.non_enum_variant(); + return variant.fields.iter().map(|f| f.ident).collect(); + } + } + vec![] +} diff --git a/clippy_lints/src/default_trait_access.rs b/clippy_lints/src/default_trait_access.rs deleted file mode 100644 index 3048436d9a7b5..0000000000000 --- a/clippy_lints/src/default_trait_access.rs +++ /dev/null @@ -1,62 +0,0 @@ -use if_chain::if_chain; -use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, QPath}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; - -use crate::utils::{any_parent_is_automatically_derived, match_def_path, paths, span_lint_and_sugg}; - -declare_clippy_lint! { - /// **What it does:** Checks for literal calls to `Default::default()`. - /// - /// **Why is this bad?** It's more clear to the reader to use the name of the type whose default is - /// being gotten than the generic `Default`. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// // Bad - /// let s: String = Default::default(); - /// - /// // Good - /// let s = String::default(); - /// ``` - pub DEFAULT_TRAIT_ACCESS, - pedantic, - "checks for literal calls to `Default::default()`" -} - -declare_lint_pass!(DefaultTraitAccess => [DEFAULT_TRAIT_ACCESS]); - -impl<'tcx> LateLintPass<'tcx> for DefaultTraitAccess { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Call(ref path, ..) = expr.kind; - if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id); - if let ExprKind::Path(ref qpath) = path.kind; - if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); - if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD); - // Detect and ignore ::default() because these calls do explicitly name the type. - if let QPath::Resolved(None, _path) = qpath; - then { - let expr_ty = cx.typeck_results().expr_ty(expr); - if let ty::Adt(def, ..) = expr_ty.kind() { - // TODO: Work out a way to put "whatever the imported way of referencing - // this type in this file" rather than a fully-qualified type. - let replacement = format!("{}::default()", cx.tcx.def_path_str(def.did)); - span_lint_and_sugg( - cx, - DEFAULT_TRAIT_ACCESS, - expr.span, - &format!("calling `{}` is more clear than this expression", replacement), - "try", - replacement, - Applicability::Unspecified, // First resolve the TODO above - ); - } - } - } - } -} diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs index 07f604cf71472..edecba57e44f0 100644 --- a/clippy_lints/src/doc.rs +++ b/clippy_lints/src/doc.rs @@ -15,7 +15,7 @@ use rustc_parse::maybe_new_parser_from_source_str; use rustc_session::parse::ParseSess; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{BytePos, FilePathMapping, MultiSpan, SourceMap, Span}; -use rustc_span::{FileName, Pos}; +use rustc_span::{sym, FileName, Pos}; use std::io; use std::ops::Range; use url::Url; @@ -237,7 +237,7 @@ fn lint_for_missing_headers<'tcx>( ); } if !headers.errors { - if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { + if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { span_lint( cx, MISSING_ERRORS_DOC, @@ -255,7 +255,7 @@ fn lint_for_missing_headers<'tcx>( if let ty::Opaque(_, subs) = ret_ty.kind(); if let Some(gen) = subs.types().next(); if let ty::Generator(_, subs, _) = gen.kind(); - if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym!(result_type)); + if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::result_type); then { span_lint( cx, @@ -333,7 +333,7 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span); spans.extend_from_slice(¤t_spans); doc.push_str(&comment); - } else if attr.has_name(sym!(doc)) { + } else if attr.has_name(sym::doc) { // ignore mix of sugared and non-sugared doc // don't trigger the safety or errors check return DocHeaders { @@ -479,7 +479,7 @@ fn check_code(cx: &LateContext<'_>, text: &str, span: Span) { | ItemKind::ExternCrate(..) | ItemKind::ForeignMod(..) => return false, // We found a main function ... - ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym!(main) => { + ItemKind::Fn(_, sig, _, Some(block)) if item.ident.name == sym::main => { let is_async = matches!(sig.header.asyncness, Async::Yes{..}); let returns_nothing = match &sig.decl.output { FnRetTy::Default(..) => true, diff --git a/clippy_lints/src/explicit_write.rs b/clippy_lints/src/explicit_write.rs index 0240e80d81418..f8038d06e5034 100644 --- a/clippy_lints/src/explicit_write.rs +++ b/clippy_lints/src/explicit_write.rs @@ -5,6 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usage of `write!()` / `writeln()!` which can be @@ -33,7 +34,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite { if_chain! { // match call to unwrap if let ExprKind::MethodCall(ref unwrap_fun, _, ref unwrap_args, _) = expr.kind; - if unwrap_fun.ident.name == sym!(unwrap); + if unwrap_fun.ident.name == sym::unwrap; // match call to write_fmt if !unwrap_args.is_empty(); if let ExprKind::MethodCall(ref write_fun, _, write_args, _) = diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index a9e05fddbe762..fe817fe94f2e4 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -6,7 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for impls of `From<..>` that contain `panic!()` or `unwrap()` @@ -95,8 +95,8 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) { self.result.push(expr.span); } @@ -113,7 +113,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h for impl_item in impl_items { if_chain! { - if impl_item.ident.name == sym!(from); + if impl_item.ident.name == sym::from; if let ImplItemKind::Fn(_, body_id) = cx.tcx.hir().impl_item(impl_item.id).kind; then { diff --git a/clippy_lints/src/format.rs b/clippy_lints/src/format.rs index 26da058598e4f..8e41e0e34daf7 100644 --- a/clippy_lints/src/format.rs +++ b/clippy_lints/src/format.rs @@ -10,6 +10,7 @@ use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, MatchSource, PatKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for the use of `format!("string literal with no @@ -91,7 +92,7 @@ fn on_argumentv1_new<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arms: & if pats.len() == 1; then { let ty = cx.typeck_results().pat_ty(&pats[0]).peel_refs(); - if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym!(string_type)) { + if *ty.kind() != rustc_middle::ty::Str && !is_type_diagnostic_item(cx, ty, sym::string_type) { return None; } if let ExprKind::Lit(ref lit) = format_args.kind { @@ -186,15 +187,15 @@ fn check_unformatted(expr: &Expr<'_>) -> bool { if exprs.len() == 1; // struct `core::fmt::rt::v1::Argument` if let ExprKind::Struct(_, ref fields, _) = exprs[0].kind; - if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym!(format)); + if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format); // struct `core::fmt::rt::v1::FormatSpec` if let ExprKind::Struct(_, ref fields, _) = format_field.expr.kind; - if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym!(precision)); + if let Some(precision_field) = fields.iter().find(|f| f.ident.name == sym::precision); if let ExprKind::Path(ref precision_path) = precision_field.expr.kind; - if last_path_segment(precision_path).ident.name == sym!(Implied); - if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym!(width)); + if last_path_segment(precision_path).ident.name == sym::Implied; + if let Some(width_field) = fields.iter().find(|f| f.ident.name == sym::width); if let ExprKind::Path(ref width_qpath) = width_field.expr.kind; - if last_path_segment(width_qpath).ident.name == sym!(Implied); + if last_path_segment(width_qpath).ident.name == sym::Implied; then { return true; } diff --git a/clippy_lints/src/functions.rs b/clippy_lints/src/functions.rs index 9c0efef95de8a..8b58d1f26013a 100644 --- a/clippy_lints/src/functions.rs +++ b/clippy_lints/src/functions.rs @@ -16,6 +16,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; +use rustc_span::sym; use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; @@ -473,7 +474,7 @@ fn check_result_unit_err(cx: &LateContext<'_>, decl: &hir::FnDecl<'_>, item_span if !in_external_macro(cx.sess(), item_span); if let hir::FnRetTy::Return(ref ty) = decl.output; if let hir::TyKind::Path(ref qpath) = ty.kind; - if is_type_diagnostic_item(cx, hir_ty_to_ty(cx.tcx, ty), sym!(result_type)); + if is_type_diagnostic_item(cx, hir_ty_to_ty(cx.tcx, ty), sym::result_type); if let Some(ref args) = last_path_segment(qpath).args; if let [_, hir::GenericArg::Type(ref err_ty)] = args.args; if let hir::TyKind::Tup(t) = err_ty.kind; diff --git a/clippy_lints/src/get_last_with_len.rs b/clippy_lints/src/get_last_with_len.rs index 48ebcf5ebcd9c..cdd8a42e7cd12 100644 --- a/clippy_lints/src/get_last_with_len.rs +++ b/clippy_lints/src/get_last_with_len.rs @@ -8,6 +8,7 @@ use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for using `x.get(x.len() - 1)` instead of @@ -55,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for GetLastWithLen { // Argument 0 (the struct we're calling the method on) is a vector if let Some(struct_calling_on) = args.get(0); let struct_ty = cx.typeck_results().expr_ty(struct_calling_on); - if is_type_diagnostic_item(cx, struct_ty, sym!(vec_type)); + if is_type_diagnostic_item(cx, struct_ty, sym::vec_type); // Argument to "get" is a subtraction if let Some(get_index_arg) = args.get(1); diff --git a/clippy_lints/src/if_let_some_result.rs b/clippy_lints/src/if_let_some_result.rs index 28b20cdeac343..e0a1f4c5ca4f2 100644 --- a/clippy_lints/src/if_let_some_result.rs +++ b/clippy_lints/src/if_let_some_result.rs @@ -4,6 +4,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:*** Checks for unnecessary `ok()` in if let. @@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for OkIfLet { if let ExprKind::MethodCall(_, ok_span, ref result_types, _) = op.kind; //check is expr.ok() has type Result.ok(, _) if let PatKind::TupleStruct(QPath::Resolved(_, ref x), ref y, _) = body[0].pat.kind; //get operation if method_chain_args(op, &["ok"]).is_some(); //test to see if using ok() methoduse std::marker::Sized; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym!(result_type)); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&result_types[0]), sym::result_type); if rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_path(x, false)) == "Some"; then { diff --git a/clippy_lints/src/inherent_to_string.rs b/clippy_lints/src/inherent_to_string.rs index 0877b44d90138..b723d06a6881d 100644 --- a/clippy_lints/src/inherent_to_string.rs +++ b/clippy_lints/src/inherent_to_string.rs @@ -2,6 +2,7 @@ use if_chain::if_chain; use rustc_hir::{ImplItem, ImplItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use crate::utils::{ get_trait_def_id, implements_trait, is_type_diagnostic_item, paths, return_ty, span_lint_and_help, @@ -107,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString { if decl.inputs.len() == 1; // Check if return type is String - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type)); + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::string_type); // Filters instances of to_string which are required by a trait if trait_ref_of_method(cx, impl_item.hir_id).is_none(); diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs index 4b605fdb366a9..d1c3fdc71461b 100644 --- a/clippy_lints/src/inline_fn_without_body.rs +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; declare_clippy_lint! { /// **What it does:** Checks for `#[inline]` on trait methods without bodies @@ -41,7 +41,7 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) { for attr in attrs { - if !attr.has_name(sym!(inline)) { + if !attr.has_name(sym::inline) { continue; } diff --git a/clippy_lints/src/items_after_statements.rs b/clippy_lints/src/items_after_statements.rs index c8576bcfcb444..8998fae09de31 100644 --- a/clippy_lints/src/items_after_statements.rs +++ b/clippy_lints/src/items_after_statements.rs @@ -2,7 +2,8 @@ use crate::utils::span_lint; use rustc_ast::ast::{Block, ItemKind, StmtKind}; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { @@ -53,7 +54,7 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]); impl EarlyLintPass for ItemsAfterStatements { fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) { - if item.span.from_expansion() { + if in_external_macro(cx.sess(), item.span) { return; } @@ -67,7 +68,7 @@ impl EarlyLintPass for ItemsAfterStatements { // lint on all further items for stmt in stmts { if let StmtKind::Item(ref it) = *stmt { - if it.span.from_expansion() { + if in_external_macro(cx.sess(), it.span) { return; } if let ItemKind::MacroDef(..) = it.kind { diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index c9c4891bb08ac..8e2f03d6e4e91 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -68,7 +68,44 @@ declare_clippy_lint! { "traits or impls with a public `len` method but no corresponding `is_empty` method" } -declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY]); +declare_clippy_lint! { + /// **What it does:** Checks for comparing to an empty slice such as "" or [],` + /// and suggests using `.is_empty()` where applicable. + /// + /// **Why is this bad?** Some structures can answer `.is_empty()` much faster + /// than checking for equality. So it is good to get into the habit of using + /// `.is_empty()`, and having it is cheap. + /// Besides, it makes the intent clearer than a manual comparison in some contexts. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```ignore + /// if s == "" { + /// .. + /// } + /// + /// if arr == [] { + /// .. + /// } + /// ``` + /// Use instead: + /// ```ignore + /// if s.is_empty() { + /// .. + /// } + /// + /// if arr.is_empty() { + /// .. + /// } + /// ``` + pub COMPARISON_TO_EMPTY, + style, + "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead" +} + +declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]); impl<'tcx> LateLintPass<'tcx> for LenZero { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { @@ -221,6 +258,8 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to) + } else { + check_empty_expr(cx, span, method, lit, op) } } @@ -258,6 +297,42 @@ fn check_len( } } +fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) { + if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) { + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + COMPARISON_TO_EMPTY, + span, + "comparison to empty slice", + &format!("using `{}is_empty` is clearer and more explicit", op), + format!( + "{}{}.is_empty()", + op, + snippet_with_applicability(cx, lit1.span, "_", &mut applicability) + ), + applicability, + ); + } +} + +fn is_empty_string(expr: &Expr<'_>) -> bool { + if let ExprKind::Lit(ref lit) = expr.kind { + if let LitKind::Str(lit, _) = lit.node { + let lit = lit.as_str(); + return lit == ""; + } + } + false +} + +fn is_empty_array(expr: &Expr<'_>) -> bool { + if let ExprKind::Array(ref arr) = expr.kind { + return arr.is_empty(); + } + false +} + /// Checks if this type has an `is_empty` method. fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { /// Gets an `AssocItem` and return true if it matches `is_empty(self)`. diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index e97fa543a093d..126852df502eb 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -176,7 +176,7 @@ mod copies; mod copy_iterator; mod create_dir; mod dbg_macro; -mod default_trait_access; +mod default; mod dereference; mod derive; mod disallowed_method; @@ -234,6 +234,7 @@ mod macro_use; mod main_recursion; mod manual_async_fn; mod manual_non_exhaustive; +mod manual_ok_or; mod manual_strip; mod manual_unwrap_or; mod map_clone; @@ -294,6 +295,7 @@ mod redundant_closure_call; mod redundant_field_names; mod redundant_pub_crate; mod redundant_static_lifetimes; +mod ref_option_ref; mod reference; mod regex; mod repeat_once; @@ -537,7 +539,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ©_iterator::COPY_ITERATOR, &create_dir::CREATE_DIR, &dbg_macro::DBG_MACRO, - &default_trait_access::DEFAULT_TRAIT_ACCESS, + &default::DEFAULT_TRAIT_ACCESS, + &default::FIELD_REASSIGN_WITH_DEFAULT, &dereference::EXPLICIT_DEREF_METHODS, &derive::DERIVE_HASH_XOR_EQ, &derive::DERIVE_ORD_XOR_PARTIAL_ORD, @@ -615,6 +618,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &large_const_arrays::LARGE_CONST_ARRAYS, &large_enum_variant::LARGE_ENUM_VARIANT, &large_stack_arrays::LARGE_STACK_ARRAYS, + &len_zero::COMPARISON_TO_EMPTY, &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, &let_if_seq::USELESS_LET_IF_SEQ, @@ -649,6 +653,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &main_recursion::MAIN_RECURSION, &manual_async_fn::MANUAL_ASYNC_FN, &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, + &manual_ok_or::MANUAL_OK_OR, &manual_strip::MANUAL_STRIP, &manual_unwrap_or::MANUAL_UNWRAP_OR, &map_clone::MAP_CLONE, @@ -692,6 +697,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::FILTER_NEXT, &methods::FIND_MAP, &methods::FLAT_MAP_IDENTITY, + &methods::FROM_ITER_INSTEAD_OF_COLLECT, &methods::GET_UNWRAP, &methods::INEFFICIENT_TO_STRING, &methods::INTO_ITER_ON_REF, @@ -702,6 +708,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::ITER_NTH_ZERO, &methods::ITER_SKIP_NEXT, &methods::MANUAL_SATURATING_ARITHMETIC, + &methods::MAP_COLLECT_RESULT_UNIT, &methods::MAP_FLATTEN, &methods::MAP_UNWRAP_OR, &methods::NEW_RET_NO_SELF, @@ -712,8 +719,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &methods::RESULT_MAP_OR_INTO_OPTION, &methods::SEARCH_IS_SOME, &methods::SHOULD_IMPLEMENT_TRAIT, + &methods::SINGLE_CHAR_ADD_STR, &methods::SINGLE_CHAR_PATTERN, - &methods::SINGLE_CHAR_PUSH_STR, &methods::SKIP_WHILE_NEXT, &methods::STRING_EXTEND_CHARS, &methods::SUSPICIOUS_MAP, @@ -807,6 +814,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &redundant_field_names::REDUNDANT_FIELD_NAMES, &redundant_pub_crate::REDUNDANT_PUB_CRATE, &redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES, + &ref_option_ref::REF_OPTION_REF, &reference::DEREF_ADDROF, &reference::REF_IN_DEREF, ®ex::INVALID_REGEX, @@ -1030,6 +1038,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &sess.target, ); store.register_late_pass(move || box pass_by_ref_or_value); + store.register_late_pass(|| box ref_option_ref::RefOptionRef); store.register_late_pass(|| box try_err::TryErr); store.register_late_pass(|| box use_self::UseSelf); store.register_late_pass(|| box bytecount::ByteCount); @@ -1047,7 +1056,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd); store.register_late_pass(|| box unwrap::Unwrap); store.register_late_pass(|| box duration_subsec::DurationSubsec); - store.register_late_pass(|| box default_trait_access::DefaultTraitAccess); store.register_late_pass(|| box indexing_slicing::IndexingSlicing); store.register_late_pass(|| box non_copy_const::NonCopyConst); store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast); @@ -1098,6 +1106,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: let enum_variant_name_threshold = conf.enum_variant_name_threshold; store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold)); store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments); + store.register_late_pass(|| box default::Default::default()); store.register_late_pass(|| box unused_self::UnusedSelf); store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall); store.register_late_pass(|| box exit::Exit); @@ -1146,6 +1155,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); store.register_late_pass(|| box self_assignment::SelfAssignment); store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr); + store.register_late_pass(|| box manual_ok_or::ManualOkOr); store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); store.register_late_pass(|| box manual_strip::ManualStrip); @@ -1210,7 +1220,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&checked_conversions::CHECKED_CONVERSIONS), LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), LintId::of(©_iterator::COPY_ITERATOR), - LintId::of(&default_trait_access::DEFAULT_TRAIT_ACCESS), + LintId::of(&default::DEFAULT_TRAIT_ACCESS), LintId::of(&dereference::EXPLICIT_DEREF_METHODS), LintId::of(&derive::EXPL_IMPL_CLONE_ON_COPY), LintId::of(&derive::UNSAFE_DERIVE_DESERIALIZE), @@ -1234,6 +1244,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), LintId::of(&loops::EXPLICIT_ITER_LOOP), LintId::of(¯o_use::MACRO_USE_IMPORTS), + LintId::of(&manual_ok_or::MANUAL_OK_OR), LintId::of(&map_err_ignore::MAP_ERR_IGNORE), LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS), LintId::of(&matches::MATCH_BOOL), @@ -1258,6 +1269,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF), LintId::of(&ranges::RANGE_MINUS_ONE), LintId::of(&ranges::RANGE_PLUS_ONE), + LintId::of(&ref_option_ref::REF_OPTION_REF), LintId::of(&shadow::SHADOW_UNRELATED), LintId::of(&strings::STRING_ADD_ASSIGN), LintId::of(&trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), @@ -1319,6 +1331,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&comparison_chain::COMPARISON_CHAIN), LintId::of(&copies::IFS_SAME_COND), LintId::of(&copies::IF_SAME_THEN_ELSE), + LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT), LintId::of(&derive::DERIVE_HASH_XOR_EQ), LintId::of(&derive::DERIVE_ORD_XOR_PARTIAL_ORD), LintId::of(&doc::MISSING_SAFETY_DOC), @@ -1366,6 +1379,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&int_plus_one::INT_PLUS_ONE), LintId::of(&large_const_arrays::LARGE_CONST_ARRAYS), LintId::of(&large_enum_variant::LARGE_ENUM_VARIANT), + LintId::of(&len_zero::COMPARISON_TO_EMPTY), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), @@ -1419,6 +1433,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::EXPECT_FUN_CALL), LintId::of(&methods::FILTER_NEXT), LintId::of(&methods::FLAT_MAP_IDENTITY), + LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITERATOR_STEP_BY_ZERO), LintId::of(&methods::ITER_CLONED_COLLECT), @@ -1427,6 +1442,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(&methods::MAP_COLLECT_RESULT_UNIT), LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_AS_REF_DEREF), @@ -1435,8 +1451,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(&methods::SEARCH_IS_SOME), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), + LintId::of(&methods::SINGLE_CHAR_ADD_STR), LintId::of(&methods::SINGLE_CHAR_PATTERN), - LintId::of(&methods::SINGLE_CHAR_PUSH_STR), LintId::of(&methods::SKIP_WHILE_NEXT), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::SUSPICIOUS_MAP), @@ -1577,6 +1593,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(&collapsible_if::COLLAPSIBLE_IF), LintId::of(&comparison_chain::COMPARISON_CHAIN), + LintId::of(&default::FIELD_REASSIGN_WITH_DEFAULT), LintId::of(&doc::MISSING_SAFETY_DOC), LintId::of(&doc::NEEDLESS_DOCTEST_MAIN), LintId::of(&enum_variants::ENUM_VARIANT_NAMES), @@ -1592,6 +1609,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&functions::RESULT_UNIT_ERR), LintId::of(&if_let_some_result::IF_LET_SOME_RESULT), LintId::of(&inherent_to_string::INHERENT_TO_STRING), + LintId::of(&len_zero::COMPARISON_TO_EMPTY), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), LintId::of(&literal_representation::INCONSISTENT_DIGIT_GROUPING), @@ -1615,18 +1633,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT), LintId::of(&methods::CHARS_LAST_CMP), LintId::of(&methods::CHARS_NEXT_CMP), + LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT), LintId::of(&methods::INTO_ITER_ON_REF), LintId::of(&methods::ITER_CLONED_COLLECT), LintId::of(&methods::ITER_NEXT_SLICE), LintId::of(&methods::ITER_NTH_ZERO), LintId::of(&methods::ITER_SKIP_NEXT), LintId::of(&methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(&methods::MAP_COLLECT_RESULT_UNIT), LintId::of(&methods::NEW_RET_NO_SELF), LintId::of(&methods::OK_EXPECT), LintId::of(&methods::OPTION_MAP_OR_NONE), LintId::of(&methods::RESULT_MAP_OR_INTO_OPTION), LintId::of(&methods::SHOULD_IMPLEMENT_TRAIT), - LintId::of(&methods::SINGLE_CHAR_PUSH_STR), + LintId::of(&methods::SINGLE_CHAR_ADD_STR), LintId::of(&methods::STRING_EXTEND_CHARS), LintId::of(&methods::UNNECESSARY_FOLD), LintId::of(&methods::UNNECESSARY_LAZY_EVALUATIONS), @@ -1953,6 +1973,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) { ls.register_renamed("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"); ls.register_renamed("clippy::identity_conversion", "clippy::useless_conversion"); ls.register_renamed("clippy::zero_width_space", "clippy::invisible_characters"); + ls.register_renamed("clippy::single_char_push_str", "clippy::single_char_add_str"); } // only exists to let the dogfood integration test works. diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs index c8a5a9c943135..4d737b3f49b03 100644 --- a/clippy_lints/src/lifetimes.rs +++ b/clippy_lints/src/lifetimes.rs @@ -16,7 +16,6 @@ use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, Symbol}; -use std::iter::FromIterator; declare_clippy_lint! { /// **What it does:** Checks for lifetime annotations which can be removed by @@ -214,14 +213,15 @@ fn could_use_elision<'tcx>( } if allowed_lts - .intersection(&FxHashSet::from_iter( - input_visitor + .intersection( + &input_visitor .nested_elision_site_lts .iter() .chain(output_visitor.nested_elision_site_lts.iter()) .cloned() - .filter(|v| matches!(v, RefLt::Named(_))), - )) + .filter(|v| matches!(v, RefLt::Named(_))) + .collect(), + ) .next() .is_some() { diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 5d4d3dbcff45e..32c2562ee95b4 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -619,9 +619,9 @@ impl<'tcx> LateLintPass<'tcx> for Loops { } let lhs_constructor = last_path_segment(qpath); - if method_path.ident.name == sym!(next) + if method_path.ident.name == sym::next && match_trait_method(cx, match_expr, &paths::ITERATOR) - && lhs_constructor.ident.name == sym!(Some) + && lhs_constructor.ident.name == sym::Some && (pat_args.is_empty() || !is_refutable(cx, &pat_args[0]) && !is_used_inside(cx, iter_expr, &arms[0].body) @@ -985,13 +985,13 @@ fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool { _ => false, }; - is_slice || is_type_diagnostic_item(cx, ty, sym!(vec_type)) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) + is_slice || is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) } fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { if let ExprKind::MethodCall(method, _, args, _) = expr.kind; - if method.ident.name == sym!(clone); + if method.ident.name == sym::clone; if args.len() == 1; if let Some(arg) = args.get(0); then { arg } else { expr } @@ -1355,7 +1355,7 @@ fn get_vec_push<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> Option<(& if let Some(self_expr) = args.get(0); if let Some(pushed_item) = args.get(1); // Check that the method being called is push() on a Vec - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym!(vec_type)); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::vec_type); if path.ident.name.as_str() == "push"; then { return Some((self_expr, pushed_item)) @@ -1736,7 +1736,7 @@ fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, expr: /// Checks for `for` loops over `Option`s and `Result`s. fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { let ty = cx.typeck_results().expr_ty(arg); - if is_type_diagnostic_item(cx, ty, sym!(option_type)) { + if is_type_diagnostic_item(cx, ty, sym::option_type) { span_lint_and_help( cx, FOR_LOOPS_OVER_FALLIBLES, @@ -1753,7 +1753,7 @@ fn check_arg_type(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) { snippet(cx, arg.span, "_") ), ); - } else if is_type_diagnostic_item(cx, ty, sym!(result_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::result_type) { span_lint_and_help( cx, FOR_LOOPS_OVER_FALLIBLES, @@ -2186,8 +2186,8 @@ impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> { if_chain! { // a range index op if let ExprKind::MethodCall(ref meth, _, ref args, _) = expr.kind; - if (meth.ident.name == sym!(index) && match_trait_method(self.cx, expr, &paths::INDEX)) - || (meth.ident.name == sym!(index_mut) && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); + if (meth.ident.name == sym::index && match_trait_method(self.cx, expr, &paths::INDEX)) + || (meth.ident.name == sym::index_mut && match_trait_method(self.cx, expr, &paths::INDEX_MUT)); if !self.check(&args[1], &args[0], expr); then { return } } @@ -2333,7 +2333,7 @@ fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { // will allow further borrows afterwards let ty = cx.typeck_results().expr_ty(e); is_iterable_array(ty, cx) || - is_type_diagnostic_item(cx, ty, sym!(vec_type)) || + is_type_diagnostic_item(cx, ty, sym::vec_type) || match_type(cx, ty, &paths::LINKED_LIST) || is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) || is_type_diagnostic_item(cx, ty, sym!(hashset_type)) || @@ -2890,7 +2890,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); then { let ty = cx.typeck_results().node_type(ty.hir_id); - if is_type_diagnostic_item(cx, ty, sym!(vec_type)) || + if is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) || match_type(cx, ty, &paths::BTREEMAP) || is_type_diagnostic_item(cx, ty, sym!(hashmap_type)) { diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs index 9c623821fdddc..a1450b0d5feaa 100644 --- a/clippy_lints/src/manual_non_exhaustive.rs +++ b/clippy_lints/src/manual_non_exhaustive.rs @@ -5,7 +5,7 @@ use rustc_attr as attr; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for manual implementations of the non-exhaustive pattern. @@ -83,9 +83,9 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants } fn is_doc_hidden(attr: &Attribute) -> bool { - attr.has_name(sym!(doc)) + attr.has_name(sym::doc) && match attr.meta_item_list() { - Some(l) => attr::list_contains_name(&l, sym!(hidden)), + Some(l) => attr::list_contains_name(&l, sym::hidden), None => false, } } @@ -102,7 +102,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants "this seems like a manual implementation of the non-exhaustive pattern", |diag| { if_chain! { - if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive))); + if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)); let header_span = cx.sess.source_map().span_until_char(item.span, '{'); if let Some(snippet) = snippet_opt(cx, header_span); then { @@ -154,7 +154,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: "this seems like a manual implementation of the non-exhaustive pattern", |diag| { if_chain! { - if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive))); + if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive)); let header_span = find_header_span(cx, item, data); if let Some(snippet) = snippet_opt(cx, header_span); then { diff --git a/clippy_lints/src/manual_ok_or.rs b/clippy_lints/src/manual_ok_or.rs new file mode 100644 index 0000000000000..c99d2e35b94a6 --- /dev/null +++ b/clippy_lints/src/manual_ok_or.rs @@ -0,0 +1,99 @@ +use crate::utils::{ + indent_of, is_type_diagnostic_item, match_qpath, paths, reindent_multiline, snippet_opt, span_lint_and_sugg, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{def, Expr, ExprKind, PatKind, QPath}; +use rustc_lint::LintContext; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** + /// Finds patterns that reimplement `Option::ok_or`. + /// + /// **Why is this bad?** + /// Concise code helps focusing on behavior instead of boilerplate. + /// + /// **Known problems:** None. + /// + /// **Examples:** + /// ```rust + /// let foo: Option = None; + /// foo.map_or(Err("error"), |v| Ok(v)); + /// + /// let foo: Option = None; + /// foo.map_or(Err("error"), |v| Ok(v)); + /// ``` + /// + /// Use instead: + /// ```rust + /// let foo: Option = None; + /// foo.ok_or("error"); + /// ``` + pub MANUAL_OK_OR, + pedantic, + "finds patterns that can be encoded more concisely with `Option::ok_or`" +} + +declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]); + +impl LateLintPass<'_> for ManualOkOr { + fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) { + if in_external_macro(cx.sess(), scrutinee.span) { + return; + } + + if_chain! { + if let ExprKind::MethodCall(method_segment, _, args, _) = scrutinee.kind; + if method_segment.ident.name == sym!(map_or); + if args.len() == 3; + let method_receiver = &args[0]; + let ty = cx.typeck_results().expr_ty(method_receiver); + if is_type_diagnostic_item(cx, ty, sym!(option_type)); + let or_expr = &args[1]; + if is_ok_wrapping(cx, &args[2]); + if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; + if match_qpath(err_path, &paths::RESULT_ERR); + if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span); + if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); + if let Some(indent) = indent_of(cx, scrutinee.span); + then { + let reindented_err_arg_snippet = + reindent_multiline(err_arg_snippet.into(), true, Some(indent + 4)); + span_lint_and_sugg( + cx, + MANUAL_OK_OR, + scrutinee.span, + "this pattern reimplements `Option::ok_or`", + "replace with", + format!( + "{}.ok_or({})", + method_receiver_snippet, + reindented_err_arg_snippet + ), + Applicability::MachineApplicable, + ); + } + } + } +} + +fn is_ok_wrapping(cx: &LateContext<'_>, map_expr: &Expr<'_>) -> bool { + if let ExprKind::Path(ref qpath) = map_expr.kind { + if match_qpath(qpath, &paths::RESULT_OK) { + return true; + } + } + if_chain! { + if let ExprKind::Closure(_, _, body_id, ..) = map_expr.kind; + let body = cx.tcx.hir().body(body_id); + if let PatKind::Binding(_, param_id, ..) = body.params[0].pat.kind; + if let ExprKind::Call(Expr { kind: ExprKind::Path(ok_path), .. }, &[ref ok_arg]) = body.value.kind; + if match_qpath(ok_path, &paths::RESULT_OK); + if let ExprKind::Path(QPath::Resolved(_, ok_arg_path)) = ok_arg.kind; + if let def::Res::Local(ok_arg_path_id) = ok_arg_path.res; + then { param_id == ok_arg_path_id } else { false } + } +} diff --git a/clippy_lints/src/manual_unwrap_or.rs b/clippy_lints/src/manual_unwrap_or.rs index 22aa37e41fec0..9e2c6c7f231da 100644 --- a/clippy_lints/src/manual_unwrap_or.rs +++ b/clippy_lints/src/manual_unwrap_or.rs @@ -8,6 +8,7 @@ use rustc_lint::LintContext; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** @@ -97,9 +98,9 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind; let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some(case) = if utils::is_type_diagnostic_item(cx, ty, sym!(option_type)) { + if let Some(case) = if utils::is_type_diagnostic_item(cx, ty, sym::option_type) { Some(Case::Option) - } else if utils::is_type_diagnostic_item(cx, ty, sym!(result_type)) { + } else if utils::is_type_diagnostic_item(cx, ty, sym::result_type) { Some(Case::Result) } else { None diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 6d1c2ffbfbdd2..034cd99a9be06 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests @@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { if args.len() == 2; if method.ident.as_str() == "map"; let ty = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, ty, sym!(option_type)) || match_trait_method(cx, e, &paths::ITERATOR); + if is_type_diagnostic_item(cx, ty, sym::option_type) || match_trait_method(cx, e, &paths::ITERATOR); if let hir::ExprKind::Closure(_, _, body_id, _, _) = args[1].kind; let closure_body = cx.tcx.hir().body(body_id); let closure_expr = remove_blocks(&closure_body.value); diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs index d4c2e66ff4b1e..6b782385a38d2 100644 --- a/clippy_lints/src/map_identity.rs +++ b/clippy_lints/src/map_identity.rs @@ -7,6 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function. @@ -65,8 +66,8 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a if args.len() == 2 && method.ident.as_str() == "map"; let caller_ty = cx.typeck_results().expr_ty(&args[0]); if match_trait_method(cx, expr, &paths::ITERATOR) - || is_type_diagnostic_item(cx, caller_ty, sym!(result_type)) - || is_type_diagnostic_item(cx, caller_ty, sym!(option_type)); + || is_type_diagnostic_item(cx, caller_ty, sym::result_type) + || is_type_diagnostic_item(cx, caller_ty, sym::option_type); then { Some(args) } else { diff --git a/clippy_lints/src/map_unit_fn.rs b/clippy_lints/src/map_unit_fn.rs index 076ef235b8bd8..e50d11a4d7175 100644 --- a/clippy_lints/src/map_unit_fn.rs +++ b/clippy_lints/src/map_unit_fn.rs @@ -6,6 +6,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usage of `option.map(f)` where f is a function @@ -206,9 +207,9 @@ fn lint_map_unit_fn(cx: &LateContext<'_>, stmt: &hir::Stmt<'_>, expr: &hir::Expr let var_arg = &map_args[0]; let (map_type, variant, lint) = - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym!(option_type)) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::option_type) { ("Option", "Some", OPTION_MAP_UNIT_FN) - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym!(result_type)) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(var_arg), sym::result_type) { ("Result", "Ok", RESULT_MAP_UNIT_FN) } else { return; diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs index 331b6c6c34a94..086dae9422f9b 100644 --- a/clippy_lints/src/match_on_vec_items.rs +++ b/clippy_lints/src/match_on_vec_items.rs @@ -5,6 +5,7 @@ use rustc_hir::{Expr, ExprKind, LangItem, MatchSource}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for `match vec[idx]` or `match vec[n..m]`. @@ -90,7 +91,7 @@ fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opti fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let ty = cx.typeck_results().expr_ty(expr); let ty = ty.peel_refs(); - is_type_diagnostic_item(cx, ty, sym!(vec_type)) + is_type_diagnostic_item(cx, ty, sym::vec_type) } fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs index 4bdfca1a2921d..c6dca54e2509a 100644 --- a/clippy_lints/src/matches.rs +++ b/clippy_lints/src/matches.rs @@ -22,7 +22,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::{Span, Spanned}; -use rustc_span::Symbol; +use rustc_span::{sym, Symbol}; use std::cmp::Ordering; use std::collections::hash_map::Entry; use std::collections::Bound; @@ -662,7 +662,7 @@ fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp } } else { // not a block, don't lint - return; + return; }; let ty = cx.typeck_results().expr_ty(ex); @@ -840,7 +840,7 @@ fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms fn check_wild_err_arm(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) { let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs(); - if is_type_diagnostic_item(cx, ex_ty, sym!(result_type)) { + if is_type_diagnostic_item(cx, ex_ty, sym::result_type) { for arm in arms { if let PatKind::TupleStruct(ref path, ref inner, _) = arm.pat.kind { let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); @@ -1509,6 +1509,7 @@ mod redundant_pattern_match { use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind, QPath}; use rustc_lint::LateContext; + use rustc_span::sym; pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Match(op, arms, ref match_source) = &expr.kind { @@ -1552,7 +1553,7 @@ mod redundant_pattern_match { if_chain! { if keyword == "while"; if let ExprKind::MethodCall(method_path, _, _, _) = op.kind; - if method_path.ident.name == sym!(next); + if method_path.ident.name == sym::next; if match_trait_method(cx, op, &paths::ITERATOR); then { return; diff --git a/clippy_lints/src/methods/inefficient_to_string.rs b/clippy_lints/src/methods/inefficient_to_string.rs index 5dae7efad9763..c83b6f2c32963 100644 --- a/clippy_lints/src/methods/inefficient_to_string.rs +++ b/clippy_lints/src/methods/inefficient_to_string.rs @@ -7,6 +7,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; +use rustc_span::sym; /// Checks for the `INEFFICIENT_TO_STRING` lint pub fn lint<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &hir::Expr<'_>, arg_ty: Ty<'tcx>) { @@ -50,7 +51,7 @@ fn specializes_tostring(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { return true; } - if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, ty, sym::string_type) { return true; } diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index d250bfd71e936..7186656f4e11a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -32,8 +32,7 @@ use crate::utils::{ is_copy, is_expn_of, is_type_diagnostic_item, iter_input_pats, last_path_segment, match_def_path, match_qpath, match_trait_method, match_type, match_var, method_calls, method_chain_args, paths, remove_blocks, return_ty, single_segment_path, snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, - span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, - SpanlessEq, + span_lint_and_help, span_lint_and_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq, }; declare_clippy_lint! { @@ -1291,8 +1290,8 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Warns when using `push_str` with a single-character string literal, - /// and `push` with a `char` would work fine. + /// **What it does:** Warns when using `push_str`/`insert_str` with a single-character string literal + /// where `push`/`insert` with a `char` would work fine. /// /// **Why is this bad?** It's less clear that we are pushing a single character. /// @@ -1301,16 +1300,18 @@ declare_clippy_lint! { /// **Example:** /// ```rust /// let mut string = String::new(); + /// string.insert_str(0, "R"); /// string.push_str("R"); /// ``` /// Could be written as /// ```rust /// let mut string = String::new(); + /// string.insert(0, 'R'); /// string.push('R'); /// ``` - pub SINGLE_CHAR_PUSH_STR, + pub SINGLE_CHAR_ADD_STR, style, - "`push_str()` used with a single-character string literal as parameter" + "`push_str()` or `insert_str()` used with a single-character string literal as parameter" } declare_clippy_lint! { @@ -1349,6 +1350,60 @@ declare_clippy_lint! { "using unnecessary lazy evaluation, which can be replaced with simpler eager evaluation" } +declare_clippy_lint! { + /// **What it does:** Checks for usage of `_.map(_).collect::()`. + /// + /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// (0..3).map(|t| Err(t)).collect::>(); + /// ``` + /// Use instead: + /// ```rust + /// (0..3).try_for_each(|t| Err(t)); + /// ``` + pub MAP_COLLECT_RESULT_UNIT, + style, + "using `.map(_).collect::()`, which can be replaced with `try_for_each`" +} + +declare_clippy_lint! { + /// **What it does:** Checks for `from_iter()` function calls on types that implement the `FromIterator` + /// trait. + /// + /// **Why is this bad?** It is recommended style to use collect. See + /// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html) + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// use std::iter::FromIterator; + /// + /// let five_fives = std::iter::repeat(5).take(5); + /// + /// let v = Vec::from_iter(five_fives); + /// + /// assert_eq!(v, vec![5, 5, 5, 5, 5]); + /// ``` + /// Use instead: + /// ```rust + /// let five_fives = std::iter::repeat(5).take(5); + /// + /// let v: Vec = five_fives.collect(); + /// + /// assert_eq!(v, vec![5, 5, 5, 5, 5]); + /// ``` + pub FROM_ITER_INSTEAD_OF_COLLECT, + style, + "use `.collect()` instead of `::from_iter()`" +} + declare_lint_pass!(Methods => [ UNWRAP_USED, EXPECT_USED, @@ -1370,7 +1425,7 @@ declare_lint_pass!(Methods => [ INEFFICIENT_TO_STRING, NEW_RET_NO_SELF, SINGLE_CHAR_PATTERN, - SINGLE_CHAR_PUSH_STR, + SINGLE_CHAR_ADD_STR, SEARCH_IS_SOME, FILTER_NEXT, SKIP_WHILE_NEXT, @@ -1398,6 +1453,8 @@ declare_lint_pass!(Methods => [ FILETYPE_IS_FILE, OPTION_AS_REF_DEREF, UNNECESSARY_LAZY_EVALUATIONS, + MAP_COLLECT_RESULT_UNIT, + FROM_ITER_INSTEAD_OF_COLLECT, ]); impl<'tcx> LateLintPass<'tcx> for Methods { @@ -1479,10 +1536,18 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ["unwrap_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "unwrap_or"), ["get_or_insert_with", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "get_or_insert"), ["ok_or_else", ..] => unnecessary_lazy_eval::lint(cx, expr, arg_lists[0], "ok_or"), + ["collect", "map"] => lint_map_collect(cx, expr, arg_lists[1], arg_lists[0]), _ => {}, } match expr.kind { + hir::ExprKind::Call(ref func, ref args) => { + if let hir::ExprKind::Path(path) = &func.kind { + if match_qpath(path, &["from_iter"]) { + lint_from_iter(cx, expr, args); + } + } + }, hir::ExprKind::MethodCall(ref method_call, ref method_span, ref args, _) => { lint_or_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); lint_expect_fun_call(cx, expr, *method_span, &method_call.ident.as_str(), args); @@ -1499,6 +1564,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { if match_def_path(cx, fn_def_id, &paths::PUSH_STR) { lint_single_char_push_string(cx, expr, args); + } else if match_def_path(cx, fn_def_id, &paths::INSERT_STR) { + lint_single_char_insert_string(cx, expr, args); } } @@ -1655,7 +1722,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if_chain! { if !in_external_macro(cx.tcx.sess, item.span); - if item.ident.name == sym!(new); + if item.ident.name == sym::new; if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.hir_id); let self_ty = TraitRef::identity(cx.tcx, item.hir_id.owner.to_def_id()).self_ty(); @@ -1712,7 +1779,7 @@ fn lint_or_fun_call<'tcx>( "try this", format!( "{}.unwrap_or_default()", - snippet_with_applicability(cx, self_expr.span, "_", &mut applicability) + snippet_with_applicability(cx, self_expr.span, "..", &mut applicability) ), applicability, ); @@ -1745,7 +1812,7 @@ fn lint_or_fun_call<'tcx>( _ => (), } - if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { + if is_type_diagnostic_item(cx, ty, sym::vec_type) { return; } } @@ -1842,11 +1909,11 @@ fn lint_expect_fun_call( hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, hir::ExprKind::MethodCall(method_name, _, call_args, _) => { if call_args.len() == 1 - && (method_name.ident.name == sym!(as_str) || method_name.ident.name == sym!(as_ref)) + && (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref)) && { let arg_type = cx.typeck_results().expr_ty(&call_args[0]); let base_type = arg_type.peel_refs(); - *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym!(string_type)) + *base_type.kind() == ty::Str || is_type_diagnostic_item(cx, base_type, sym::string_type) } { &call_args[0] @@ -1864,7 +1931,7 @@ fn lint_expect_fun_call( // converted to string. fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool { let arg_ty = cx.typeck_results().expr_ty(arg); - if is_type_diagnostic_item(cx, arg_ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, arg_ty, sym::string_type) { return false; } if let ty::Ref(_, ty, ..) = arg_ty.kind() { @@ -1951,9 +2018,9 @@ fn lint_expect_fun_call( } let receiver_type = cx.typeck_results().expr_ty_adjusted(&args[0]); - let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym!(option_type)) { + let closure_args = if is_type_diagnostic_item(cx, receiver_type, sym::option_type) { "||" - } else if is_type_diagnostic_item(cx, receiver_type, sym!(result_type)) { + } else if is_type_diagnostic_item(cx, receiver_type, sym::result_type) { "|_|" } else { return; @@ -2119,7 +2186,7 @@ fn lint_clone_on_ref_ptr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir:: return; }; - let snippet = snippet_with_macro_callsite(cx, arg.span, "_"); + let snippet = snippet_with_macro_callsite(cx, arg.span, ".."); span_lint_and_sugg( cx, @@ -2140,7 +2207,7 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E let self_ty = cx.typeck_results().expr_ty(target).peel_refs(); let ref_str = if *self_ty.kind() == ty::Str { "" - } else if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { + } else if is_type_diagnostic_item(cx, self_ty, sym::string_type) { "&" } else { return; @@ -2155,9 +2222,9 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E "try this", format!( "{}.push_str({}{})", - snippet_with_applicability(cx, args[0].span, "_", &mut applicability), + snippet_with_applicability(cx, args[0].span, "..", &mut applicability), ref_str, - snippet_with_applicability(cx, target.span, "_", &mut applicability) + snippet_with_applicability(cx, target.span, "..", &mut applicability) ), applicability, ); @@ -2166,14 +2233,14 @@ fn lint_string_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::E fn lint_extend(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); - if is_type_diagnostic_item(cx, obj_ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, obj_ty, sym::string_type) { lint_string_extend(cx, expr, args); } } fn lint_iter_cloned_collect<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) { if_chain! { - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym!(vec_type)); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::vec_type); if let Some(slice) = derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])); if let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite()); @@ -2326,7 +2393,7 @@ fn lint_iter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_ ); } } - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym!(vec_type)) + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(caller_expr), sym::vec_type) || matches!( &cx.typeck_results().expr_ty(caller_expr).peel_refs().kind(), ty::Array(_, _) @@ -2359,7 +2426,7 @@ fn lint_iter_nth<'tcx>( let mut_str = if is_mut { "_mut" } else { "" }; let caller_type = if derefs_to_slice(cx, &iter_args[0], cx.typeck_results().expr_ty(&iter_args[0])).is_some() { "slice" - } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vec_type)) { + } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym::vec_type) { "Vec" } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&iter_args[0]), sym!(vecdeque_type)) { "VecDeque" @@ -2404,7 +2471,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: let mut applicability = Applicability::MachineApplicable; let expr_ty = cx.typeck_results().expr_ty(&get_args[0]); let get_args_str = if get_args.len() > 1 { - snippet_with_applicability(cx, get_args[1].span, "_", &mut applicability) + snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability) } else { return; // not linting on a .get().unwrap() chain or variant }; @@ -2412,7 +2479,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() { needs_ref = get_args_str.parse::().is_ok(); "slice" - } else if is_type_diagnostic_item(cx, expr_ty, sym!(vec_type)) { + } else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) { needs_ref = get_args_str.parse::().is_ok(); "Vec" } else if is_type_diagnostic_item(cx, expr_ty, sym!(vecdeque_type)) { @@ -2464,7 +2531,7 @@ fn lint_get_unwrap<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: format!( "{}{}[{}]", borrow_str, - snippet_with_applicability(cx, get_args[0].span, "_", &mut applicability), + snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability), get_args_str ), applicability, @@ -2480,7 +2547,7 @@ fn lint_iter_skip_next(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[ cx, ITER_SKIP_NEXT, expr.span.trim_start(caller.span).unwrap(), - "called `skip(x).next()` on an iterator", + "called `skip(..).next()` on an iterator", "use `nth` instead", hint, Applicability::MachineApplicable, @@ -2498,7 +2565,7 @@ fn derefs_to_slice<'tcx>( match ty.kind() { ty::Slice(_) => true, ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()), - ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym!(vec_type)), + ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::vec_type), ty::Array(_, size) => size .try_eval_usize(cx.tcx, cx.param_env) .map_or(false, |size| size < 32), @@ -2508,7 +2575,7 @@ fn derefs_to_slice<'tcx>( } if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = expr.kind { - if path.ident.name == sym!(iter) && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { + if path.ident.name == sym::iter && may_slice(cx, cx.typeck_results().expr_ty(&args[0])) { Some(&args[0]) } else { None @@ -2533,9 +2600,9 @@ fn derefs_to_slice<'tcx>( fn lint_unwrap(cx: &LateContext<'_>, expr: &hir::Expr<'_>, unwrap_args: &[hir::Expr<'_>]) { let obj_ty = cx.typeck_results().expr_ty(&unwrap_args[0]).peel_refs(); - let mess = if is_type_diagnostic_item(cx, obj_ty, sym!(option_type)) { + let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) { Some((UNWRAP_USED, "an Option", "None")) - } else if is_type_diagnostic_item(cx, obj_ty, sym!(result_type)) { + } else if is_type_diagnostic_item(cx, obj_ty, sym::result_type) { Some((UNWRAP_USED, "a Result", "Err")) } else { None @@ -2585,7 +2652,7 @@ fn lint_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::E fn lint_ok_expect(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ok_args: &[hir::Expr<'_>]) { if_chain! { // lint if the caller of `ok()` is a `Result` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym!(result_type)); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&ok_args[0]), sym::result_type); let result_type = cx.typeck_results().expr_ty(&ok_args[0]); if let Some(error_type) = get_error_type(cx, result_type); if has_debug_impl(error_type, cx); @@ -2615,7 +2682,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map _ => map_closure_ty.fn_sig(cx.tcx), }; let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&map_closure_sig.output()); - is_type_diagnostic_item(cx, map_closure_return_ty, sym!(option_type)) + is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type) }, _ => false, }; @@ -2641,7 +2708,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map } // lint if caller of `.map().flatten()` is an Option - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) { let func_snippet = snippet(cx, map_args[1].span, ".."); let hint = format!(".and_then({})", func_snippet); span_lint_and_sugg( @@ -2665,8 +2732,8 @@ fn lint_map_unwrap_or_else<'tcx>( unwrap_args: &'tcx [hir::Expr<'_>], ) -> bool { // lint if the caller of `map()` is an `Option` - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(result_type)); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type); if is_option || is_result { // Don't make a suggestion that may fail to compile due to mutably borrowing @@ -2683,11 +2750,11 @@ fn lint_map_unwrap_or_else<'tcx>( // lint message let msg = if is_option { - "called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling \ - `map_or_else(g, f)` instead" + "called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling \ + `map_or_else(, )` instead" } else { - "called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling \ - `.map_or_else(g, f)` instead" + "called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling \ + `.map_or_else(, )` instead" }; // get snippets for args to map() and unwrap_or_else() let map_snippet = snippet(cx, map_args[1].span, ".."); @@ -2697,16 +2764,15 @@ fn lint_map_unwrap_or_else<'tcx>( let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1; let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt(); if same_span && !multiline { - span_lint_and_note( + let var_snippet = snippet(cx, map_args[0].span, ".."); + span_lint_and_sugg( cx, MAP_UNWRAP_OR, expr.span, msg, - None, - &format!( - "replace `map({0}).unwrap_or_else({1})` with `map_or_else({1}, {0})`", - map_snippet, unwrap_snippet, - ), + "try this", + format!("{}.map_or_else({}, {})", var_snippet, unwrap_snippet, map_snippet), + Applicability::MachineApplicable, ); return true; } else if same_span && multiline { @@ -2720,8 +2786,8 @@ fn lint_map_unwrap_or_else<'tcx>( /// lint use of `_.map_or(None, _)` for `Option`s and `Result`s fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map_or_args: &'tcx [hir::Expr<'_>]) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym!(result_type)); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_or_args[0]), sym::result_type); // There are two variants of this `map_or` lint: // (1) using `map_or` as an adapter from `Result` to `Option` @@ -2753,8 +2819,8 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map if is_option { let self_snippet = snippet(cx, map_or_args[0].span, ".."); let func_snippet = snippet(cx, map_or_args[2].span, ".."); - let msg = "called `map_or(None, f)` on an `Option` value. This can be done more directly by calling \ - `and_then(f)` instead"; + let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \ + `and_then(..)` instead"; ( OPTION_MAP_OR_NONE, msg, @@ -2792,18 +2858,20 @@ fn lint_map_or_none<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map fn lint_filter_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { // lint if caller of `.filter().next()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling \ - `.find(p)` instead."; + let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ + `.find(..)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { + let iter_snippet = snippet(cx, filter_args[0].span, ".."); // add note if not multi-line - span_lint_and_note( + span_lint_and_sugg( cx, FILTER_NEXT, expr.span, msg, - None, - &format!("replace `filter({0}).next()` with `find({0})`", filter_snippet), + "try this", + format!("{}.find({})", iter_snippet, filter_snippet), + Applicability::MachineApplicable, ); } else { span_lint(cx, FILTER_NEXT, expr.span, msg); @@ -2823,9 +2891,9 @@ fn lint_skip_while_next<'tcx>( cx, SKIP_WHILE_NEXT, expr.span, - "called `skip_while(p).next()` on an `Iterator`", + "called `skip_while(

).next()` on an `Iterator`", None, - "this is more succinctly expressed by calling `.find(!p)` instead", + "this is more succinctly expressed by calling `.find(!

)` instead", ); } } @@ -2839,7 +2907,7 @@ fn lint_filter_map<'tcx>( ) { // lint if caller of `.filter().map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(p).map(q)` on an `Iterator`"; + let msg = "called `filter(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.filter_map(..)` instead"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); } @@ -2848,17 +2916,19 @@ fn lint_filter_map<'tcx>( /// lint use of `filter_map().next()` for `Iterators` fn lint_filter_map_next<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) { if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling \ - `.find_map(p)` instead."; + let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \ + `.find_map(..)` instead."; let filter_snippet = snippet(cx, filter_args[1].span, ".."); if filter_snippet.lines().count() <= 1 { - span_lint_and_note( + let iter_snippet = snippet(cx, filter_args[0].span, ".."); + span_lint_and_sugg( cx, FILTER_MAP_NEXT, expr.span, msg, - None, - &format!("replace `filter_map({0}).next()` with `find_map({0})`", filter_snippet), + "try this", + format!("{}.find_map({})", iter_snippet, filter_snippet), + Applicability::MachineApplicable, ); } else { span_lint(cx, FILTER_MAP_NEXT, expr.span, msg); @@ -2875,7 +2945,7 @@ fn lint_find_map<'tcx>( ) { // lint if caller of `.filter().map()` is an Iterator if match_trait_method(cx, &map_args[0], &paths::ITERATOR) { - let msg = "called `find(p).map(q)` on an `Iterator`"; + let msg = "called `find(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.find_map(..)` instead"; span_lint_and_help(cx, FIND_MAP, expr.span, msg, None, hint); } @@ -2890,7 +2960,7 @@ fn lint_filter_map_map<'tcx>( ) { // lint if caller of `.filter().map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter_map(p).map(q)` on an `Iterator`"; + let msg = "called `filter_map(..).map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by only calling `.filter_map(..)` instead"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); } @@ -2905,7 +2975,7 @@ fn lint_filter_flat_map<'tcx>( ) { // lint if caller of `.filter().flat_map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter(p).flat_map(q)` on an `Iterator`"; + let msg = "called `filter(..).flat_map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); @@ -2921,7 +2991,7 @@ fn lint_filter_map_flat_map<'tcx>( ) { // lint if caller of `.filter_map().flat_map()` is an Iterator if match_trait_method(cx, expr, &paths::ITERATOR) { - let msg = "called `filter_map(p).flat_map(q)` on an `Iterator`"; + let msg = "called `filter_map(..).flat_map(..)` on an `Iterator`"; let hint = "this is more succinctly expressed by calling `.flat_map(..)` \ and filtering by returning `iter::empty()`"; span_lint_and_help(cx, FILTER_MAP, expr.span, msg, None, hint); @@ -3075,7 +3145,7 @@ fn lint_chars_cmp( if arg_char.len() == 1; if let hir::ExprKind::Path(ref qpath) = fun.kind; if let Some(segment) = single_segment_path(qpath); - if segment.ident.name == sym!(Some); + if segment.ident.name == sym::Some; then { let mut applicability = Applicability::MachineApplicable; let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs(); @@ -3092,9 +3162,9 @@ fn lint_chars_cmp( "like this", format!("{}{}.{}({})", if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability), + snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), suggest, - snippet_with_applicability(cx, arg_char[0].span, "_", &mut applicability)), + snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)), applicability, ); @@ -3141,7 +3211,7 @@ fn lint_chars_cmp_with_unwrap<'tcx>( "like this", format!("{}{}.{}('{}')", if info.eq { "" } else { "!" }, - snippet_with_applicability(cx, args[0][0].span, "_", &mut applicability), + snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability), suggest, c), applicability, @@ -3177,7 +3247,7 @@ fn get_hint_if_single_char_arg( if let hir::ExprKind::Lit(lit) = &arg.kind; if let ast::LitKind::Str(r, style) = lit.node; let string = r.as_str(); - if string.len() == 1; + if string.chars().count() == 1; then { let snip = snippet_with_applicability(cx, arg.span, &string, applicability); let ch = if let ast::StrStyle::Raw(nhash) = style { @@ -3216,11 +3286,12 @@ fn lint_single_char_pattern(cx: &LateContext<'_>, _expr: &hir::Expr<'_>, arg: &h fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { let mut applicability = Applicability::MachineApplicable; if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) { - let base_string_snippet = snippet_with_applicability(cx, args[0].span, "_", &mut applicability); + let base_string_snippet = + snippet_with_applicability(cx, args[0].span.source_callsite(), "..", &mut applicability); let sugg = format!("{}.push({})", base_string_snippet, extension_string); span_lint_and_sugg( cx, - SINGLE_CHAR_PUSH_STR, + SINGLE_CHAR_ADD_STR, expr.span, "calling `push_str()` using a single-character string literal", "consider using `push` with a character literal", @@ -3230,6 +3301,26 @@ fn lint_single_char_push_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args } } +/// lint for length-1 `str`s as argument for `insert_str` +fn lint_single_char_insert_string(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let mut applicability = Applicability::MachineApplicable; + if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[2], &mut applicability) { + let base_string_snippet = + snippet_with_applicability(cx, args[0].span.source_callsite(), "_", &mut applicability); + let pos_arg = snippet_with_applicability(cx, args[1].span, "..", &mut applicability); + let sugg = format!("{}.insert({}, {})", base_string_snippet, pos_arg, extension_string); + span_lint_and_sugg( + cx, + SINGLE_CHAR_ADD_STR, + expr.span, + "calling `insert_str()` using a single-character string literal", + "consider using `insert` with a character literal", + sugg, + applicability, + ); + } +} + /// Checks for the `USELESS_ASREF` lint. fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_ref_args: &[hir::Expr<'_>]) { // when we get here, we've already checked that the call name is "as_ref" or "as_mut" @@ -3259,7 +3350,7 @@ fn lint_asref(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, as_re expr.span, &format!("this call to `{}` does nothing", call_name), "try this", - snippet_with_applicability(cx, recvr.span, "_", &mut applicability).to_string(), + snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), applicability, ); } @@ -3350,7 +3441,7 @@ fn lint_option_as_ref_deref<'tcx>( let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]); - if !is_type_diagnostic_item(cx, option_ty, sym!(option_type)) { + if !is_type_diagnostic_item(cx, option_ty, sym::option_type) { return; } @@ -3445,10 +3536,46 @@ fn lint_option_as_ref_deref<'tcx>( } } +fn lint_map_collect( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + map_args: &[hir::Expr<'_>], + collect_args: &[hir::Expr<'_>], +) { + if_chain! { + // called on Iterator + if let [map_expr] = collect_args; + if match_trait_method(cx, map_expr, &paths::ITERATOR); + // return of collect `Result<(),_>` + let collect_ret_ty = cx.typeck_results().expr_ty(expr); + if is_type_diagnostic_item(cx, collect_ret_ty, sym::result_type); + if let ty::Adt(_, substs) = collect_ret_ty.kind(); + if let Some(result_t) = substs.types().next(); + if result_t.is_unit(); + // get parts for snippet + if let [iter, map_fn] = map_args; + then { + span_lint_and_sugg( + cx, + MAP_COLLECT_RESULT_UNIT, + expr.span, + "`.map().collect()` can be replaced with `.try_for_each()`", + "try this", + format!( + "{}.try_for_each({})", + snippet(cx, iter.span, ".."), + snippet(cx, map_fn.span, "..") + ), + Applicability::MachineApplicable, + ); + } + } +} + /// Given a `Result` type, return its error type (`E`). fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option> { match ty.kind() { - ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym!(result_type)) => substs.types().nth(1), + ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::result_type) => substs.types().nth(1), _ => None, } } @@ -3770,6 +3897,28 @@ fn lint_filetype_is_file(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir span_lint_and_help(cx, FILETYPE_IS_FILE, span, &lint_msg, None, &help_msg); } +fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) { + let ty = cx.typeck_results().expr_ty(expr); + let arg_ty = cx.typeck_results().expr_ty(&args[0]); + + let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); + let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap(); + + if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) { + // `expr` implements `FromIterator` trait + let iter_expr = snippet(cx, args[0].span, ".."); + span_lint_and_sugg( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "usage of `FromIterator::from_iter`", + "use `.collect()` instead of `::from_iter()`", + format!("{}.collect()", iter_expr), + Applicability::MaybeIncorrect, + ); + } +} + fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool { expected.constness == actual.constness && expected.unsafety == actual.unsafety diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs index 95fa28e1c0f75..7763fd5f113fa 100644 --- a/clippy_lints/src/methods/option_map_unwrap_or.rs +++ b/clippy_lints/src/methods/option_map_unwrap_or.rs @@ -7,7 +7,7 @@ use rustc_hir::{self, HirId, Path}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; use rustc_span::source_map::Span; -use rustc_span::symbol::Symbol; +use rustc_span::{sym, Symbol}; use super::MAP_UNWRAP_OR; @@ -20,7 +20,7 @@ pub(super) fn lint<'tcx>( map_span: Span, ) { // lint if the caller of `map()` is an `Option` - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym!(option_type)) { + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type) { if !is_copy(cx, cx.typeck_results().expr_ty(&unwrap_args[1])) { // Do not lint if the `map` argument uses identifiers in the `map` // argument that are also used in the `unwrap_or` argument @@ -53,15 +53,15 @@ pub(super) fn lint<'tcx>( // lint message // comparing the snippet from source to raw text ("None") below is safe // because we already have checked the type. - let arg = if unwrap_snippet == "None" { "None" } else { "a" }; + let arg = if unwrap_snippet == "None" { "None" } else { "" }; let unwrap_snippet_none = unwrap_snippet == "None"; let suggest = if unwrap_snippet_none { - "and_then(f)" + "and_then()" } else { - "map_or(a, f)" + "map_or(, )" }; let msg = &format!( - "called `map(f).unwrap_or({})` on an `Option` value. \ + "called `map().unwrap_or({})` on an `Option` value. \ This can be done more directly by calling `{}` instead", arg, suggest ); diff --git a/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/clippy_lints/src/methods/unnecessary_lazy_eval.rs index 08b3eab9b7cdf..cde89983a2656 100644 --- a/clippy_lints/src/methods/unnecessary_lazy_eval.rs +++ b/clippy_lints/src/methods/unnecessary_lazy_eval.rs @@ -3,6 +3,7 @@ use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::LateContext; +use rustc_span::sym; use super::UNNECESSARY_LAZY_EVALUATIONS; @@ -14,8 +15,8 @@ pub(super) fn lint<'tcx>( args: &'tcx [hir::Expr<'_>], simplify_using: &str, ) { - let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(option_type)); - let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym!(result_type)); + let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::option_type); + let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]), sym::result_type); if is_option || is_result { if let hir::ExprKind::Closure(_, _, eid, _, _) = args[1].kind { diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs index 909e79f661a6d..308e92057b751 100644 --- a/clippy_lints/src/misc.rs +++ b/clippy_lints/src/misc.rs @@ -7,6 +7,7 @@ use rustc_hir::{ StmtKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::DesugaringKind; @@ -271,13 +272,16 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { k: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Body<'_>, - _: Span, + span: Span, _: HirId, ) { if let FnKind::Closure(_) = k { // Does not apply to closures return; } + if in_external_macro(cx.tcx.sess, span) { + return; + } for arg in iter_input_pats(decl, body) { if let PatKind::Binding(BindingAnnotation::Ref | BindingAnnotation::RefMut, ..) = arg.pat.kind { span_lint( @@ -293,13 +297,16 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if_chain! { + if !in_external_macro(cx.tcx.sess, stmt.span); if let StmtKind::Local(ref local) = stmt.kind; if let PatKind::Binding(an, .., name, None) = local.pat.kind; if let Some(ref init) = local.init; if !higher::is_from_for_desugar(local); then { if an == BindingAnnotation::Ref || an == BindingAnnotation::RefMut { - let sugg_init = if init.span.from_expansion() { + // use the macro callsite when the init span (but not the whole local span) + // comes from an expansion like `vec![1, 2, 3]` in `let ref _ = vec![1, 2, 3];` + let sugg_init = if init.span.from_expansion() && !local.span.from_expansion() { Sugg::hir_with_macro_callsite(cx, init, "..") } else { Sugg::hir(cx, init, "..") @@ -310,7 +317,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { ("", sugg_init.addr()) }; let tyopt = if let Some(ref ty) = local.ty { - format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "_")) + format!(": &{mutopt}{ty}", mutopt=mutopt, ty=snippet(cx, ty.span, "..")) } else { String::new() }; @@ -326,7 +333,7 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { "try", format!( "let {name}{tyopt} = {initref};", - name=snippet(cx, name.span, "_"), + name=snippet(cx, name.span, ".."), tyopt=tyopt, initref=initref, ), diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs index 813f9c4394819..009e3d8937e02 100644 --- a/clippy_lints/src/missing_doc.rs +++ b/clippy_lints/src/missing_doc.rs @@ -14,6 +14,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Warns if there is missing doc for any documentable item @@ -105,10 +106,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn enter_lint_attrs(&mut self, _: &LateContext<'tcx>, attrs: &'tcx [ast::Attribute]) { let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| { - attr.has_name(sym!(doc)) + attr.has_name(sym::doc) && match attr.meta_item_list() { None => false, - Some(l) => attr::list_contains_name(&l[..], sym!(hidden)), + Some(l) => attr::list_contains_name(&l[..], sym::hidden), } }); self.doc_hidden_stack.push(doc_hidden); @@ -128,7 +129,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { hir::ItemKind::Enum(..) => "an enum", hir::ItemKind::Fn(..) => { // ignore main() - if it.ident.name == sym!(main) { + if it.ident.name == sym::main { let def_id = it.hir_id.owner; let def_key = cx.tcx.hir().def_key(def_id); if def_key.parent == Some(hir::def_id::CRATE_DEF_INDEX) { diff --git a/clippy_lints/src/missing_inline.rs b/clippy_lints/src/missing_inline.rs index 3eae45b2819d8..53abe6086ea41 100644 --- a/clippy_lints/src/missing_inline.rs +++ b/clippy_lints/src/missing_inline.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_lint::{self, LateContext, LateLintPass, LintContext}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** it lints if an exported function, method, trait method with default impl, @@ -57,7 +58,7 @@ declare_clippy_lint! { } fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[ast::Attribute], sp: Span, desc: &'static str) { - let has_inline = attrs.iter().any(|a| a.has_name(sym!(inline))); + let has_inline = attrs.iter().any(|a| a.has_name(sym::inline)); if !has_inline { span_lint( cx, diff --git a/clippy_lints/src/needless_borrow.rs b/clippy_lints/src/needless_borrow.rs index b71d5496a37a3..405c21d608d97 100644 --- a/clippy_lints/src/needless_borrow.rs +++ b/clippy_lints/src/needless_borrow.rs @@ -10,6 +10,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for address of operations (`&`) that are going to @@ -112,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { } fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if item.attrs.iter().any(|a| a.has_name(sym!(automatically_derived))) { + if item.attrs.iter().any(|a| a.has_name(sym::automatically_derived)) { debug_assert!(self.derived_item.is_none()); self.derived_item = Some(item.hir_id); } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 2423eb4e6e394..1d0e230c6a777 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, TypeFoldable}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::can_type_implement_copy; @@ -204,12 +204,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { let deref_span = spans_need_deref.get(&canonical_id); if_chain! { - if is_type_diagnostic_item(cx, ty, sym!(vec_type)); + if is_type_diagnostic_item(cx, ty, sym::vec_type); if let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]); if let TyKind::Path(QPath::Resolved(_, ref path)) = input.kind; if let Some(elem_ty) = path.segments.iter() - .find(|seg| seg.ident.name == sym!(Vec)) + .find(|seg| seg.ident.name == sym::Vec) .and_then(|ps| ps.args.as_ref()) .map(|params| params.args.iter().find_map(|arg| match arg { GenericArg::Type(ty) => Some(ty), @@ -243,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { } } - if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + if is_type_diagnostic_item(cx, ty, sym::string_type) { if let Some(clone_spans) = get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) { diag.span_suggestion( @@ -302,7 +302,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { /// Functions marked with these attributes must have the exact signature. fn requires_exact_signature(attrs: &[Attribute]) -> bool { attrs.iter().any(|attr| { - [sym!(proc_macro), sym!(proc_macro_attribute), sym!(proc_macro_derive)] + [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] .iter() .any(|&allow| attr.has_name(allow)) }) diff --git a/clippy_lints/src/new_without_default.rs b/clippy_lints/src/new_without_default.rs index 28d1322e94626..68fdd0eb269ef 100644 --- a/clippy_lints/src/new_without_default.rs +++ b/clippy_lints/src/new_without_default.rs @@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{Ty, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for types with a `fn new() -> Self` method and no @@ -91,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { // impl of `Default` return; } - if sig.decl.inputs.is_empty() && name == sym!(new) && cx.access_levels.is_reachable(id) { + if sig.decl.inputs.is_empty() && name == sym::new && cx.access_levels.is_reachable(id) { let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id)); let self_ty = cx.tcx.type_of(self_def_id); if_chain! { diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 603440c0f8376..485888fa9444f 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -7,6 +7,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; +use rustc_span::sym; use rustc_span::symbol::{Ident, Symbol}; use std::cmp::Ordering; @@ -384,7 +385,7 @@ impl EarlyLintPass for NonExpressiveNames { } fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) { - if !attrs.iter().any(|attr| attr.has_name(sym!(test))) { + if !attrs.iter().any(|attr| attr.has_name(sym::test)) { let mut visitor = SimilarNamesLocalVisitor { names: Vec::new(), cx, diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index eb7624b25a3c9..681dbce97697e 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -8,6 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** @@ -66,7 +67,7 @@ declare_lint_pass!(OptionIfLetElse => [OPTION_IF_LET_ELSE]); fn is_result_ok(cx: &LateContext<'_>, expr: &'_ Expr<'_>) -> bool { if let ExprKind::MethodCall(ref path, _, &[ref receiver], _) = &expr.kind { path.ident.name.to_ident_string() == "ok" - && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym!(result_type)) + && is_type_diagnostic_item(cx, &cx.typeck_results().expr_ty(&receiver), sym::result_type) } else { false } diff --git a/clippy_lints/src/panic_in_result_fn.rs b/clippy_lints/src/panic_in_result_fn.rs index 4077aba6ef17d..72dfccc1089e9 100644 --- a/clippy_lints/src/panic_in_result_fn.rs +++ b/clippy_lints/src/panic_in_result_fn.rs @@ -5,7 +5,7 @@ use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!` or `unreachable!` in a function of type result. @@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { hir_id: hir::HirId, ) { if !matches!(fn_kind, FnKind::Closure(_)) - && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) + && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) { lint_impl_body(cx, span, body); } diff --git a/clippy_lints/src/partialeq_ne_impl.rs b/clippy_lints/src/partialeq_ne_impl.rs index 19d355e64ca86..ceecc8dbc06fc 100644 --- a/clippy_lints/src/partialeq_ne_impl.rs +++ b/clippy_lints/src/partialeq_ne_impl.rs @@ -3,6 +3,7 @@ use if_chain::if_chain; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for manual re-implementations of `PartialEq::ne`. @@ -39,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { if trait_ref.path.res.def_id() == eq_trait; then { for impl_item in impl_items { - if impl_item.ident.name == sym!(ne) { + if impl_item.ident.name == sym::ne { span_lint_hir( cx, PARTIALEQ_NE_IMPL, diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 28816c3076ddf..030650c3256c0 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -10,7 +10,7 @@ use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, ItemKind, MutTy, Mutabil use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::Span; +use rustc_span::{sym, Span}; use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; use rustc_target::spec::Target; @@ -230,8 +230,8 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { } for a in attrs { if let Some(meta_items) = a.meta_item_list() { - if a.has_name(sym!(proc_macro_derive)) - || (a.has_name(sym!(inline)) && attr::list_contains_name(&meta_items, sym!(always))) + if a.has_name(sym::proc_macro_derive) + || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always)) { return; } diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs index 6b1c848a9467b..dcb643a28aebc 100644 --- a/clippy_lints/src/ptr.rs +++ b/clippy_lints/src/ptr.rs @@ -15,7 +15,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use rustc_span::MultiSpan; +use rustc_span::{sym, MultiSpan}; use std::borrow::Cow; declare_clippy_lint! { @@ -181,7 +181,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: } if let ty::Ref(_, ty, Mutability::Not) = ty.kind() { - if is_type_diagnostic_item(cx, ty, sym!(vec_type)) { + if is_type_diagnostic_item(cx, ty, sym::vec_type) { let mut ty_snippet = None; if_chain! { if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind; @@ -225,7 +225,7 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: }, ); } - } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::string_type) { if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) { span_lint_and_then( cx, diff --git a/clippy_lints/src/ptr_offset_with_cast.rs b/clippy_lints/src/ptr_offset_with_cast.rs index 0a2d1b5fbe6ac..e0996804a5934 100644 --- a/clippy_lints/src/ptr_offset_with_cast.rs +++ b/clippy_lints/src/ptr_offset_with_cast.rs @@ -3,6 +3,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use std::fmt; declare_clippy_lint! { @@ -92,7 +93,7 @@ fn expr_as_ptr_offset_call<'tcx>( ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> { if let ExprKind::MethodCall(ref path_segment, _, ref args, _) = expr.kind { if is_expr_ty_raw_ptr(cx, &args[0]) { - if path_segment.ident.name == sym!(offset) { + if path_segment.ident.name == sym::offset { return Some((&args[0], &args[1], Method::Offset)); } if path_segment.ident.name == sym!(wrapping_offset) { diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index dbc676ae22408..d9b280b7a8597 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -4,6 +4,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{def, BindingAnnotation, Block, Expr, ExprKind, MatchSource, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use crate::utils::sugg::Sugg; use crate::utils::{ @@ -143,7 +144,7 @@ impl QuestionMark { fn is_option(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { let expr_ty = cx.typeck_results().expr_ty(expression); - is_type_diagnostic_item(cx, expr_ty, sym!(option_type)) + is_type_diagnostic_item(cx, expr_ty, sym::option_type) } fn expression_returns_none(cx: &LateContext<'_>, expression: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index de54711d8511b..79e9a56af9a19 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -7,6 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{Span, Spanned}; +use rustc_span::sym; use rustc_span::symbol::Ident; use std::cmp::Ordering; @@ -304,7 +305,7 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: if_chain! { // `.iter()` call if let ExprKind::MethodCall(ref iter_path, _, ref iter_args, _) = *iter; - if iter_path.ident.name == sym!(iter); + if iter_path.ident.name == sym::iter; // range expression in `.zip()` call: `0..x.len()` if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::range(zip_arg); if is_integer_const(cx, start, 0); diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index ae3b0a037542a..b4a9804fb25a5 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -17,6 +17,7 @@ use rustc_middle::ty::{self, fold::TypeVisitor, Ty}; use rustc_mir::dataflow::{Analysis, AnalysisDomain, GenKill, GenKillAnalysis, ResultsCursor}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::{BytePos, Span}; +use rustc_span::sym; use std::convert::TryFrom; use std::ops::ControlFlow; @@ -115,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone { let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD) || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD) || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD) - && is_type_diagnostic_item(cx, arg_ty, sym!(string_type))); + && is_type_diagnostic_item(cx, arg_ty, sym::string_type)); let from_deref = !from_borrow && (match_def_path(cx, fn_def_id, &paths::PATH_TO_PATH_BUF) @@ -518,7 +519,10 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { self.possible_borrower.add(borrowed.local, lhs); }, other => { - if ContainsRegion.visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty).is_continue() { + if ContainsRegion + .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty) + .is_continue() + { return; } rvalue_locals(other, |rhs| { diff --git a/clippy_lints/src/ref_option_ref.rs b/clippy_lints/src/ref_option_ref.rs new file mode 100644 index 0000000000000..a914a77d48b4e --- /dev/null +++ b/clippy_lints/src/ref_option_ref.rs @@ -0,0 +1,66 @@ +use crate::utils::{last_path_segment, snippet, span_lint_and_sugg}; +use rustc_hir::{GenericArg, Mutability, Ty, TyKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +use if_chain::if_chain; +use rustc_errors::Applicability; + +declare_clippy_lint! { + /// **What it does:** Checks for usage of `&Option<&T>`. + /// + /// **Why is this bad?** Since `&` is Copy, it's useless to have a + /// reference on `Option<&T>`. + /// + /// **Known problems:** It may be irrevelent to use this lint on + /// public API code as it will make a breaking change to apply it. + /// + /// **Example:** + /// + /// ```rust,ignore + /// let x: &Option<&u32> = &Some(&0u32); + /// ``` + /// Use instead: + /// ```rust,ignore + /// let x: Option<&u32> = Some(&0u32); + /// ``` + pub REF_OPTION_REF, + pedantic, + "use `Option<&T>` instead of `&Option<&T>`" +} + +declare_lint_pass!(RefOptionRef => [REF_OPTION_REF]); + +impl<'tcx> LateLintPass<'tcx> for RefOptionRef { + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { + if_chain! { + if let TyKind::Rptr(_, ref mut_ty) = ty.kind; + if mut_ty.mutbl == Mutability::Not; + if let TyKind::Path(ref qpath) = &mut_ty.ty.kind; + let last = last_path_segment(qpath); + if let Some(res) = last.res; + if let Some(def_id) = res.opt_def_id(); + + if cx.tcx.is_diagnostic_item(sym!(option_type), def_id); + if let Some(ref params) = last_path_segment(qpath).args ; + if !params.parenthesized; + if let Some(inner_ty) = params.args.iter().find_map(|arg| match arg { + GenericArg::Type(inner_ty) => Some(inner_ty), + _ => None, + }); + if let TyKind::Rptr(_, _) = inner_ty.kind; + + then { + span_lint_and_sugg( + cx, + REF_OPTION_REF, + ty.span, + "since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>`", + "try", + format!("Option<{}>", &snippet(cx, inner_ty.span, "..")), + Applicability::MaybeIncorrect, + ); + } + } + } +} diff --git a/clippy_lints/src/repeat_once.rs b/clippy_lints/src/repeat_once.rs index ae6013530091e..d34e744eb944c 100644 --- a/clippy_lints/src/repeat_once.rs +++ b/clippy_lints/src/repeat_once.rs @@ -5,6 +5,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usage of `.repeat(1)` and suggest the following method for each types. @@ -65,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for RepeatOnce { format!("{}.to_vec()", snippet(cx, receiver.span, r#""...""#)), Applicability::MachineApplicable, ); - } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) { + } else if is_type_diagnostic_item(cx, ty, sym::string_type) { span_lint_and_sugg( cx, REPEAT_ONCE, diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index a6e4252a0c825..7f4913a02cbd3 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -9,6 +9,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then}; @@ -141,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } fn attr_is_cfg(attr: &Attribute) -> bool { - attr.meta_item_list().is_some() && attr.has_name(sym!(cfg)) + attr.meta_item_list().is_some() && attr.has_name(sym::cfg) } fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) { diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs index 3783bd78de25e..0dd2da949c4c3 100644 --- a/clippy_lints/src/strings.rs +++ b/clippy_lints/src/strings.rs @@ -4,6 +4,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; +use rustc_span::sym; use if_chain::if_chain; @@ -154,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for StringAdd { } fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym!(string_type)) + is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), sym::string_type) } fn is_add(cx: &LateContext<'_>, src: &Expr<'_>, target: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/swap.rs b/clippy_lints/src/swap.rs index 54b38d9f4ced2..386987eb181ea 100644 --- a/clippy_lints/src/swap.rs +++ b/clippy_lints/src/swap.rs @@ -8,6 +8,7 @@ use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for manual swapping. @@ -197,7 +198,7 @@ fn check_for_slice<'a>(cx: &LateContext<'_>, lhs1: &'a Expr<'_>, lhs2: &'a Expr< if matches!(ty.kind(), ty::Slice(_)) || matches!(ty.kind(), ty::Array(_, _)) - || is_type_diagnostic_item(cx, ty, sym!(vec_type)) + || is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type)) { return Slice::Swappable(lhs1, idx1, idx2); diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 3e747ec4ad9e2..6f6b6999bf0a9 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -9,6 +9,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for usages of `Err(x)?`. @@ -133,7 +134,7 @@ fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> O fn result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { if_chain! { if let ty::Adt(_, subst) = ty.kind(); - if is_type_diagnostic_item(cx, ty, sym!(result_type)); + if is_type_diagnostic_item(cx, ty, sym::result_type); let err_ty = subst.type_at(1); then { Some(err_ty) @@ -151,7 +152,7 @@ fn poll_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option< let ready_ty = subst.type_at(0); if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym!(result_type), ready_def.did); + if cx.tcx.is_diagnostic_item(sym::result_type, ready_def.did); let err_ty = ready_subst.type_at(1); then { @@ -170,11 +171,11 @@ fn poll_option_result_error_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> let ready_ty = subst.type_at(0); if let ty::Adt(ready_def, ready_subst) = ready_ty.kind(); - if cx.tcx.is_diagnostic_item(sym!(option_type), ready_def.did); + if cx.tcx.is_diagnostic_item(sym::option_type, ready_def.did); let some_ty = ready_subst.type_at(0); if let ty::Adt(some_def, some_subst) = some_ty.kind(); - if cx.tcx.is_diagnostic_item(sym!(result_type), some_def.did); + if cx.tcx.is_diagnostic_item(sym::result_type, some_def.did); let err_ty = some_subst.type_at(1); then { diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs index 6a33aaaaab204..c7d82da3b8ba4 100644 --- a/clippy_lints/src/types.rs +++ b/clippy_lints/src/types.rs @@ -10,9 +10,9 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::intravisit::{walk_body, walk_expr, walk_ty, FnKind, NestedVisitorMap, Visitor}; use rustc_hir::{ - BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericParamKind, HirId, ImplItem, - ImplItemKind, Item, ItemKind, Lifetime, Lit, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, StmtKind, - TraitFn, TraitItem, TraitItemKind, TyKind, UnOp, + BinOpKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, FnSig, GenericArg, GenericBounds, GenericParamKind, HirId, + ImplItem, ImplItemKind, Item, ItemKind, Lifetime, Lit, Local, MatchSource, MutTy, Mutability, Node, QPath, Stmt, + StmtKind, SyntheticTyParamKind, TraitFn, TraitItem, TraitItemKind, TyKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; @@ -522,7 +522,7 @@ impl Types { ); return; // don't recurse into the type } - } else if cx.tcx.is_diagnostic_item(sym!(vec_type), def_id) { + } else if cx.tcx.is_diagnostic_item(sym::vec_type, def_id) { if_chain! { // Get the _ part of Vec<_> if let Some(ref last) = last_path_segment(qpath).args; @@ -559,7 +559,7 @@ impl Types { return; // don't recurse into the type } } - } else if cx.tcx.is_diagnostic_item(sym!(option_type), def_id) { + } else if cx.tcx.is_diagnostic_item(sym::option_type, def_id) { if match_type_parameter(cx, qpath, &paths::OPTION).is_some() { span_lint( cx, @@ -678,17 +678,30 @@ impl Types { // details. return; } + + // When trait objects or opaque types have lifetime or auto-trait bounds, + // we need to add parentheses to avoid a syntax error due to its ambiguity. + // Originally reported as the issue #3128. + let inner_snippet = snippet(cx, inner.span, ".."); + let suggestion = match &inner.kind { + TyKind::TraitObject(bounds, lt_bound) if bounds.len() > 1 || !lt_bound.is_elided() => { + format!("&{}({})", ltopt, &inner_snippet) + }, + TyKind::Path(qpath) + if get_bounds_if_impl_trait(cx, qpath, inner.hir_id) + .map_or(false, |bounds| bounds.len() > 1) => + { + format!("&{}({})", ltopt, &inner_snippet) + }, + _ => format!("&{}{}", ltopt, &inner_snippet), + }; span_lint_and_sugg( cx, BORROWED_BOX, hir_ty.span, "you seem to be trying to use `&Box`. Consider using just `&T`", "try", - format!( - "&{}{}", - ltopt, - &snippet(cx, inner.span, "..") - ), + suggestion, // To make this `MachineApplicable`, at least one needs to check if it isn't a trait item // because the trait impls of it will break otherwise; // and there may be other cases that result in invalid code. @@ -721,6 +734,21 @@ fn is_any_trait(t: &hir::Ty<'_>) -> bool { false } +fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: HirId) -> Option> { + if_chain! { + if let Some(did) = qpath_res(cx, qpath, id).opt_def_id(); + if let Some(node) = cx.tcx.hir().get_if_local(did); + if let Node::GenericParam(generic_param) = node; + if let GenericParamKind::Type { synthetic, .. } = generic_param.kind; + if synthetic == Some(SyntheticTyParamKind::ImplTrait); + then { + Some(generic_param.bounds) + } else { + None + } + } +} + declare_clippy_lint! { /// **What it does:** Checks for binding a unit value. /// @@ -1582,7 +1610,7 @@ fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { if names.is_empty() { return false; } - if names[0] == sym!(libc) || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) { + if names[0] == sym::libc || names[0] == sym::core && *names.last().unwrap() == sym!(c_void) { return true; } } @@ -2749,7 +2777,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't } if match_path(ty_path, &paths::HASHMAP) { - if method.ident.name == sym!(new) { + if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashMap::default()".to_string()); } else if method.ident.name == sym!(with_capacity) { @@ -2762,7 +2790,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 't ); } } else if match_path(ty_path, &paths::HASHSET) { - if method.ident.name == sym!(new) { + if method.ident.name == sym::new { self.suggestions .insert(e.span, "HashSet::default()".to_string()); } else if method.ident.name == sym!(with_capacity) { diff --git a/clippy_lints/src/unnecessary_sort_by.rs b/clippy_lints/src/unnecessary_sort_by.rs index 1307237dbc70a..0bccfc156788a 100644 --- a/clippy_lints/src/unnecessary_sort_by.rs +++ b/clippy_lints/src/unnecessary_sort_by.rs @@ -6,6 +6,7 @@ use rustc_hir::{Expr, ExprKind, Mutability, Param, Pat, PatKind, Path, PathSegme use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, subst::GenericArgKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; use rustc_span::symbol::Ident; declare_clippy_lint! { @@ -175,7 +176,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let name = name_ident.ident.name.to_ident_string(); if name == "sort_by" || name == "sort_unstable_by"; if let [vec, Expr { kind: ExprKind::Closure(_, _, closure_body_id, _, _), .. }] = args; - if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym!(vec_type)); + if utils::is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(vec), sym::vec_type); if let closure_body = cx.tcx.hir().body(*closure_body_id); if let &[ Param { pat: Pat { kind: PatKind::Binding(_, _, left_ident, _), .. }, ..}, diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index 7548c6afa973a..b1339c3d6395d 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -123,6 +123,17 @@ fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { fn_source .rfind("->") .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + let mut rpos = rpos; + let chars: Vec = fn_source.chars().collect(); + while rpos > 1 { + if let Some(c) = chars.get(rpos - 1) { + if c.is_whitespace() { + rpos -= 1; + continue; + } + } + break; + } ( #[allow(clippy::cast_possible_truncation)] ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index ea4b8172c9c2e..f4a77e54dd149 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -11,6 +11,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::Ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for calls of `unwrap[_err]()` that cannot fail. @@ -92,11 +93,11 @@ fn collect_unwrap_info<'tcx>( invert: bool, ) -> Vec> { fn is_relevant_option_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool { - is_type_diagnostic_item(cx, ty, sym!(option_type)) && ["is_some", "is_none"].contains(&method_name) + is_type_diagnostic_item(cx, ty, sym::option_type) && ["is_some", "is_none"].contains(&method_name) } fn is_relevant_result_call(cx: &LateContext<'_>, ty: Ty<'_>, method_name: &str) -> bool { - is_type_diagnostic_item(cx, ty, sym!(result_type)) && ["is_ok", "is_err"].contains(&method_name) + is_type_diagnostic_item(cx, ty, sym::result_type) && ["is_ok", "is_err"].contains(&method_name) } if let ExprKind::Binary(op, left, right) = &expr.kind { @@ -168,8 +169,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { if_chain! { if let ExprKind::MethodCall(ref method_name, _, ref args, _) = expr.kind; if let ExprKind::Path(QPath::Resolved(None, ref path)) = args[0].kind; - if [sym!(unwrap), sym!(unwrap_err)].contains(&method_name.ident.name); - let call_to_unwrap = method_name.ident.name == sym!(unwrap); + if [sym::unwrap, sym!(unwrap_err)].contains(&method_name.ident.name); + let call_to_unwrap = method_name.ident.name == sym::unwrap; if let Some(unwrappable) = self.unwrappables.iter() .find(|u| u.ident.res == path.res); // Span contexts should not differ with the conditional branch diff --git a/clippy_lints/src/unwrap_in_result.rs b/clippy_lints/src/unwrap_in_result.rs index 0f8797243eca3..fde3102933098 100644 --- a/clippy_lints/src/unwrap_in_result.rs +++ b/clippy_lints/src/unwrap_in_result.rs @@ -5,7 +5,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::Span; +use rustc_span::{sym, Span}; declare_clippy_lint! { /// **What it does:** Checks for functions of type Result that contain `expect()` or `unwrap()` @@ -57,8 +57,8 @@ impl<'tcx> LateLintPass<'tcx> for UnwrapInResult { // first check if it's a method or function if let hir::ImplItemKind::Fn(ref _signature, _) = impl_item.kind; // checking if its return type is `result` or `option` - if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(result_type)) - || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(option_type)); + if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::result_type) + || is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym::option_type); then { lint_impl_body(cx, impl_item.span, impl_item); } @@ -82,8 +82,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `expect` if let Some(arglists) = method_chain_args(expr, &["expect"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) { self.result.push(expr.span); } @@ -92,8 +92,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> { // check for `unwrap` if let Some(arglists) = method_chain_args(expr, &["unwrap"]) { let reciever_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs(); - if is_type_diagnostic_item(self.lcx, reciever_ty, sym!(option_type)) - || is_type_diagnostic_item(self.lcx, reciever_ty, sym!(result_type)) + if is_type_diagnostic_item(self.lcx, reciever_ty, sym::option_type) + || is_type_diagnostic_item(self.lcx, reciever_ty, sym::result_type) { self.result.push(expr.span); } diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 4e4a206a583a2..c6194b0c6de3e 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -9,6 +9,7 @@ use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, TyS}; use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls @@ -106,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); - if is_type_diagnostic_item(cx, a, sym!(result_type)); + if is_type_diagnostic_item(cx, a, sym::result_type); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); if TyS::same_type(a_type, b); @@ -136,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { then { if_chain! { if match_def_path(cx, def_id, &paths::TRY_FROM); - if is_type_diagnostic_item(cx, a, sym!(result_type)); + if is_type_diagnostic_item(cx, a, sym::result_type); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); if TyS::same_type(a_type, b); diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs index 6ca72d895c8da..8b59a9541a736 100644 --- a/clippy_lints/src/utils/internal_lints.rs +++ b/clippy_lints/src/utils/internal_lints.rs @@ -225,7 +225,7 @@ declare_clippy_lint! { /// /// Good: /// ```rust,ignore - /// utils::is_type_diagnostic_item(cx, ty, sym!(vec_type)) + /// utils::is_type_diagnostic_item(cx, ty, sym::vec_type) /// ``` pub MATCH_TYPE_ON_DIAGNOSTIC_ITEM, internal, @@ -724,7 +724,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchTypeOnDiagItem { expr.span, "usage of `utils::match_type()` on a type diagnostic item", "try", - format!("utils::is_type_diagnostic_item({}, {}, sym!({}))", cx_snippet, ty_snippet, item_name), + format!("utils::is_type_diagnostic_item({}, {}, sym::{})", cx_snippet, ty_snippet, item_name), Applicability::MaybeIncorrect, ); } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 0a8a4a5f9aedb..85e7f055e79de 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -52,6 +52,7 @@ use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::original_sp; +use rustc_span::sym as rustc_sym; use rustc_span::symbol::{self, kw, Symbol}; use rustc_span::{BytePos, Pos, Span, DUMMY_SP}; use rustc_target::abi::Integer; @@ -974,7 +975,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { /// Checks for the `#[automatically_derived]` attribute all `#[derive]`d /// implementations have. pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool { - attrs.iter().any(|attr| attr.has_name(sym!(automatically_derived))) + attrs.iter().any(|attr| attr.has_name(rustc_sym::automatically_derived)) } /// Remove blocks around an expression. diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 736a531eda657..1ad8c6029860b 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -44,6 +44,7 @@ pub const FN: [&str; 3] = ["core", "ops", "Fn"]; pub const FN_MUT: [&str; 3] = ["core", "ops", "FnMut"]; pub const FN_ONCE: [&str; 3] = ["core", "ops", "FnOnce"]; pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"]; +pub const FROM_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "FromIterator"]; pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"]; pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"]; pub const HASH: [&str; 3] = ["core", "hash", "Hash"]; @@ -52,6 +53,7 @@ pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entr pub const HASHSET: [&str; 5] = ["std", "collections", "hash", "set", "HashSet"]; pub const INDEX: [&str; 3] = ["core", "ops", "Index"]; pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"]; +pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"]; pub const INTO: [&str; 3] = ["core", "convert", "Into"]; pub const INTO_ITERATOR: [&str; 5] = ["core", "iter", "traits", "collect", "IntoIterator"]; pub const IO_READ: [&str; 3] = ["std", "io", "Read"]; diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs index d9d60fffcd7ae..ff414f748ef97 100644 --- a/clippy_lints/src/write.rs +++ b/clippy_lints/src/write.rs @@ -10,8 +10,7 @@ use rustc_lexer::unescape::{self, EscapeError}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_parse::parser; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::symbol::Symbol; -use rustc_span::{BytePos, Span}; +use rustc_span::{sym, BytePos, Span, Symbol}; declare_clippy_lint! { /// **What it does:** This lint warns when you use `println!("")` to @@ -224,7 +223,7 @@ impl EarlyLintPass for Write { .expect("path has at least one segment") .ident .name; - if trait_name == sym!(Debug) { + if trait_name == sym::Debug { self.in_debug_impl = true; } } diff --git a/doc/adding_lints.md b/doc/adding_lints.md index 2572833b8debf..b1dacfc9c6d28 100644 --- a/doc/adding_lints.md +++ b/doc/adding_lints.md @@ -311,7 +311,7 @@ Running our UI test should now produce output that contains the lint message. According to [the rustc-dev-guide], the text should be matter of fact and avoid capitalization and periods, unless multiple sentences are needed. When code or an identifier must appear in a message or label, it should be -surrounded with single acute accents \`. +surrounded with single grave accents \`. [check_fn]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html#method.check_fn [diagnostics]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/diagnostics.rs diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index c2e63ecb581ec..702f9d86de62d 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -298,6 +298,13 @@ vec![ deprecation: None, module: "comparison_chain", }, + Lint { + name: "comparison_to_empty", + group: "style", + desc: "checking `x == \"\"` or `x == []` (or similar) when `.is_empty()` could be used instead", + deprecation: None, + module: "len_zero", + }, Lint { name: "copy_iterator", group: "pedantic", @@ -352,7 +359,7 @@ vec![ group: "pedantic", desc: "checks for literal calls to `Default::default()`", deprecation: None, - module: "default_trait_access", + module: "default", }, Lint { name: "deprecated_cfg_attr", @@ -620,6 +627,13 @@ vec![ deprecation: None, module: "fallible_impl_from", }, + Lint { + name: "field_reassign_with_default", + group: "style", + desc: "binding initialized with Default should have its fields set in the initializer", + deprecation: None, + module: "default", + }, Lint { name: "filetype_is_file", group: "restriction", @@ -746,6 +760,13 @@ vec![ deprecation: None, module: "drop_forget_ref", }, + Lint { + name: "from_iter_instead_of_collect", + group: "style", + desc: "use `.collect()` instead of `::from_iter()`", + deprecation: None, + module: "methods", + }, Lint { name: "future_not_send", group: "nursery", @@ -1173,6 +1194,13 @@ vec![ deprecation: None, module: "manual_non_exhaustive", }, + Lint { + name: "manual_ok_or", + group: "pedantic", + desc: "finds patterns that can be encoded more concisely with `Option::ok_or`", + deprecation: None, + module: "manual_ok_or", + }, Lint { name: "manual_range_contains", group: "style", @@ -1222,6 +1250,13 @@ vec![ deprecation: None, module: "map_clone", }, + Lint { + name: "map_collect_result_unit", + group: "style", + desc: "using `.map(_).collect::()`, which can be replaced with `try_for_each`", + deprecation: None, + module: "methods", + }, Lint { name: "map_entry", group: "perf", @@ -2013,6 +2048,13 @@ vec![ deprecation: None, module: "reference", }, + Lint { + name: "ref_option_ref", + group: "pedantic", + desc: "use `Option<&T>` instead of `&Option<&T>`", + deprecation: None, + module: "ref_option_ref", + }, Lint { name: "repeat_once", group: "complexity", @@ -2133,16 +2175,16 @@ vec![ module: "non_expressive_names", }, Lint { - name: "single_char_pattern", - group: "perf", - desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", + name: "single_char_add_str", + group: "style", + desc: "`push_str()` or `insert_str()` used with a single-character string literal as parameter", deprecation: None, module: "methods", }, Lint { - name: "single_char_push_str", - group: "style", - desc: "`push_str()` used with a single-character string literal as parameter", + name: "single_char_pattern", + group: "perf", + desc: "using a single-character str where a char could be used, e.g., `_.split(\"x\")`", deprecation: None, module: "methods", }, diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs index 0bbb9534928ef..93303865e178e 100644 --- a/tests/ui/auxiliary/macro_rules.rs +++ b/tests/ui/auxiliary/macro_rules.rs @@ -56,3 +56,17 @@ macro_rules! option_env_unwrap_external { option_env!($env).expect($message) }; } + +#[macro_export] +macro_rules! ref_arg_binding { + () => { + let ref _y = 42; + }; +} + +#[macro_export] +macro_rules! ref_arg_function { + () => { + fn fun_example(ref _x: usize) {} + }; +} diff --git a/tests/ui/borrow_box.rs b/tests/ui/borrow_box.rs index 1901de46ca894..b606f773cfbad 100644 --- a/tests/ui/borrow_box.rs +++ b/tests/ui/borrow_box.rs @@ -3,6 +3,8 @@ #![allow(unused_variables)] #![allow(dead_code)] +use std::fmt::Display; + pub fn test1(foo: &mut Box) { // Although this function could be changed to "&mut bool", // avoiding the Box, mutable references to boxes are not @@ -89,6 +91,20 @@ pub fn test13(boxed_slice: &mut Box<[i32]>) { *boxed_slice = data.into_boxed_slice(); } +// The suggestion should include proper parentheses to avoid a syntax error. +pub fn test14(_display: &Box) {} +pub fn test15(_display: &Box) {} +pub fn test16<'a>(_display: &'a Box) {} + +pub fn test17(_display: &Box) {} +pub fn test18(_display: &Box) {} +pub fn test19<'a>(_display: &'a Box) {} + +// This exists only to check what happens when parentheses are already present. +// Even though the current implementation doesn't put extra parentheses, +// it's fine that unnecessary parentheses appear in the future for some reason. +pub fn test20(_display: &Box<(dyn Display + Send)>) {} + fn main() { test1(&mut Box::new(false)); test2(); diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index b5db691f89f39..3eac32815be3f 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -1,5 +1,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:19:14 + --> $DIR/borrow_box.rs:21:14 | LL | let foo: &Box; | ^^^^^^^^^^ help: try: `&bool` @@ -11,16 +11,58 @@ LL | #![deny(clippy::borrowed_box)] | ^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:23:10 + --> $DIR/borrow_box.rs:25:10 | LL | foo: &'a Box, | ^^^^^^^^^^^^^ help: try: `&'a bool` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> $DIR/borrow_box.rs:27:17 + --> $DIR/borrow_box.rs:29:17 | LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` -error: aborting due to 3 previous errors +error: you seem to be trying to use `&Box`. Consider using just `&T` + --> $DIR/borrow_box.rs:95:25 + | +LL | pub fn test14(_display: &Box) {} + | ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display` + +error: you seem to be trying to use `&Box`. Consider using just `&T` + --> $DIR/borrow_box.rs:96:25 + | +LL | pub fn test15(_display: &Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` + +error: you seem to be trying to use `&Box`. Consider using just `&T` + --> $DIR/borrow_box.rs:97:29 + | +LL | pub fn test16<'a>(_display: &'a Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)` + +error: you seem to be trying to use `&Box`. Consider using just `&T` + --> $DIR/borrow_box.rs:99:25 + | +LL | pub fn test17(_display: &Box) {} + | ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display` + +error: you seem to be trying to use `&Box`. Consider using just `&T` + --> $DIR/borrow_box.rs:100:25 + | +LL | pub fn test18(_display: &Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)` + +error: you seem to be trying to use `&Box`. Consider using just `&T` + --> $DIR/borrow_box.rs:101:29 + | +LL | pub fn test19<'a>(_display: &'a Box) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)` + +error: you seem to be trying to use `&Box`. Consider using just `&T` + --> $DIR/borrow_box.rs:106:25 + | +LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` + +error: aborting due to 10 previous errors diff --git a/tests/ui/comparison_to_empty.fixed b/tests/ui/comparison_to_empty.fixed new file mode 100644 index 0000000000000..261024caca761 --- /dev/null +++ b/tests/ui/comparison_to_empty.fixed @@ -0,0 +1,23 @@ +// run-rustfix + +#![warn(clippy::comparison_to_empty)] + +fn main() { + // Disallow comparisons to empty + let s = String::new(); + let _ = s.is_empty(); + let _ = !s.is_empty(); + + let v = vec![0]; + let _ = v.is_empty(); + let _ = !v.is_empty(); + + // Allow comparisons to non-empty + let s = String::new(); + let _ = s == " "; + let _ = s != " "; + + let v = vec![0]; + let _ = v == [0]; + let _ = v != [0]; +} diff --git a/tests/ui/comparison_to_empty.rs b/tests/ui/comparison_to_empty.rs new file mode 100644 index 0000000000000..98ddd97495161 --- /dev/null +++ b/tests/ui/comparison_to_empty.rs @@ -0,0 +1,23 @@ +// run-rustfix + +#![warn(clippy::comparison_to_empty)] + +fn main() { + // Disallow comparisons to empty + let s = String::new(); + let _ = s == ""; + let _ = s != ""; + + let v = vec![0]; + let _ = v == []; + let _ = v != []; + + // Allow comparisons to non-empty + let s = String::new(); + let _ = s == " "; + let _ = s != " "; + + let v = vec![0]; + let _ = v == [0]; + let _ = v != [0]; +} diff --git a/tests/ui/comparison_to_empty.stderr b/tests/ui/comparison_to_empty.stderr new file mode 100644 index 0000000000000..f69d6bd5255df --- /dev/null +++ b/tests/ui/comparison_to_empty.stderr @@ -0,0 +1,28 @@ +error: comparison to empty slice + --> $DIR/comparison_to_empty.rs:8:13 + | +LL | let _ = s == ""; + | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` + | + = note: `-D clippy::comparison-to-empty` implied by `-D warnings` + +error: comparison to empty slice + --> $DIR/comparison_to_empty.rs:9:13 + | +LL | let _ = s != ""; + | ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` + +error: comparison to empty slice + --> $DIR/comparison_to_empty.rs:12:13 + | +LL | let _ = v == []; + | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` + +error: comparison to empty slice + --> $DIR/comparison_to_empty.rs:13:13 + | +LL | let _ = v != []; + | ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/crashes/ice-6250.rs b/tests/ui/crashes/ice-6250.rs new file mode 100644 index 0000000000000..c33580ff6ab6a --- /dev/null +++ b/tests/ui/crashes/ice-6250.rs @@ -0,0 +1,16 @@ +// originally from glacier/fixed/77218.rs +// ice while adjusting... + +pub struct Cache { + data: Vec, +} + +pub fn list_data(cache: &Cache, key: usize) { + for reference in vec![1, 2, 3] { + if + /* let */ + Some(reference) = cache.data.get(key) { + unimplemented!() + } + } +} diff --git a/tests/ui/crashes/ice-6250.stderr b/tests/ui/crashes/ice-6250.stderr new file mode 100644 index 0000000000000..8241dcd8feb7b --- /dev/null +++ b/tests/ui/crashes/ice-6250.stderr @@ -0,0 +1,27 @@ +error[E0601]: `main` function not found in crate `ice_6250` + --> $DIR/ice-6250.rs:4:1 + | +LL | / pub struct Cache { +LL | | data: Vec, +LL | | } +LL | | +... | +LL | | } +LL | | } + | |_^ consider adding a `main` function to `$DIR/ice-6250.rs` + +error[E0308]: mismatched types + --> $DIR/ice-6250.rs:12:9 + | +LL | Some(reference) = cache.data.get(key) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | let Some(reference) = cache.data.get(key) { + | ^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0601. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/crashes/ice-6251.rs b/tests/ui/crashes/ice-6251.rs new file mode 100644 index 0000000000000..6aa779aaeb3b6 --- /dev/null +++ b/tests/ui/crashes/ice-6251.rs @@ -0,0 +1,6 @@ +// originally from glacier/fixed/77329.rs +// assertion failed: `(left == right) ; different DefIds + +fn bug() -> impl Iterator { + std::iter::empty() +} diff --git a/tests/ui/crashes/ice-6251.stderr b/tests/ui/crashes/ice-6251.stderr new file mode 100644 index 0000000000000..9a7cf4b0919f6 --- /dev/null +++ b/tests/ui/crashes/ice-6251.stderr @@ -0,0 +1,43 @@ +error[E0601]: `main` function not found in crate `ice_6251` + --> $DIR/ice-6251.rs:4:1 + | +LL | / fn bug() -> impl Iterator { +LL | | std::iter::empty() +LL | | } + | |_^ consider adding a `main` function to `$DIR/ice-6251.rs` + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/ice-6251.rs:4:45 + | +LL | fn bug() -> impl Iterator { + | ^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: unsized fn params are gated as an unstable feature +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | fn bug() -> impl Iterator { + | ^ + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/ice-6251.rs:4:54 + | +LL | fn bug() -> impl Iterator { + | ^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = note: the return type of a function must have a statically known size + +error[E0308]: mismatched types + --> $DIR/ice-6251.rs:4:44 + | +LL | fn bug() -> impl Iterator { + | ^^^^^^^^^^^ expected `usize`, found closure + | + = note: expected type `usize` + found closure `[closure@$DIR/ice-6251.rs:4:44: 4:55]` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0308, E0601. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/crashes/ice-6252.rs b/tests/ui/crashes/ice-6252.rs new file mode 100644 index 0000000000000..2e3d9fd1e9240 --- /dev/null +++ b/tests/ui/crashes/ice-6252.rs @@ -0,0 +1,15 @@ +// originally from glacier fixed/77919.rs +// encountered errors resolving bounds after type-checking + +trait TypeVal { + const VAL: T; +} +struct Five; +struct Multiply { + _n: PhantomData, +} +impl TypeVal for Multiply where N: TypeVal {} + +fn main() { + [1; >::VAL]; +} diff --git a/tests/ui/crashes/ice-6252.stderr b/tests/ui/crashes/ice-6252.stderr new file mode 100644 index 0000000000000..440973e24398e --- /dev/null +++ b/tests/ui/crashes/ice-6252.stderr @@ -0,0 +1,46 @@ +error[E0412]: cannot find type `PhantomData` in this scope + --> $DIR/ice-6252.rs:9:9 + | +LL | _n: PhantomData, + | ^^^^^^^^^^^ not found in this scope + | +help: consider importing this struct + | +LL | use std::marker::PhantomData; + | + +error[E0412]: cannot find type `VAL` in this scope + --> $DIR/ice-6252.rs:11:63 + | +LL | impl TypeVal for Multiply where N: TypeVal {} + | - ^^^ not found in this scope + | | + | help: you might be missing a type parameter: `, VAL` + +error[E0046]: not all trait items implemented, missing: `VAL` + --> $DIR/ice-6252.rs:11:1 + | +LL | const VAL: T; + | ------------- `VAL` from trait +... +LL | impl TypeVal for Multiply where N: TypeVal {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + +error: any use of this value will cause an error + --> $DIR/ice-6252.rs:5:5 + | +LL | const VAL: T; + | ^^^^^^^^^^^^^ no MIR body is available for DefId(0:5 ~ ice_6252[317d]::TypeVal::VAL) + | + = note: `#[deny(const_err)]` on by default + +error[E0080]: evaluation of constant value failed + --> $DIR/ice-6252.rs:14:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0046, E0080, E0412. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/crashes/ice-6254.rs b/tests/ui/crashes/ice-6254.rs new file mode 100644 index 0000000000000..c19eca43884aa --- /dev/null +++ b/tests/ui/crashes/ice-6254.rs @@ -0,0 +1,15 @@ +// originally from ./src/test/ui/pattern/usefulness/consts-opaque.rs +// panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', +// compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5 + +#[derive(PartialEq)] +struct Foo(i32); +const FOO_REF_REF: &&Foo = &&Foo(42); + +fn main() { + // This used to cause an ICE (https://github.com/rust-lang/rust/issues/78071) + match FOO_REF_REF { + FOO_REF_REF => {}, + Foo(_) => {}, + } +} diff --git a/tests/ui/crashes/ice-6254.stderr b/tests/ui/crashes/ice-6254.stderr new file mode 100644 index 0000000000000..95ebf23d81817 --- /dev/null +++ b/tests/ui/crashes/ice-6254.stderr @@ -0,0 +1,12 @@ +error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/ice-6254.rs:12:9 + | +LL | FOO_REF_REF => {}, + | ^^^^^^^^^^^ + | + = note: `-D indirect-structural-match` implied by `-D warnings` + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + +error: aborting due to previous error + diff --git a/tests/ui/crashes/ice-6255.rs b/tests/ui/crashes/ice-6255.rs new file mode 100644 index 0000000000000..bd4a81d98e2e7 --- /dev/null +++ b/tests/ui/crashes/ice-6255.rs @@ -0,0 +1,15 @@ +// originally from rustc ./src/test/ui/macros/issue-78325-inconsistent-resolution.rs +// inconsistent resolution for a macro + +macro_rules! define_other_core { + ( ) => { + extern crate std as core; + //~^ ERROR macro-expanded `extern crate` items cannot shadow names passed with `--extern` + }; +} + +fn main() { + core::panic!(); +} + +define_other_core!(); diff --git a/tests/ui/crashes/ice-6255.stderr b/tests/ui/crashes/ice-6255.stderr new file mode 100644 index 0000000000000..d973ea1e23a25 --- /dev/null +++ b/tests/ui/crashes/ice-6255.stderr @@ -0,0 +1,13 @@ +error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` + --> $DIR/ice-6255.rs:6:9 + | +LL | extern crate std as core; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | define_other_core!(); + | --------------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/crashes/ice-6256.rs b/tests/ui/crashes/ice-6256.rs new file mode 100644 index 0000000000000..6f60d45d68a8e --- /dev/null +++ b/tests/ui/crashes/ice-6256.rs @@ -0,0 +1,13 @@ +// originally from rustc ./src/test/ui/regions/issue-78262.rs +// ICE: to get the signature of a closure, use substs.as_closure().sig() not fn_sig() + +trait TT {} + +impl dyn TT { + fn func(&self) {} +} + +fn main() { + let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types + //[nll]~^ ERROR: borrowed data escapes outside of closure +} diff --git a/tests/ui/crashes/ice-6256.stderr b/tests/ui/crashes/ice-6256.stderr new file mode 100644 index 0000000000000..0e8353a418a87 --- /dev/null +++ b/tests/ui/crashes/ice-6256.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/ice-6256.rs:11:28 + | +LL | let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types + | ^^^^ lifetime mismatch + | + = note: expected reference `&(dyn TT + 'static)` + found reference `&dyn TT` +note: the anonymous lifetime #1 defined on the body at 11:13... + --> $DIR/ice-6256.rs:11:13 + | +LL | let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types + | ^^^^^^^^^^^^^^^^^^^^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs new file mode 100644 index 0000000000000..79a30c22f9536 --- /dev/null +++ b/tests/ui/field_reassign_with_default.rs @@ -0,0 +1,110 @@ +#![warn(clippy::field_reassign_with_default)] + +#[derive(Default)] +struct A { + i: i32, + j: i64, +} + +struct B { + i: i32, + j: i64, +} + +/// Implements .next() that returns a different number each time. +struct SideEffect(i32); + +impl SideEffect { + fn new() -> SideEffect { + SideEffect(0) + } + fn next(&mut self) -> i32 { + self.0 += 1; + self.0 + } +} + +fn main() { + // wrong, produces first error in stderr + let mut a: A = Default::default(); + a.i = 42; + + // right + let mut a: A = Default::default(); + + // right + let a = A { + i: 42, + ..Default::default() + }; + + // right + let mut a: A = Default::default(); + if a.i == 0 { + a.j = 12; + } + + // right + let mut a: A = Default::default(); + let b = 5; + + // right + let mut b = 32; + let mut a: A = Default::default(); + b = 2; + + // right + let b: B = B { i: 42, j: 24 }; + + // right + let mut b: B = B { i: 42, j: 24 }; + b.i = 52; + + // right + let mut b = B { i: 15, j: 16 }; + let mut a: A = Default::default(); + b.i = 2; + + // wrong, produces second error in stderr + let mut a: A = Default::default(); + a.j = 43; + a.i = 42; + + // wrong, produces third error in stderr + let mut a: A = Default::default(); + a.i = 42; + a.j = 43; + a.j = 44; + + // wrong, produces fourth error in stderr + let mut a = A::default(); + a.i = 42; + + // wrong, but does not produce an error in stderr, because we can't produce a correct kind of + // suggestion with current implementation + let mut c: (i32, i32) = Default::default(); + c.0 = 42; + c.1 = 21; + + // wrong, produces the fifth error in stderr + let mut a: A = Default::default(); + a.i = Default::default(); + + // wrong, produces the sixth error in stderr + let mut a: A = Default::default(); + a.i = Default::default(); + a.j = 45; + + // right, because an assignment refers to another field + let mut x = A::default(); + x.i = 42; + x.j = 21 + x.i as i64; + + // right, we bail out if there's a reassignment to the same variable, since there is a risk of + // side-effects affecting the outcome + let mut x = A::default(); + let mut side_effect = SideEffect::new(); + x.i = side_effect.next(); + x.j = 2; + x.i = side_effect.next(); +} diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr new file mode 100644 index 0000000000000..c788ebae5526c --- /dev/null +++ b/tests/ui/field_reassign_with_default.stderr @@ -0,0 +1,75 @@ +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:30:5 + | +LL | a.i = 42; + | ^^^^^^^^^ + | + = note: `-D clippy::field-reassign-with-default` implied by `-D warnings` +note: consider initializing the variable with `A { i: 42, ..Default::default() }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:29:5 + | +LL | let mut a: A = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:70:5 + | +LL | a.j = 43; + | ^^^^^^^^^ + | +note: consider initializing the variable with `A { j: 43, i: 42 }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:69:5 + | +LL | let mut a: A = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:75:5 + | +LL | a.i = 42; + | ^^^^^^^^^ + | +note: consider initializing the variable with `A { i: 42, j: 44 }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:74:5 + | +LL | let mut a: A = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:81:5 + | +LL | a.i = 42; + | ^^^^^^^^^ + | +note: consider initializing the variable with `A { i: 42, ..Default::default() }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:80:5 + | +LL | let mut a = A::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:91:5 + | +LL | a.i = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: consider initializing the variable with `A::default()` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:90:5 + | +LL | let mut a: A = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:95:5 + | +LL | a.i = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: consider initializing the variable with `A { j: 45, ..Default::default() }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:94:5 + | +LL | let mut a: A = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/filter_map_next.rs b/tests/ui/filter_map_next.rs index f5d051be198ed..dbeb2354309c9 100644 --- a/tests/ui/filter_map_next.rs +++ b/tests/ui/filter_map_next.rs @@ -3,9 +3,6 @@ fn main() { let a = ["1", "lol", "3", "NaN", "5"]; - let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); - assert_eq!(element, Some(1)); - #[rustfmt::skip] let _: Option = vec![1, 2, 3, 4, 5, 6] .into_iter() diff --git a/tests/ui/filter_map_next.stderr b/tests/ui/filter_map_next.stderr index d69ae212414f6..45427684d96e1 100644 --- a/tests/ui/filter_map_next.stderr +++ b/tests/ui/filter_map_next.stderr @@ -1,14 +1,5 @@ -error: called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(p)` instead. - --> $DIR/filter_map_next.rs:6:32 - | -LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::filter-map-next` implied by `-D warnings` - = note: replace `filter_map(|s| s.parse().ok()).next()` with `find_map(|s| s.parse().ok())` - -error: called `filter_map(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(p)` instead. - --> $DIR/filter_map_next.rs:10:26 +error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead. + --> $DIR/filter_map_next.rs:7:26 | LL | let _: Option = vec![1, 2, 3, 4, 5, 6] | __________________________^ @@ -19,6 +10,8 @@ LL | | if x == 2 { LL | | }) LL | | .next(); | |_______________^ + | + = note: `-D clippy::filter-map-next` implied by `-D warnings` -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/filter_map_next_fixable.fixed b/tests/ui/filter_map_next_fixable.fixed new file mode 100644 index 0000000000000..c3992d7e92cf3 --- /dev/null +++ b/tests/ui/filter_map_next_fixable.fixed @@ -0,0 +1,10 @@ +// run-rustfix + +#![warn(clippy::all, clippy::pedantic)] + +fn main() { + let a = ["1", "lol", "3", "NaN", "5"]; + + let element: Option = a.iter().find_map(|s| s.parse().ok()); + assert_eq!(element, Some(1)); +} diff --git a/tests/ui/filter_map_next_fixable.rs b/tests/ui/filter_map_next_fixable.rs new file mode 100644 index 0000000000000..447219a968391 --- /dev/null +++ b/tests/ui/filter_map_next_fixable.rs @@ -0,0 +1,10 @@ +// run-rustfix + +#![warn(clippy::all, clippy::pedantic)] + +fn main() { + let a = ["1", "lol", "3", "NaN", "5"]; + + let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); + assert_eq!(element, Some(1)); +} diff --git a/tests/ui/filter_map_next_fixable.stderr b/tests/ui/filter_map_next_fixable.stderr new file mode 100644 index 0000000000000..6c2530e0379e4 --- /dev/null +++ b/tests/ui/filter_map_next_fixable.stderr @@ -0,0 +1,10 @@ +error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead. + --> $DIR/filter_map_next_fixable.rs:8:32 + | +LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `a.iter().find_map(|s| s.parse().ok())` + | + = note: `-D clippy::filter-map-next` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index 84a957a374c6b..91718dd11755b 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,4 +1,4 @@ -error: called `filter(p).map(q)` on an `Iterator` +error: called `filter(..).map(..)` on an `Iterator` --> $DIR/filter_methods.rs:5:21 | LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); @@ -7,7 +7,7 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * = note: `-D clippy::filter-map` implied by `-D warnings` = help: this is more succinctly expressed by calling `.filter_map(..)` instead -error: called `filter(p).flat_map(q)` on an `Iterator` +error: called `filter(..).flat_map(..)` on an `Iterator` --> $DIR/filter_methods.rs:7:21 | LL | let _: Vec<_> = vec![5_i8; 6] @@ -19,7 +19,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` -error: called `filter_map(p).flat_map(q)` on an `Iterator` +error: called `filter_map(..).flat_map(..)` on an `Iterator` --> $DIR/filter_methods.rs:13:21 | LL | let _: Vec<_> = vec![5_i8; 6] @@ -31,7 +31,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` -error: called `filter_map(p).map(q)` on an `Iterator` +error: called `filter_map(..).map(..)` on an `Iterator` --> $DIR/filter_methods.rs:19:21 | LL | let _: Vec<_> = vec![5_i8; 6] diff --git a/tests/ui/find_map.stderr b/tests/ui/find_map.stderr index f279850fef8af..aea3cc62afcc4 100644 --- a/tests/ui/find_map.stderr +++ b/tests/ui/find_map.stderr @@ -1,4 +1,4 @@ -error: called `find(p).map(q)` on an `Iterator` +error: called `find(..).map(..)` on an `Iterator` --> $DIR/find_map.rs:20:26 | LL | let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s| s.parse().unwrap()); @@ -7,7 +7,7 @@ LL | let _: Option = a.iter().find(|s| s.parse::().is_ok()).map(|s = note: `-D clippy::find-map` implied by `-D warnings` = help: this is more succinctly expressed by calling `.find_map(..)` instead -error: called `find(p).map(q)` on an `Iterator` +error: called `find(..).map(..)` on an `Iterator` --> $DIR/find_map.rs:23:29 | LL | let _: Option = desserts_of_the_week diff --git a/tests/ui/from_iter_instead_of_collect.rs b/tests/ui/from_iter_instead_of_collect.rs new file mode 100644 index 0000000000000..045eb3133d3c4 --- /dev/null +++ b/tests/ui/from_iter_instead_of_collect.rs @@ -0,0 +1,13 @@ +#![warn(clippy::from_iter_instead_of_collect)] + +use std::collections::HashMap; +use std::iter::FromIterator; + +fn main() { + let iter_expr = std::iter::repeat(5).take(5); + Vec::from_iter(iter_expr); + + HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + + Vec::from_iter(vec![42u32]); +} diff --git a/tests/ui/from_iter_instead_of_collect.stderr b/tests/ui/from_iter_instead_of_collect.stderr new file mode 100644 index 0000000000000..46bdc2f4e199b --- /dev/null +++ b/tests/ui/from_iter_instead_of_collect.stderr @@ -0,0 +1,16 @@ +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:8:5 + | +LL | Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect()` + | + = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:10:5 + | +LL | HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect()` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/get_unwrap.fixed b/tests/ui/get_unwrap.fixed index 97e6b20f471fc..924c02a4054d4 100644 --- a/tests/ui/get_unwrap.fixed +++ b/tests/ui/get_unwrap.fixed @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused_mut)] +#![allow(unused_mut, clippy::from_iter_instead_of_collect)] #![deny(clippy::get_unwrap)] use std::collections::BTreeMap; diff --git a/tests/ui/get_unwrap.rs b/tests/ui/get_unwrap.rs index 1c9a71c09699a..c0c37bb720663 100644 --- a/tests/ui/get_unwrap.rs +++ b/tests/ui/get_unwrap.rs @@ -1,5 +1,5 @@ // run-rustfix -#![allow(unused_mut)] +#![allow(unused_mut, clippy::from_iter_instead_of_collect)] #![deny(clippy::get_unwrap)] use std::collections::BTreeMap; diff --git a/tests/ui/integer_arithmetic.rs b/tests/ui/integer_arithmetic.rs index 7b1b64f390a5a..b74c93dc4a666 100644 --- a/tests/ui/integer_arithmetic.rs +++ b/tests/ui/integer_arithmetic.rs @@ -11,6 +11,8 @@ #[rustfmt::skip] fn main() { let mut i = 1i32; + let mut var1 = 0i32; + let mut var2 = -1i32; 1 + i; i * 2; 1 % @@ -32,7 +34,15 @@ fn main() { i -= 1; i *= 2; i /= 2; + i /= 0; + i /= -1; + i /= var1; + i /= var2; i %= 2; + i %= 0; + i %= -1; + i %= var1; + i %= var2; i <<= 3; i >>= 2; diff --git a/tests/ui/integer_arithmetic.stderr b/tests/ui/integer_arithmetic.stderr index 83e8a9cde3ff1..add3b6b90fa26 100644 --- a/tests/ui/integer_arithmetic.stderr +++ b/tests/ui/integer_arithmetic.stderr @@ -1,5 +1,19 @@ +error: this operation will panic at runtime + --> $DIR/integer_arithmetic.rs:37:5 + | +LL | i /= 0; + | ^^^^^^ attempt to divide `_` by zero + | + = note: `#[deny(unconditional_panic)]` on by default + +error: this operation will panic at runtime + --> $DIR/integer_arithmetic.rs:42:5 + | +LL | i %= 0; + | ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero + error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:14:5 + --> $DIR/integer_arithmetic.rs:16:5 | LL | 1 + i; | ^^^^^ @@ -7,125 +21,149 @@ LL | 1 + i; = note: `-D clippy::integer-arithmetic` implied by `-D warnings` error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:15:5 + --> $DIR/integer_arithmetic.rs:17:5 | LL | i * 2; | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:16:5 + --> $DIR/integer_arithmetic.rs:18:5 | LL | / 1 % LL | | i / 2; // no error, this is part of the expression in the preceding line - | |_________^ + | |_____^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:18:5 + --> $DIR/integer_arithmetic.rs:20:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:19:5 + --> $DIR/integer_arithmetic.rs:21:5 | LL | -i; | ^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:20:5 + --> $DIR/integer_arithmetic.rs:22:5 | LL | i >> 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:21:5 + --> $DIR/integer_arithmetic.rs:23:5 | LL | i << 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:31:5 + --> $DIR/integer_arithmetic.rs:33:5 | LL | i += 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:32:5 + --> $DIR/integer_arithmetic.rs:34:5 | LL | i -= 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:33:5 + --> $DIR/integer_arithmetic.rs:35:5 | LL | i *= 2; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:34:5 + --> $DIR/integer_arithmetic.rs:38:11 | -LL | i /= 2; - | ^^^^^^ +LL | i /= -1; + | ^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:35:5 + --> $DIR/integer_arithmetic.rs:39:5 | -LL | i %= 2; - | ^^^^^^ +LL | i /= var1; + | ^^^^^^^^^ + +error: integer arithmetic detected + --> $DIR/integer_arithmetic.rs:40:5 + | +LL | i /= var2; + | ^^^^^^^^^ + +error: integer arithmetic detected + --> $DIR/integer_arithmetic.rs:43:11 + | +LL | i %= -1; + | ^ + +error: integer arithmetic detected + --> $DIR/integer_arithmetic.rs:44:5 + | +LL | i %= var1; + | ^^^^^^^^^ + +error: integer arithmetic detected + --> $DIR/integer_arithmetic.rs:45:5 + | +LL | i %= var2; + | ^^^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:36:5 + --> $DIR/integer_arithmetic.rs:46:5 | LL | i <<= 3; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:37:5 + --> $DIR/integer_arithmetic.rs:47:5 | LL | i >>= 2; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:79:5 + --> $DIR/integer_arithmetic.rs:89:5 | LL | 3 + &1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:80:5 + --> $DIR/integer_arithmetic.rs:90:5 | LL | &3 + 1; | ^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:81:5 + --> $DIR/integer_arithmetic.rs:91:5 | LL | &3 + &1; | ^^^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:86:5 + --> $DIR/integer_arithmetic.rs:96:5 | LL | a + x | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:90:5 + --> $DIR/integer_arithmetic.rs:100:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:94:5 + --> $DIR/integer_arithmetic.rs:104:5 | LL | x + y | ^^^^^ error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:98:5 + --> $DIR/integer_arithmetic.rs:108:5 | LL | (&x + &y) | ^^^^^^^^^ -error: aborting due to 21 previous errors +error: aborting due to 27 previous errors diff --git a/tests/ui/item_after_statement.rs b/tests/ui/item_after_statement.rs index c17a7cbc8d905..377e58e441749 100644 --- a/tests/ui/item_after_statement.rs +++ b/tests/ui/item_after_statement.rs @@ -28,7 +28,10 @@ fn mac() { // do not lint this, because it needs to be after `a` macro_rules! b { () => {{ - a = 6 + a = 6; + fn say_something() { + println!("something"); + } }}; } b!(); diff --git a/tests/ui/item_after_statement.stderr b/tests/ui/item_after_statement.stderr index f8f010b5e5c1f..68a3c81b6a804 100644 --- a/tests/ui/item_after_statement.stderr +++ b/tests/ui/item_after_statement.stderr @@ -16,5 +16,18 @@ LL | | println!("foo"); LL | | } | |_____^ -error: aborting due to 2 previous errors +error: adding items after statements is confusing, since items exist from the start of the scope + --> $DIR/item_after_statement.rs:32:13 + | +LL | / fn say_something() { +LL | | println!("something"); +LL | | } + | |_____________^ +... +LL | b!(); + | ----- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors diff --git a/tests/ui/iter_skip_next.stderr b/tests/ui/iter_skip_next.stderr index feedc2f288a2b..486de718bb563 100644 --- a/tests/ui/iter_skip_next.stderr +++ b/tests/ui/iter_skip_next.stderr @@ -1,4 +1,4 @@ -error: called `skip(x).next()` on an iterator +error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:15:28 | LL | let _ = some_vec.iter().skip(42).next(); @@ -6,19 +6,19 @@ LL | let _ = some_vec.iter().skip(42).next(); | = note: `-D clippy::iter-skip-next` implied by `-D warnings` -error: called `skip(x).next()` on an iterator +error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:16:36 | LL | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` -error: called `skip(x).next()` on an iterator +error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:17:20 | LL | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)` -error: called `skip(x).next()` on an iterator +error: called `skip(..).next()` on an iterator --> $DIR/iter_skip_next.rs:18:33 | LL | let _ = &some_vec[..].iter().skip(3).next(); diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed new file mode 100644 index 0000000000000..b42e94bd727de --- /dev/null +++ b/tests/ui/manual_ok_or.fixed @@ -0,0 +1,40 @@ +// run-rustfix +#![warn(clippy::manual_ok_or)] +#![allow(clippy::blacklisted_name)] +#![allow(clippy::redundant_closure)] +#![allow(dead_code)] +#![allow(unused_must_use)] + +fn main() { + // basic case + let foo: Option = None; + foo.ok_or("error"); + + // eta expansion case + foo.ok_or("error"); + + // turbo fish syntax + None::.ok_or("error"); + + // multiline case + #[rustfmt::skip] + foo.ok_or(&format!( + "{}{}{}{}{}{}{}", + "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer")); + + // not applicable, closure isn't direct `Ok` wrapping + foo.map_or(Err("error"), |v| Ok(v + 1)); + + // not applicable, or side isn't `Result::Err` + foo.map_or(Ok::(1), |v| Ok(v)); + + // not applicatble, expr is not a `Result` value + foo.map_or(42, |v| v); + + // TODO patterns not covered yet + match foo { + Some(v) => Ok(v), + None => Err("error"), + }; + foo.map_or_else(|| Err("error"), |v| Ok(v)); +} diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs new file mode 100644 index 0000000000000..e5a6056fbf5cc --- /dev/null +++ b/tests/ui/manual_ok_or.rs @@ -0,0 +1,44 @@ +// run-rustfix +#![warn(clippy::manual_ok_or)] +#![allow(clippy::blacklisted_name)] +#![allow(clippy::redundant_closure)] +#![allow(dead_code)] +#![allow(unused_must_use)] + +fn main() { + // basic case + let foo: Option = None; + foo.map_or(Err("error"), |v| Ok(v)); + + // eta expansion case + foo.map_or(Err("error"), Ok); + + // turbo fish syntax + None::.map_or(Err("error"), |v| Ok(v)); + + // multiline case + #[rustfmt::skip] + foo.map_or(Err::( + &format!( + "{}{}{}{}{}{}{}", + "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer") + ), + |v| Ok(v), + ); + + // not applicable, closure isn't direct `Ok` wrapping + foo.map_or(Err("error"), |v| Ok(v + 1)); + + // not applicable, or side isn't `Result::Err` + foo.map_or(Ok::(1), |v| Ok(v)); + + // not applicatble, expr is not a `Result` value + foo.map_or(42, |v| v); + + // TODO patterns not covered yet + match foo { + Some(v) => Ok(v), + None => Err("error"), + }; + foo.map_or_else(|| Err("error"), |v| Ok(v)); +} diff --git a/tests/ui/manual_ok_or.stderr b/tests/ui/manual_ok_or.stderr new file mode 100644 index 0000000000000..8ea10ac543636 --- /dev/null +++ b/tests/ui/manual_ok_or.stderr @@ -0,0 +1,41 @@ +error: this pattern reimplements `Option::ok_or` + --> $DIR/manual_ok_or.rs:11:5 + | +LL | foo.map_or(Err("error"), |v| Ok(v)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")` + | + = note: `-D clippy::manual-ok-or` implied by `-D warnings` + +error: this pattern reimplements `Option::ok_or` + --> $DIR/manual_ok_or.rs:14:5 + | +LL | foo.map_or(Err("error"), Ok); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")` + +error: this pattern reimplements `Option::ok_or` + --> $DIR/manual_ok_or.rs:17:5 + | +LL | None::.map_or(Err("error"), |v| Ok(v)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `None::.ok_or("error")` + +error: this pattern reimplements `Option::ok_or` + --> $DIR/manual_ok_or.rs:21:5 + | +LL | / foo.map_or(Err::( +LL | | &format!( +LL | | "{}{}{}{}{}{}{}", +LL | | "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer") +LL | | ), +LL | | |v| Ok(v), +LL | | ); + | |_____^ + | +help: replace with + | +LL | foo.ok_or(&format!( +LL | "{}{}{}{}{}{}{}", +LL | "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer")); + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/map_collect_result_unit.fixed b/tests/ui/map_collect_result_unit.fixed new file mode 100644 index 0000000000000..e66c9cc24207a --- /dev/null +++ b/tests/ui/map_collect_result_unit.fixed @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::map_collect_result_unit)] + +fn main() { + { + let _ = (0..3).try_for_each(|t| Err(t + 1)); + let _: Result<(), _> = (0..3).try_for_each(|t| Err(t + 1)); + + let _ = (0..3).try_for_each(|t| Err(t + 1)); + } +} + +fn _ignore() { + let _ = (0..3).map(|t| Err(t + 1)).collect::, _>>(); + let _ = (0..3).map(|t| Err(t + 1)).collect::>>(); +} diff --git a/tests/ui/map_collect_result_unit.rs b/tests/ui/map_collect_result_unit.rs new file mode 100644 index 0000000000000..6f08f4c3c5354 --- /dev/null +++ b/tests/ui/map_collect_result_unit.rs @@ -0,0 +1,16 @@ +// run-rustfix +#![warn(clippy::map_collect_result_unit)] + +fn main() { + { + let _ = (0..3).map(|t| Err(t + 1)).collect::>(); + let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); + + let _ = (0..3).try_for_each(|t| Err(t + 1)); + } +} + +fn _ignore() { + let _ = (0..3).map(|t| Err(t + 1)).collect::, _>>(); + let _ = (0..3).map(|t| Err(t + 1)).collect::>>(); +} diff --git a/tests/ui/map_collect_result_unit.stderr b/tests/ui/map_collect_result_unit.stderr new file mode 100644 index 0000000000000..8b06e13baa6b4 --- /dev/null +++ b/tests/ui/map_collect_result_unit.stderr @@ -0,0 +1,16 @@ +error: `.map().collect()` can be replaced with `.try_for_each()` + --> $DIR/map_collect_result_unit.rs:6:17 + | +LL | let _ = (0..3).map(|t| Err(t + 1)).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))` + | + = note: `-D clippy::map-collect-result-unit` implied by `-D warnings` + +error: `.map().collect()` can be replaced with `.try_for_each()` + --> $DIR/map_collect_result_unit.rs:7:32 + | +LL | let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/map_unwrap_or.rs b/tests/ui/map_unwrap_or.rs index 585944032e70d..87e16f5d09bd7 100644 --- a/tests/ui/map_unwrap_or.rs +++ b/tests/ui/map_unwrap_or.rs @@ -1,4 +1,3 @@ -// FIXME: Add "run-rustfix" once it's supported for multipart suggestions // aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] @@ -47,10 +46,6 @@ fn option_methods() { let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); // Check for `option.map(_).unwrap_or_else(_)` use. - // single line case - let _ = opt.map(|x| x + 1) - // Should lint even though this call is on a separate line. - .unwrap_or_else(|| 0); // Multi-line cases. let _ = opt.map(|x| { x + 1 @@ -60,37 +55,24 @@ fn option_methods() { .unwrap_or_else(|| 0 ); - // Macro case. - // Should not lint. - let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); - - // Issue #4144 - { - let mut frequencies = HashMap::new(); - let word = "foo"; - - frequencies - .get_mut(word) - .map(|count| { - *count += 1; - }) - .unwrap_or_else(|| { - frequencies.insert(word.to_owned(), 1); - }); - } } +#[rustfmt::skip] fn result_methods() { let res: Result = Ok(1); // Check for `result.map(_).unwrap_or_else(_)` use. - // single line case - let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line - // multi line cases - let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); + // multi line cases + let _ = res.map(|x| { + x + 1 + } + ).unwrap_or_else(|_e| 0); + let _ = res.map(|x| x + 1) + .unwrap_or_else(|_e| { + 0 + }); // macro case - let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|e| 0); // should not lint + let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint } fn main() { diff --git a/tests/ui/map_unwrap_or.stderr b/tests/ui/map_unwrap_or.stderr index b62080a073f35..96b9d6cc3c145 100644 --- a/tests/ui/map_unwrap_or.stderr +++ b/tests/ui/map_unwrap_or.stderr @@ -1,5 +1,5 @@ -error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/map_unwrap_or.rs:17:13 +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead + --> $DIR/map_unwrap_or.rs:16:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -8,13 +8,13 @@ LL | | .unwrap_or(0); | |_____________________^ | = note: `-D clippy::map-unwrap-or` implied by `-D warnings` -help: use `map_or(a, f)` instead +help: use `map_or(, )` instead | LL | let _ = opt.map_or(0, |x| x + 1); | ^^^^^^ ^^ -- -error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/map_unwrap_or.rs:21:13 +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead + --> $DIR/map_unwrap_or.rs:20:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -23,7 +23,7 @@ LL | | } LL | | ).unwrap_or(0); | |__________________^ | -help: use `map_or(a, f)` instead +help: use `map_or(, )` instead | LL | let _ = opt.map_or(0, |x| { LL | x + 1 @@ -31,8 +31,8 @@ LL | } LL | ); | -error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/map_unwrap_or.rs:25:13 +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead + --> $DIR/map_unwrap_or.rs:24:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -41,26 +41,26 @@ LL | | 0 LL | | }); | |__________^ | -help: use `map_or(a, f)` instead +help: use `map_or(, )` instead | LL | let _ = opt.map_or({ LL | 0 LL | }, |x| x + 1); | -error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/map_unwrap_or.rs:30:13 +error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead + --> $DIR/map_unwrap_or.rs:29:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `and_then(f)` instead +help: use `and_then()` instead | LL | let _ = opt.and_then(|x| Some(x + 1)); | ^^^^^^^^ -- -error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/map_unwrap_or.rs:32:13 +error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead + --> $DIR/map_unwrap_or.rs:31:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -69,7 +69,7 @@ LL | | } LL | | ).unwrap_or(None); | |_____________________^ | -help: use `and_then(f)` instead +help: use `and_then()` instead | LL | let _ = opt.and_then(|x| { LL | Some(x + 1) @@ -77,8 +77,8 @@ LL | } LL | ); | -error: called `map(f).unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead - --> $DIR/map_unwrap_or.rs:36:13 +error: called `map().unwrap_or(None)` on an `Option` value. This can be done more directly by calling `and_then()` instead + --> $DIR/map_unwrap_or.rs:35:13 | LL | let _ = opt | _____________^ @@ -86,35 +86,24 @@ LL | | .map(|x| Some(x + 1)) LL | | .unwrap_or(None); | |________________________^ | -help: use `and_then(f)` instead +help: use `and_then()` instead | LL | .and_then(|x| Some(x + 1)); | ^^^^^^^^ -- -error: called `map(f).unwrap_or(a)` on an `Option` value. This can be done more directly by calling `map_or(a, f)` instead - --> $DIR/map_unwrap_or.rs:47:13 +error: called `map().unwrap_or()` on an `Option` value. This can be done more directly by calling `map_or(, )` instead + --> $DIR/map_unwrap_or.rs:46:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: use `map_or(a, f)` instead +help: use `map_or(, )` instead | LL | let _ = Some("prefix").map_or(id, |p| format!("{}.", p)); | ^^^^^^ ^^^ -- -error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/map_unwrap_or.rs:51:13 - | -LL | let _ = opt.map(|x| x + 1) - | _____________^ -LL | | // Should lint even though this call is on a separate line. -LL | | .unwrap_or_else(|| 0); - | |_____________________________^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|| 0)` with `map_or_else(|| 0, |x| x + 1)` - -error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/map_unwrap_or.rs:55:13 +error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead + --> $DIR/map_unwrap_or.rs:50:13 | LL | let _ = opt.map(|x| { | _____________^ @@ -123,8 +112,8 @@ LL | | } LL | | ).unwrap_or_else(|| 0); | |__________________________^ -error: called `map(f).unwrap_or_else(g)` on an `Option` value. This can be done more directly by calling `map_or_else(g, f)` instead - --> $DIR/map_unwrap_or.rs:59:13 +error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead + --> $DIR/map_unwrap_or.rs:54:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ @@ -133,29 +122,25 @@ LL | | 0 LL | | ); | |_________^ -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead - --> $DIR/map_unwrap_or.rs:88:13 +error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead + --> $DIR/map_unwrap_or.rs:66:13 | -LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); // should lint even though this call is on a separate line - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` - -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead - --> $DIR/map_unwrap_or.rs:90:13 - | -LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` +LL | let _ = res.map(|x| { + | _____________^ +LL | | x + 1 +LL | | } +LL | | ).unwrap_or_else(|_e| 0); + | |____________________________^ -error: called `map(f).unwrap_or_else(g)` on a `Result` value. This can be done more directly by calling `.map_or_else(g, f)` instead - --> $DIR/map_unwrap_or.rs:91:13 - | -LL | let _ = res.map(|x| x + 1).unwrap_or_else(|e| 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead + --> $DIR/map_unwrap_or.rs:70:13 | - = note: replace `map(|x| x + 1).unwrap_or_else(|e| 0)` with `map_or_else(|e| 0, |x| x + 1)` +LL | let _ = res.map(|x| x + 1) + | _____________^ +LL | | .unwrap_or_else(|_e| { +LL | | 0 +LL | | }); + | |__________^ -error: aborting due to 13 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/map_unwrap_or_fixable.fixed b/tests/ui/map_unwrap_or_fixable.fixed new file mode 100644 index 0000000000000..bd5b4f7165a4e --- /dev/null +++ b/tests/ui/map_unwrap_or_fixable.fixed @@ -0,0 +1,54 @@ +// run-rustfix +// aux-build:option_helpers.rs + +#![warn(clippy::map_unwrap_or)] + +#[macro_use] +extern crate option_helpers; + +use std::collections::HashMap; + +#[rustfmt::skip] +fn option_methods() { + let opt = Some(1); + + // Check for `option.map(_).unwrap_or_else(_)` use. + // single line case + let _ = opt.map_or_else(|| 0, |x| x + 1); + + // Macro case. + // Should not lint. + let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); + + // Issue #4144 + { + let mut frequencies = HashMap::new(); + let word = "foo"; + + frequencies + .get_mut(word) + .map(|count| { + *count += 1; + }) + .unwrap_or_else(|| { + frequencies.insert(word.to_owned(), 1); + }); + } +} + +#[rustfmt::skip] +fn result_methods() { + let res: Result = Ok(1); + + // Check for `result.map(_).unwrap_or_else(_)` use. + // single line case + let _ = res.map_or_else(|_e| 0, |x| x + 1); + + // macro case + let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint +} + +fn main() { + option_methods(); + result_methods(); +} diff --git a/tests/ui/map_unwrap_or_fixable.rs b/tests/ui/map_unwrap_or_fixable.rs new file mode 100644 index 0000000000000..0b892caf20e82 --- /dev/null +++ b/tests/ui/map_unwrap_or_fixable.rs @@ -0,0 +1,58 @@ +// run-rustfix +// aux-build:option_helpers.rs + +#![warn(clippy::map_unwrap_or)] + +#[macro_use] +extern crate option_helpers; + +use std::collections::HashMap; + +#[rustfmt::skip] +fn option_methods() { + let opt = Some(1); + + // Check for `option.map(_).unwrap_or_else(_)` use. + // single line case + let _ = opt.map(|x| x + 1) + // Should lint even though this call is on a separate line. + .unwrap_or_else(|| 0); + + // Macro case. + // Should not lint. + let _ = opt_map!(opt, |x| x + 1).unwrap_or_else(|| 0); + + // Issue #4144 + { + let mut frequencies = HashMap::new(); + let word = "foo"; + + frequencies + .get_mut(word) + .map(|count| { + *count += 1; + }) + .unwrap_or_else(|| { + frequencies.insert(word.to_owned(), 1); + }); + } +} + +#[rustfmt::skip] +fn result_methods() { + let res: Result = Ok(1); + + // Check for `result.map(_).unwrap_or_else(_)` use. + // single line case + let _ = res.map(|x| x + 1) + // should lint even though this call is on a separate line + .unwrap_or_else(|_e| 0); + + // macro case + let _ = opt_map!(res, |x| x + 1).unwrap_or_else(|_e| 0); // should not lint +} + +fn main() { + option_methods(); + result_methods(); +} diff --git a/tests/ui/map_unwrap_or_fixable.stderr b/tests/ui/map_unwrap_or_fixable.stderr new file mode 100644 index 0000000000000..1837bc2ca3b8b --- /dev/null +++ b/tests/ui/map_unwrap_or_fixable.stderr @@ -0,0 +1,22 @@ +error: called `map().unwrap_or_else()` on an `Option` value. This can be done more directly by calling `map_or_else(, )` instead + --> $DIR/map_unwrap_or_fixable.rs:17:13 + | +LL | let _ = opt.map(|x| x + 1) + | _____________^ +LL | | // Should lint even though this call is on a separate line. +LL | | .unwrap_or_else(|| 0); + | |_____________________________^ help: try this: `opt.map_or_else(|| 0, |x| x + 1)` + | + = note: `-D clippy::map-unwrap-or` implied by `-D warnings` + +error: called `map().unwrap_or_else()` on a `Result` value. This can be done more directly by calling `.map_or_else(, )` instead + --> $DIR/map_unwrap_or_fixable.rs:47:13 + | +LL | let _ = res.map(|x| x + 1) + | _____________^ +LL | | // should lint even though this call is on a separate line +LL | | .unwrap_or_else(|_e| 0); + | |_______________________________^ help: try this: `res.map_or_else(|_e| 0, |x| x + 1)` + +error: aborting due to 2 previous errors + diff --git a/tests/ui/match_type_on_diag_item.stderr b/tests/ui/match_type_on_diag_item.stderr index 5e5fe9e3a3e73..82465dbaf6ecc 100644 --- a/tests/ui/match_type_on_diag_item.stderr +++ b/tests/ui/match_type_on_diag_item.stderr @@ -2,7 +2,7 @@ error: usage of `utils::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:41:17 | LL | let _ = match_type(cx, ty, &paths::VEC); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(vec_type))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::vec_type)` | note: the lint level is defined here --> $DIR/match_type_on_diag_item.rs:1:9 @@ -15,19 +15,19 @@ error: usage of `utils::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:42:17 | LL | let _ = match_type(cx, ty, &OPTION); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(option_type))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::option_type)` error: usage of `utils::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:43:17 | LL | let _ = match_type(cx, ty, &["core", "result", "Result"]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(result_type))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::result_type)` error: usage of `utils::match_type()` on a type diagnostic item --> $DIR/match_type_on_diag_item.rs:46:17 | LL | let _ = utils::match_type(cx, ty, rc_path); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym!(Rc))` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `utils::is_type_diagnostic_item(cx, ty, sym::Rc)` error: aborting due to 4 previous errors diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 80dd2f744b3a1..d93e5b114ecfa 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -122,16 +122,13 @@ impl Mul for T { fn filter_next() { let v = vec![3, 2, 1, 0, -1, -2, -3]; - // Single-line case. - let _ = v.iter().filter(|&x| *x < 0).next(); - // Multi-line case. let _ = v.iter().filter(|&x| { *x < 0 } ).next(); - // Check that hat we don't lint if the caller is not an `Iterator`. + // Check that we don't lint if the caller is not an `Iterator`. let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.filter().next(); } diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 2a0a43e83a653..8a281c2dbd25c 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -8,27 +8,20 @@ LL | | } | = note: `-D clippy::new-ret-no-self` implied by `-D warnings` -error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead. --> $DIR/methods.rs:126:13 | -LL | let _ = v.iter().filter(|&x| *x < 0).next(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::filter-next` implied by `-D warnings` - = note: replace `filter(|&x| *x < 0).next()` with `find(|&x| *x < 0)` - -error: called `filter(p).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(p)` instead. - --> $DIR/methods.rs:129:13 - | LL | let _ = v.iter().filter(|&x| { | _____________^ LL | | *x < 0 LL | | } LL | | ).next(); | |___________________________^ + | + = note: `-D clippy::filter-next` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:146:22 + --> $DIR/methods.rs:143:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` @@ -36,25 +29,25 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = note: `-D clippy::search-is-some` implied by `-D warnings` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:147:20 + --> $DIR/methods.rs:144:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:148:20 + --> $DIR/methods.rs:145:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:149:22 + --> $DIR/methods.rs:146:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:152:13 + --> $DIR/methods.rs:149:13 | LL | let _ = v.iter().find(|&x| { | _____________^ @@ -64,13 +57,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:158:22 + --> $DIR/methods.rs:155:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:161:13 + --> $DIR/methods.rs:158:13 | LL | let _ = v.iter().position(|&x| { | _____________^ @@ -80,13 +73,13 @@ LL | | ).is_some(); | |______________________________^ error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:167:22 + --> $DIR/methods.rs:164:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:170:13 + --> $DIR/methods.rs:167:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ @@ -95,5 +88,5 @@ LL | | } LL | | ).is_some(); | |______________________________^ -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/methods_fixable.fixed b/tests/ui/methods_fixable.fixed new file mode 100644 index 0000000000000..ee7c1b0da6d97 --- /dev/null +++ b/tests/ui/methods_fixable.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +#![warn(clippy::filter_next)] + +/// Checks implementation of `FILTER_NEXT` lint. +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + + // Single-line case. + let _ = v.iter().find(|&x| *x < 0); +} diff --git a/tests/ui/methods_fixable.rs b/tests/ui/methods_fixable.rs new file mode 100644 index 0000000000000..6d0f1b7bd5147 --- /dev/null +++ b/tests/ui/methods_fixable.rs @@ -0,0 +1,11 @@ +// run-rustfix + +#![warn(clippy::filter_next)] + +/// Checks implementation of `FILTER_NEXT` lint. +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + + // Single-line case. + let _ = v.iter().filter(|&x| *x < 0).next(); +} diff --git a/tests/ui/methods_fixable.stderr b/tests/ui/methods_fixable.stderr new file mode 100644 index 0000000000000..70e7c3dea545b --- /dev/null +++ b/tests/ui/methods_fixable.stderr @@ -0,0 +1,10 @@ +error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead. + --> $DIR/methods_fixable.rs:10:13 + | +LL | let _ = v.iter().filter(|&x| *x < 0).next(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `v.iter().find(|&x| *x < 0)` + | + = note: `-D clippy::filter-next` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/tests/ui/option_if_let_else.fixed b/tests/ui/option_if_let_else.fixed index a7fb00a270577..47e7460fa7a44 100644 --- a/tests/ui/option_if_let_else.fixed +++ b/tests/ui/option_if_let_else.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure)] +#![allow(clippy::ref_option_ref)] fn bad1(string: Option<&str>) -> (bool, &str) { string.map_or((false, "hello"), |x| (true, x)) diff --git a/tests/ui/option_if_let_else.rs b/tests/ui/option_if_let_else.rs index 895fd86321faf..e2f8dec3b930c 100644 --- a/tests/ui/option_if_let_else.rs +++ b/tests/ui/option_if_let_else.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::option_if_let_else)] #![allow(clippy::redundant_closure)] +#![allow(clippy::ref_option_ref)] fn bad1(string: Option<&str>) -> (bool, &str) { if let Some(x) = string { diff --git a/tests/ui/option_if_let_else.stderr b/tests/ui/option_if_let_else.stderr index b69fe76768270..7aab068800a02 100644 --- a/tests/ui/option_if_let_else.stderr +++ b/tests/ui/option_if_let_else.stderr @@ -1,5 +1,5 @@ error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:6:5 + --> $DIR/option_if_let_else.rs:7:5 | LL | / if let Some(x) = string { LL | | (true, x) @@ -11,7 +11,7 @@ LL | | } = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:16:12 + --> $DIR/option_if_let_else.rs:17:12 | LL | } else if let Some(x) = string { | ____________^ @@ -22,19 +22,19 @@ LL | | } | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:24:13 + --> $DIR/option_if_let_else.rs:25:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:25:13 + --> $DIR/option_if_let_else.rs:26:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:26:13 + --> $DIR/option_if_let_else.rs:27:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ @@ -54,13 +54,13 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:32:13 + --> $DIR/option_if_let_else.rs:33:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:33:13 + --> $DIR/option_if_let_else.rs:34:13 | LL | let _ = if let Some(mut s) = num { | _____________^ @@ -80,7 +80,7 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:39:13 + --> $DIR/option_if_let_else.rs:40:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ @@ -100,7 +100,7 @@ LL | }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:48:5 + --> $DIR/option_if_let_else.rs:49:5 | LL | / if let Some(x) = arg { LL | | let y = x * x; @@ -119,7 +119,7 @@ LL | }) | error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:61:13 + --> $DIR/option_if_let_else.rs:62:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -131,7 +131,7 @@ LL | | }; | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)` error: use Option::map_or_else instead of an if let/else - --> $DIR/option_if_let_else.rs:70:13 + --> $DIR/option_if_let_else.rs:71:13 | LL | let _ = if let Some(x) = arg { | _____________^ @@ -154,7 +154,7 @@ LL | }, |x| x * x * x * x); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:99:13 + --> $DIR/option_if_let_else.rs:100:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` diff --git a/tests/ui/option_map_or_none.stderr b/tests/ui/option_map_or_none.stderr index 6f707987dbcaa..1cba29412b872 100644 --- a/tests/ui/option_map_or_none.stderr +++ b/tests/ui/option_map_or_none.stderr @@ -1,4 +1,4 @@ -error: called `map_or(None, f)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead +error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead --> $DIR/option_map_or_none.rs:10:13 | LL | let _ = opt.map_or(None, |x| Some(x + 1)); @@ -6,7 +6,7 @@ LL | let _ = opt.map_or(None, |x| Some(x + 1)); | = note: `-D clippy::option-map-or-none` implied by `-D warnings` -error: called `map_or(None, f)` on an `Option` value. This can be done more directly by calling `and_then(f)` instead +error: called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling `and_then(..)` instead --> $DIR/option_map_or_none.rs:13:13 | LL | let _ = opt.map_or(None, |x| { diff --git a/tests/ui/ref_option_ref.rs b/tests/ui/ref_option_ref.rs new file mode 100644 index 0000000000000..b2c275d68afa1 --- /dev/null +++ b/tests/ui/ref_option_ref.rs @@ -0,0 +1,47 @@ +#![allow(unused)] +#![warn(clippy::ref_option_ref)] + +// This lint is not tagged as run-rustfix because automatically +// changing the type of a variable would also means changing +// all usages of this variable to match and This is not handled +// by this lint. + +static THRESHOLD: i32 = 10; +static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD); +const CONST_THRESHOLD: &i32 = &10; +const REF_CONST: &Option<&i32> = &Some(&CONST_THRESHOLD); + +type RefOptRefU32<'a> = &'a Option<&'a u32>; +type RefOptRef<'a, T> = &'a Option<&'a T>; + +fn foo(data: &Option<&u32>) {} + +fn bar(data: &u32) -> &Option<&u32> { + &None +} + +struct StructRef<'a> { + data: &'a Option<&'a u32>, +} + +struct StructTupleRef<'a>(u32, &'a Option<&'a u32>); + +enum EnumRef<'a> { + Variant1(u32), + Variant2(&'a Option<&'a u32>), +} + +trait RefOptTrait { + type A; + fn foo(&self, _: Self::A); +} + +impl RefOptTrait for u32 { + type A = &'static Option<&'static Self>; + + fn foo(&self, _: Self::A) {} +} + +fn main() { + let x: &Option<&u32> = &None; +} diff --git a/tests/ui/ref_option_ref.stderr b/tests/ui/ref_option_ref.stderr new file mode 100644 index 0000000000000..4e7fc80006118 --- /dev/null +++ b/tests/ui/ref_option_ref.stderr @@ -0,0 +1,70 @@ +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:10:23 + | +LL | static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD); + | ^^^^^^^^^^^^^ help: try: `Option<&i32>` + | + = note: `-D clippy::ref-option-ref` implied by `-D warnings` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:12:18 + | +LL | const REF_CONST: &Option<&i32> = &Some(&CONST_THRESHOLD); + | ^^^^^^^^^^^^^ help: try: `Option<&i32>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:14:25 + | +LL | type RefOptRefU32<'a> = &'a Option<&'a u32>; + | ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:15:25 + | +LL | type RefOptRef<'a, T> = &'a Option<&'a T>; + | ^^^^^^^^^^^^^^^^^ help: try: `Option<&'a T>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:17:14 + | +LL | fn foo(data: &Option<&u32>) {} + | ^^^^^^^^^^^^^ help: try: `Option<&u32>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:19:23 + | +LL | fn bar(data: &u32) -> &Option<&u32> { + | ^^^^^^^^^^^^^ help: try: `Option<&u32>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:24:11 + | +LL | data: &'a Option<&'a u32>, + | ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:27:32 + | +LL | struct StructTupleRef<'a>(u32, &'a Option<&'a u32>); + | ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:31:14 + | +LL | Variant2(&'a Option<&'a u32>), + | ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:40:14 + | +LL | type A = &'static Option<&'static Self>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'static Self>` + +error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` + --> $DIR/ref_option_ref.rs:46:12 + | +LL | let x: &Option<&u32> = &None; + | ^^^^^^^^^^^^^ help: try: `Option<&u32>` + +error: aborting due to 11 previous errors + diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed new file mode 100644 index 0000000000000..63a6d37a9cce9 --- /dev/null +++ b/tests/ui/single_char_add_str.fixed @@ -0,0 +1,45 @@ +// run-rustfix +#![warn(clippy::single_char_add_str)] + +macro_rules! get_string { + () => { + String::from("Hello world!") + }; +} + +fn main() { + // `push_str` tests + + let mut string = String::new(); + string.push('R'); + string.push('\''); + + string.push('u'); + string.push_str("st"); + string.push_str(""); + string.push('\x52'); + string.push('\u{0052}'); + string.push('a'); + + get_string!().push('ö'); + + // `insert_str` tests + + let mut string = String::new(); + string.insert(0, 'R'); + string.insert(1, '\''); + + string.insert(0, 'u'); + string.insert_str(2, "st"); + string.insert_str(0, ""); + string.insert(0, '\x52'); + string.insert(0, '\u{0052}'); + let x: usize = 2; + string.insert(x, 'a'); + const Y: usize = 1; + string.insert(Y, 'a'); + string.insert(Y, '"'); + string.insert(Y, '\''); + + get_string!().insert(1, '?'); +} diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs new file mode 100644 index 0000000000000..a799ea7d88564 --- /dev/null +++ b/tests/ui/single_char_add_str.rs @@ -0,0 +1,45 @@ +// run-rustfix +#![warn(clippy::single_char_add_str)] + +macro_rules! get_string { + () => { + String::from("Hello world!") + }; +} + +fn main() { + // `push_str` tests + + let mut string = String::new(); + string.push_str("R"); + string.push_str("'"); + + string.push('u'); + string.push_str("st"); + string.push_str(""); + string.push_str("\x52"); + string.push_str("\u{0052}"); + string.push_str(r##"a"##); + + get_string!().push_str("ö"); + + // `insert_str` tests + + let mut string = String::new(); + string.insert_str(0, "R"); + string.insert_str(1, "'"); + + string.insert(0, 'u'); + string.insert_str(2, "st"); + string.insert_str(0, ""); + string.insert_str(0, "\x52"); + string.insert_str(0, "\u{0052}"); + let x: usize = 2; + string.insert_str(x, r##"a"##); + const Y: usize = 1; + string.insert_str(Y, r##"a"##); + string.insert_str(Y, r##"""##); + string.insert_str(Y, r##"'"##); + + get_string!().insert_str(1, "?"); +} diff --git a/tests/ui/single_char_add_str.stderr b/tests/ui/single_char_add_str.stderr new file mode 100644 index 0000000000000..55d91583ad04d --- /dev/null +++ b/tests/ui/single_char_add_str.stderr @@ -0,0 +1,94 @@ +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:14:5 + | +LL | string.push_str("R"); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')` + | + = note: `-D clippy::single-char-add-str` implied by `-D warnings` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:15:5 + | +LL | string.push_str("'"); + | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:20:5 + | +LL | string.push_str("/x52"); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:21:5 + | +LL | string.push_str("/u{0052}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:22:5 + | +LL | string.push_str(r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` + +error: calling `push_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:24:5 + | +LL | get_string!().push_str("ö"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:29:5 + | +LL | string.insert_str(0, "R"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:30:5 + | +LL | string.insert_str(1, "'"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:35:5 + | +LL | string.insert_str(0, "/x52"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:36:5 + | +LL | string.insert_str(0, "/u{0052}"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:38:5 + | +LL | string.insert_str(x, r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:40:5 + | +LL | string.insert_str(Y, r##"a"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:41:5 + | +LL | string.insert_str(Y, r##"""##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:42:5 + | +LL | string.insert_str(Y, r##"'"##); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '/'')` + +error: calling `insert_str()` using a single-character string literal + --> $DIR/single_char_add_str.rs:44:5 + | +LL | get_string!().insert_str(1, "?"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` + +error: aborting due to 15 previous errors + diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed index 3871c4f2268cc..d8b5f19e144dc 100644 --- a/tests/ui/single_char_pattern.fixed +++ b/tests/ui/single_char_pattern.fixed @@ -12,15 +12,9 @@ fn main() { let y = "x"; x.split(y); - // Not yet testing for multi-byte characters - // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_clippy::single_char_pattern` - // should have done this but produced an ICE - // - // We may not want to suggest changing these anyway - // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984 - x.split("ß"); - x.split("ℝ"); - x.split("💣"); + x.split('ß'); + x.split('ℝ'); + x.split('💣'); // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); x.contains('x'); diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs index 32afe339cd81c..a7bc73e3756df 100644 --- a/tests/ui/single_char_pattern.rs +++ b/tests/ui/single_char_pattern.rs @@ -12,12 +12,6 @@ fn main() { let y = "x"; x.split(y); - // Not yet testing for multi-byte characters - // Changing `r.len() == 1` to `r.chars().count() == 1` in `lint_clippy::single_char_pattern` - // should have done this but produced an ICE - // - // We may not want to suggest changing these anyway - // See: https://github.com/rust-lang/rust-clippy/issues/650#issuecomment-184328984 x.split("ß"); x.split("ℝ"); x.split("💣"); diff --git a/tests/ui/single_char_pattern.stderr b/tests/ui/single_char_pattern.stderr index fe7211c53f852..ee4e7e50efd17 100644 --- a/tests/ui/single_char_pattern.stderr +++ b/tests/ui/single_char_pattern.stderr @@ -7,160 +7,178 @@ LL | x.split("x"); = note: `-D clippy::single-char-pattern` implied by `-D warnings` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:26:16 + --> $DIR/single_char_pattern.rs:15:13 + | +LL | x.split("ß"); + | ^^^ help: try using a `char` instead: `'ß'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:16:13 + | +LL | x.split("ℝ"); + | ^^^ help: try using a `char` instead: `'ℝ'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:17:13 + | +LL | x.split("💣"); + | ^^^^ help: try using a `char` instead: `'💣'` + +error: single-character string constant used as pattern + --> $DIR/single_char_pattern.rs:20:16 | LL | x.contains("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:27:19 + --> $DIR/single_char_pattern.rs:21:19 | LL | x.starts_with("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:28:17 + --> $DIR/single_char_pattern.rs:22:17 | LL | x.ends_with("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:29:12 + --> $DIR/single_char_pattern.rs:23:12 | LL | x.find("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:30:13 + --> $DIR/single_char_pattern.rs:24:13 | LL | x.rfind("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:31:14 + --> $DIR/single_char_pattern.rs:25:14 | LL | x.rsplit("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:32:24 + --> $DIR/single_char_pattern.rs:26:24 | LL | x.split_terminator("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:33:25 + --> $DIR/single_char_pattern.rs:27:25 | LL | x.rsplit_terminator("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:34:17 + --> $DIR/single_char_pattern.rs:28:17 | LL | x.splitn(0, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:35:18 + --> $DIR/single_char_pattern.rs:29:18 | LL | x.rsplitn(0, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:36:15 + --> $DIR/single_char_pattern.rs:30:15 | LL | x.matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:37:16 + --> $DIR/single_char_pattern.rs:31:16 | LL | x.rmatches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:38:21 + --> $DIR/single_char_pattern.rs:32:21 | LL | x.match_indices("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:39:22 + --> $DIR/single_char_pattern.rs:33:22 | LL | x.rmatch_indices("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:40:26 + --> $DIR/single_char_pattern.rs:34:26 | LL | x.trim_start_matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:41:24 + --> $DIR/single_char_pattern.rs:35:24 | LL | x.trim_end_matches("x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:43:13 + --> $DIR/single_char_pattern.rs:37:13 | LL | x.split("/n"); | ^^^^ help: try using a `char` instead: `'/n'` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:44:13 + --> $DIR/single_char_pattern.rs:38:13 | LL | x.split("'"); | ^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:45:13 + --> $DIR/single_char_pattern.rs:39:13 | LL | x.split("/'"); | ^^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:50:31 + --> $DIR/single_char_pattern.rs:44: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:51:19 + --> $DIR/single_char_pattern.rs:45: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:58:13 + --> $DIR/single_char_pattern.rs:52: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:53: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:54: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:61:13 + --> $DIR/single_char_pattern.rs:55:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: try using a `char` instead: `'/''` error: single-character string constant used as pattern - --> $DIR/single_char_pattern.rs:62:13 + --> $DIR/single_char_pattern.rs:56:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: try using a `char` instead: `'#'` -error: aborting due to 27 previous errors +error: aborting due to 30 previous errors diff --git a/tests/ui/single_char_push_str.fixed b/tests/ui/single_char_push_str.fixed deleted file mode 100644 index 0812c026a644f..0000000000000 --- a/tests/ui/single_char_push_str.fixed +++ /dev/null @@ -1,15 +0,0 @@ -// run-rustfix -#![warn(clippy::single_char_push_str)] - -fn main() { - let mut string = String::new(); - string.push('R'); - string.push('\''); - - string.push('u'); - string.push_str("st"); - string.push_str(""); - string.push('\x52'); - string.push('\u{0052}'); - string.push('a'); -} diff --git a/tests/ui/single_char_push_str.rs b/tests/ui/single_char_push_str.rs deleted file mode 100644 index ab293bbe4eeb5..0000000000000 --- a/tests/ui/single_char_push_str.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-rustfix -#![warn(clippy::single_char_push_str)] - -fn main() { - let mut string = String::new(); - string.push_str("R"); - string.push_str("'"); - - string.push('u'); - string.push_str("st"); - string.push_str(""); - string.push_str("\x52"); - string.push_str("\u{0052}"); - string.push_str(r##"a"##); -} diff --git a/tests/ui/single_char_push_str.stderr b/tests/ui/single_char_push_str.stderr deleted file mode 100644 index 0e9bdaa23e7e8..0000000000000 --- a/tests/ui/single_char_push_str.stderr +++ /dev/null @@ -1,34 +0,0 @@ -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:6:5 - | -LL | string.push_str("R"); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')` - | - = note: `-D clippy::single-char-push-str` implied by `-D warnings` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:7:5 - | -LL | string.push_str("'"); - | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:12:5 - | -LL | string.push_str("/x52"); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:13:5 - | -LL | string.push_str("/u{0052}"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')` - -error: calling `push_str()` using a single-character string literal - --> $DIR/single_char_push_str.rs:14:5 - | -LL | string.push_str(r##"a"##); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` - -error: aborting due to 5 previous errors - diff --git a/tests/ui/skip_while_next.stderr b/tests/ui/skip_while_next.stderr index a6b7bcd63ff39..269cc13468bc8 100644 --- a/tests/ui/skip_while_next.stderr +++ b/tests/ui/skip_while_next.stderr @@ -1,13 +1,13 @@ -error: called `skip_while(p).next()` on an `Iterator` +error: called `skip_while(

).next()` on an `Iterator` --> $DIR/skip_while_next.rs:14:13 | LL | let _ = v.iter().skip_while(|&x| *x < 0).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::skip-while-next` implied by `-D warnings` - = help: this is more succinctly expressed by calling `.find(!p)` instead + = help: this is more succinctly expressed by calling `.find(!

)` instead -error: called `skip_while(p).next()` on an `Iterator` +error: called `skip_while(

).next()` on an `Iterator` --> $DIR/skip_while_next.rs:17:13 | LL | let _ = v.iter().skip_while(|&x| { @@ -17,7 +17,7 @@ LL | | } LL | | ).next(); | |___________________________^ | - = help: this is more succinctly expressed by calling `.find(!p)` instead + = help: this is more succinctly expressed by calling `.find(!

)` instead error: aborting due to 2 previous errors diff --git a/tests/ui/toplevel_ref_arg.fixed b/tests/ui/toplevel_ref_arg.fixed index 33605aca0199c..b129d95c5602f 100644 --- a/tests/ui/toplevel_ref_arg.fixed +++ b/tests/ui/toplevel_ref_arg.fixed @@ -1,7 +1,17 @@ // run-rustfix +// aux-build:macro_rules.rs #![warn(clippy::toplevel_ref_arg)] +#[macro_use] +extern crate macro_rules; + +macro_rules! gen_binding { + () => { + let _y = &42; + }; +} + fn main() { // Closures should not warn let y = |ref x| println!("{:?}", x); @@ -26,4 +36,15 @@ fn main() { // ok for ref _x in 0..10 {} + + // lint in macro + #[allow(unused)] + { + gen_binding!(); + } + + // do not lint in external macro + { + ref_arg_binding!(); + } } diff --git a/tests/ui/toplevel_ref_arg.rs b/tests/ui/toplevel_ref_arg.rs index 59759f1189333..73eb4ff7306f7 100644 --- a/tests/ui/toplevel_ref_arg.rs +++ b/tests/ui/toplevel_ref_arg.rs @@ -1,7 +1,17 @@ // run-rustfix +// aux-build:macro_rules.rs #![warn(clippy::toplevel_ref_arg)] +#[macro_use] +extern crate macro_rules; + +macro_rules! gen_binding { + () => { + let ref _y = 42; + }; +} + fn main() { // Closures should not warn let y = |ref x| println!("{:?}", x); @@ -26,4 +36,15 @@ fn main() { // ok for ref _x in 0..10 {} + + // lint in macro + #[allow(unused)] + { + gen_binding!(); + } + + // do not lint in external macro + { + ref_arg_binding!(); + } } diff --git a/tests/ui/toplevel_ref_arg.stderr b/tests/ui/toplevel_ref_arg.stderr index 19d69496709be..15cb933fedc9e 100644 --- a/tests/ui/toplevel_ref_arg.stderr +++ b/tests/ui/toplevel_ref_arg.stderr @@ -1,5 +1,5 @@ error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:10:9 + --> $DIR/toplevel_ref_arg.rs:20:9 | LL | let ref _x = 1; | ----^^^^^^----- help: try: `let _x = &1;` @@ -7,28 +7,39 @@ LL | let ref _x = 1; = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:12:9 + --> $DIR/toplevel_ref_arg.rs:22:9 | LL | let ref _y: (&_, u8) = (&1, 2); | ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:14:9 + --> $DIR/toplevel_ref_arg.rs:24:9 | LL | let ref _z = 1 + 2; | ----^^^^^^--------- help: try: `let _z = &(1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:16:9 + --> $DIR/toplevel_ref_arg.rs:26:9 | LL | let ref mut _z = 1 + 2; | ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> $DIR/toplevel_ref_arg.rs:21:9 + --> $DIR/toplevel_ref_arg.rs:31:9 | LL | let ref _x = vec![1, 2, 3]; | ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];` -error: aborting due to 5 previous errors +error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead + --> $DIR/toplevel_ref_arg.rs:11:13 + | +LL | let ref _y = 42; + | ----^^^^^^------ help: try: `let _y = &42;` +... +LL | gen_binding!(); + | --------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.rs b/tests/ui/toplevel_ref_arg_non_rustfix.rs index 42cac2ba4de25..1a493fbce0ef3 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -1,11 +1,33 @@ +// aux-build:macro_rules.rs + #![warn(clippy::toplevel_ref_arg)] #![allow(unused)] +#[macro_use] +extern crate macro_rules; + fn the_answer(ref mut x: u8) { *x = 42; } +macro_rules! gen_function { + () => { + fn fun_example(ref _x: usize) {} + }; +} + fn main() { let mut x = 0; the_answer(x); + + // lint in macro + #[allow(unused)] + { + gen_function!(); + } + + // do not lint in external macro + { + ref_arg_function!(); + } } diff --git a/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/tests/ui/toplevel_ref_arg_non_rustfix.stderr index 295e2f35608bf..6c36141a58c65 100644 --- a/tests/ui/toplevel_ref_arg_non_rustfix.stderr +++ b/tests/ui/toplevel_ref_arg_non_rustfix.stderr @@ -1,10 +1,21 @@ error: `ref` directly on a function argument is ignored. Consider using a reference type instead. - --> $DIR/toplevel_ref_arg_non_rustfix.rs:4:15 + --> $DIR/toplevel_ref_arg_non_rustfix.rs:9:15 | LL | fn the_answer(ref mut x: u8) { | ^^^^^^^^^ | = note: `-D clippy::toplevel-ref-arg` implied by `-D warnings` -error: aborting due to previous error +error: `ref` directly on a function argument is ignored. Consider using a reference type instead. + --> $DIR/toplevel_ref_arg_non_rustfix.rs:15:24 + | +LL | fn fun_example(ref _x: usize) {} + | ^^^^^^ +... +LL | gen_function!(); + | ---------------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors diff --git a/tests/ui/unused_unit.fixed b/tests/ui/unused_unit.fixed index 07f2791786d7f..7afc536135633 100644 --- a/tests/ui/unused_unit.fixed +++ b/tests/ui/unused_unit.fixed @@ -15,35 +15,35 @@ struct Unitter; impl Unitter { #[allow(clippy::no_effect)] - pub fn get_unit(&self, f: F, _g: G) - where G: Fn() { - let _y: &dyn Fn() = &f; + pub fn get_unit(&self, f: F, _g: G) + where G: Fn() { + let _y: &dyn Fn() = &f; (); // this should not lint, as it's not in return type position } } impl Into<()> for Unitter { #[rustfmt::skip] - fn into(self) { + fn into(self) { } } trait Trait { - fn redundant(&self, _f: F, _g: G, _h: H) + fn redundant(&self, _f: F, _g: G, _h: H) where - G: FnMut() , - H: Fn() ; + G: FnMut(), + H: Fn(); } impl Trait for Unitter { - fn redundant(&self, _f: F, _g: G, _h: H) + fn redundant(&self, _f: F, _g: G, _h: H) where - G: FnMut() , - H: Fn() {} + G: FnMut(), + H: Fn() {} } -fn return_unit() { } +fn return_unit() { } #[allow(clippy::needless_return)] #[allow(clippy::never_loop)] @@ -70,3 +70,12 @@ fn foo() { recv(rx) -> _x => () } } + +#[rustfmt::skip] +fn test(){} + +#[rustfmt::skip] +fn test2(){} + +#[rustfmt::skip] +fn test3(){} diff --git a/tests/ui/unused_unit.rs b/tests/ui/unused_unit.rs index e2c6afb020f58..96cef1ed5a5f2 100644 --- a/tests/ui/unused_unit.rs +++ b/tests/ui/unused_unit.rs @@ -70,3 +70,12 @@ fn foo() { recv(rx) -> _x => () } } + +#[rustfmt::skip] +fn test()->(){} + +#[rustfmt::skip] +fn test2() ->(){} + +#[rustfmt::skip] +fn test3()-> (){} diff --git a/tests/ui/unused_unit.stderr b/tests/ui/unused_unit.stderr index 81e6738e6bf67..c45634c2b6df7 100644 --- a/tests/ui/unused_unit.stderr +++ b/tests/ui/unused_unit.stderr @@ -1,8 +1,8 @@ error: unneeded unit return type - --> $DIR/unused_unit.rs:18:29 + --> $DIR/unused_unit.rs:18:28 | LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` | note: the lint level is defined here --> $DIR/unused_unit.rs:12:9 @@ -11,28 +11,28 @@ LL | #![deny(clippy::unused_unit)] | ^^^^^^^^^^^^^^^^^^^ error: unneeded unit return type - --> $DIR/unused_unit.rs:19:19 + --> $DIR/unused_unit.rs:19:18 | LL | where G: Fn() -> () { - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:18:59 + --> $DIR/unused_unit.rs:18:58 | LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:20:27 + --> $DIR/unused_unit.rs:20:26 | LL | let _y: &dyn Fn() -> () = &f; - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:27:19 + --> $DIR/unused_unit.rs:27:18 | LL | fn into(self) -> () { - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit expression --> $DIR/unused_unit.rs:28:9 @@ -41,46 +41,46 @@ LL | () | ^^ help: remove the final `()` error: unneeded unit return type - --> $DIR/unused_unit.rs:33:30 + --> $DIR/unused_unit.rs:33:29 | LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:35:20 + --> $DIR/unused_unit.rs:35:19 | LL | G: FnMut() -> (), - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:36:17 + --> $DIR/unused_unit.rs:36:16 | LL | H: Fn() -> (); - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:40:30 + --> $DIR/unused_unit.rs:40:29 | LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:42:20 + --> $DIR/unused_unit.rs:42:19 | LL | G: FnMut() -> (), - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:43:17 + --> $DIR/unused_unit.rs:43:16 | LL | H: Fn() -> () {} - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> $DIR/unused_unit.rs:46:18 + --> $DIR/unused_unit.rs:46:17 | LL | fn return_unit() -> () { () } - | ^^^^^ help: remove the `-> ()` + | ^^^^^^ help: remove the `-> ()` error: unneeded unit expression --> $DIR/unused_unit.rs:46:26 @@ -100,5 +100,23 @@ error: unneeded `()` LL | return(); | ^^ help: remove the `()` -error: aborting due to 16 previous errors +error: unneeded unit return type + --> $DIR/unused_unit.rs:75:10 + | +LL | fn test()->(){} + | ^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:78:11 + | +LL | fn test2() ->(){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> $DIR/unused_unit.rs:81:11 + | +LL | fn test3()-> (){} + | ^^^^^ help: remove the `-> ()` + +error: aborting due to 19 previous errors From 83e75f92079909aa07306633f26f42eccfb608e1 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Thu, 5 Nov 2020 18:00:34 +0100 Subject: [PATCH 016/118] Fix incorrect suggestion for `try_err` lint when `Err` arg is itself a macro --- clippy_lints/src/try_err.rs | 9 ++++++--- tests/ui/try_err.fixed | 18 ++++++++++++++++++ tests/ui/try_err.rs | 18 ++++++++++++++++++ tests/ui/try_err.stderr | 21 ++++++++++++++++----- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/try_err.rs b/clippy_lints/src/try_err.rs index 9c1185d30f21d..e1dec63a98a40 100644 --- a/clippy_lints/src/try_err.rs +++ b/clippy_lints/src/try_err.rs @@ -1,6 +1,6 @@ use crate::utils::{ - in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, snippet_with_macro_callsite, - span_lint_and_sugg, + differing_macro_contexts, in_macro, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet, + snippet_with_macro_callsite, span_lint_and_sugg, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -91,8 +91,11 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { }; let expr_err_ty = cx.typeck_results().expr_ty(err_arg); + let differing_contexts = differing_macro_contexts(expr.span, err_arg.span); - let origin_snippet = if err_arg.span.from_expansion() && !in_macro(expr.span) { + let origin_snippet = if in_macro(expr.span) && in_macro(err_arg.span) && differing_contexts { + snippet(cx, err_arg.span.ctxt().outer_expn_data().call_site, "_") + } else if err_arg.span.from_expansion() && !in_macro(expr.span) { snippet_with_macro_callsite(cx, err_arg.span, "_") } else { snippet(cx, err_arg.span, "_") diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index 053dd45f23e1a..aa43e69f79e8b 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -88,8 +88,26 @@ macro_rules! try_validation { }}; } +macro_rules! ret_one { + () => { + 1 + }; +} + +macro_rules! try_validation_in_macro { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => return Err(ret_one!()), + } + }}; +} + fn calling_macro() -> Result { + // macro try_validation!(Ok::<_, i32>(5)); + // `Err` arg is another macro + try_validation_in_macro!(Ok::<_, i32>(5)); Ok(5) } diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index 215ca6a07e62d..df3a9dc5367f3 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -88,8 +88,26 @@ macro_rules! try_validation { }}; } +macro_rules! ret_one { + () => { + 1 + }; +} + +macro_rules! try_validation_in_macro { + ($e: expr) => {{ + match $e { + Ok(_) => 0, + Err(_) => Err(ret_one!())?, + } + }}; +} + fn calling_macro() -> Result { + // macro try_validation!(Ok::<_, i32>(5)); + // `Err` arg is another macro + try_validation_in_macro!(Ok::<_, i32>(5)); Ok(5) } diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 443c8d0847218..3905ed2476b08 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -40,28 +40,39 @@ LL | try_validation!(Ok::<_, i32>(5)); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:122:9 + --> $DIR/try_err.rs:101:23 + | +LL | Err(_) => Err(ret_one!())?, + | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` +... +LL | try_validation_in_macro!(Ok::<_, i32>(5)); + | ------------------------------------------ in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: returning an `Err(_)` with the `?` operator + --> $DIR/try_err.rs:140:9 | LL | Err(foo!())?; | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:129:9 + --> $DIR/try_err.rs:147:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:131:9 + --> $DIR/try_err.rs:149:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:139:9 + --> $DIR/try_err.rs:157:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors From 1e4ce0fcaa2bd99ce51e1857767788cc498e62c0 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 6 Nov 2020 04:02:41 +0900 Subject: [PATCH 017/118] Fix `await_holding_refcell_ref` examples for clarify --- clippy_lints/src/await_holding_invalid.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index fcebb54c6c217..ca819663fded8 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -65,8 +65,8 @@ declare_clippy_lint! { /// use std::cell::RefCell; /// /// async fn foo(x: &RefCell) { - /// let b = x.borrow_mut()(); - /// *ref += 1; + /// let mut y = x.borrow_mut(); + /// *y += 1; /// bar.await; /// } /// ``` @@ -77,8 +77,8 @@ declare_clippy_lint! { /// /// async fn foo(x: &RefCell) { /// { - /// let b = x.borrow_mut(); - /// *ref += 1; + /// let mut y = x.borrow_mut(); + /// *y += 1; /// } /// bar.await; /// } From 1624b00bde42a674c50a03e63868e8b4d08b6b49 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Thu, 5 Nov 2020 13:56:57 +0900 Subject: [PATCH 018/118] Fix suggestion to add unneeded space in `manual_async` --- clippy_lints/src/manual_async_fn.rs | 17 ++++++- tests/ui/manual_async_fn.fixed | 14 +++++- tests/ui/manual_async_fn.rs | 20 ++++++++ tests/ui/manual_async_fn.stderr | 74 ++++++++++++++++++++++++++--- 4 files changed, 115 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index 864d1ea87f575..e9d65abb44302 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -69,7 +69,20 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { |diag| { if_chain! { if let Some(header_snip) = snippet_opt(cx, header_span); - if let Some(ret_pos) = header_snip.rfind("->"); + if let Some(ret_pos) = header_snip.rfind("->").map(|rpos| { + let mut rpos = rpos; + let chars: Vec = header_snip.chars().collect(); + while rpos > 1 { + if let Some(c) = chars.get(rpos - 1) { + if c.is_whitespace() { + rpos -= 1; + continue; + } + } + break; + } + rpos + }); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { let help = format!("make the function `async` and {}", ret_sugg); @@ -194,7 +207,7 @@ fn suggested_ret(cx: &LateContext<'_>, output: &Ty<'_>) -> Option<(&'static str, }, _ => { let sugg = "return the output of the future directly"; - snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip))) + snippet_opt(cx, output.span).map(|snip| (sugg, format!(" -> {}", snip))) }, } } diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed index 4f551690c4370..5184f6fdb88b3 100644 --- a/tests/ui/manual_async_fn.fixed +++ b/tests/ui/manual_async_fn.fixed @@ -7,7 +7,19 @@ use std::future::Future; async fn fut() -> i32 { 42 } -async fn empty_fut() {} +#[rustfmt::skip] +async fn fut2() -> i32 { 42 } + +#[rustfmt::skip] +async fn fut3() -> i32 { 42 } + +async fn empty_fut() {} + +#[rustfmt::skip] +async fn empty_fut2() {} + +#[rustfmt::skip] +async fn empty_fut3() {} async fn core_fut() -> i32 { 42 } diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs index 6ed60309947a8..68c0e591f0b6e 100644 --- a/tests/ui/manual_async_fn.rs +++ b/tests/ui/manual_async_fn.rs @@ -9,10 +9,30 @@ fn fut() -> impl Future { async { 42 } } +#[rustfmt::skip] +fn fut2() ->impl Future { + async { 42 } +} + +#[rustfmt::skip] +fn fut3()-> impl Future { + async { 42 } +} + fn empty_fut() -> impl Future { async {} } +#[rustfmt::skip] +fn empty_fut2() ->impl Future { + async {} +} + +#[rustfmt::skip] +fn empty_fut3()-> impl Future { + async {} +} + fn core_fut() -> impl core::future::Future { async move { 42 } } diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr index ccd828674276b..fdd43db3255ee 100644 --- a/tests/ui/manual_async_fn.stderr +++ b/tests/ui/manual_async_fn.stderr @@ -15,14 +15,44 @@ LL | fn fut() -> impl Future { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:12:1 + --> $DIR/manual_async_fn.rs:13:1 + | +LL | fn fut2() ->impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | async fn fut2() -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn fut2() ->impl Future { 42 } + | ^^^^^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:18:1 + | +LL | fn fut3()-> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and return the output of the future directly + | +LL | async fn fut3() -> i32 { + | ^^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn fut3()-> impl Future { 42 } + | ^^^^^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:22:1 | LL | fn empty_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: make the function `async` and remove the return type | -LL | async fn empty_fut() { +LL | async fn empty_fut() { | ^^^^^^^^^^^^^^^^^^^^ help: move the body of the async block to the enclosing function | @@ -30,7 +60,37 @@ LL | fn empty_fut() -> impl Future {} | ^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:16:1 + --> $DIR/manual_async_fn.rs:27:1 + | +LL | fn empty_fut2() ->impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and remove the return type + | +LL | async fn empty_fut2() { + | ^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn empty_fut2() ->impl Future {} + | ^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:32:1 + | +LL | fn empty_fut3()-> impl Future { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: make the function `async` and remove the return type + | +LL | async fn empty_fut3() { + | ^^^^^^^^^^^^^^^^^^^^^ +help: move the body of the async block to the enclosing function + | +LL | fn empty_fut3()-> impl Future {} + | ^^ + +error: this function can be simplified using the `async fn` syntax + --> $DIR/manual_async_fn.rs:36:1 | LL | fn core_fut() -> impl core::future::Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +105,7 @@ LL | fn core_fut() -> impl core::future::Future { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:38:5 + --> $DIR/manual_async_fn.rs:58:5 | LL | fn inh_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,7 +125,7 @@ LL | let c = 21; ... error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:73:1 + --> $DIR/manual_async_fn.rs:93:1 | LL | fn elided(_: &i32) -> impl Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +140,7 @@ LL | fn elided(_: &i32) -> impl Future + '_ { 42 } | ^^^^^^ error: this function can be simplified using the `async fn` syntax - --> $DIR/manual_async_fn.rs:82:1 + --> $DIR/manual_async_fn.rs:102:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -94,5 +154,5 @@ help: move the body of the async block to the enclosing function LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { 42 } | ^^^^^^ -error: aborting due to 6 previous errors +error: aborting due to 10 previous errors From 5f57608604bd35bd11c1f33cbd7202250e072b54 Mon Sep 17 00:00:00 2001 From: Aleksei Latyshev Date: Fri, 6 Nov 2020 14:38:46 +0300 Subject: [PATCH 019/118] do not trigger map_clone in the case of &mut --- clippy_lints/src/map_clone.rs | 8 +++++--- tests/ui/map_clone.fixed | 8 ++++++++ tests/ui/map_clone.rs | 8 ++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 034cd99a9be06..9a00608ce3947 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -80,9 +80,11 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) { let obj_ty = cx.typeck_results().expr_ty(&obj[0]); - if let ty::Ref(_, ty, _) = obj_ty.kind() { - let copy = is_copy(cx, ty); - lint(cx, e.span, args[0].span, copy); + if let ty::Ref(_, ty, mutability) = obj_ty.kind() { + if matches!(mutability, Mutability::Not) { + let copy = is_copy(cx, ty); + lint(cx, e.span, args[0].span, copy); + } } else { lint_needless_cloning(cx, e.span, args[0].span); } diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index 81c7f659efb1f..6e3a8e67e811e 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -44,4 +44,12 @@ fn main() { let v = vec![&mut d]; let _: Vec = v.into_iter().map(|&mut x| x).collect(); } + + // Issue #6299 + { + let mut aa = 5; + let mut bb = 3; + let items = vec![&mut aa, &mut bb]; + let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); + } } diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 8ed164f0ed51d..6fd395710d4ba 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -44,4 +44,12 @@ fn main() { let v = vec![&mut d]; let _: Vec = v.into_iter().map(|&mut x| x).collect(); } + + // Issue #6299 + { + let mut aa = 5; + let mut bb = 3; + let items = vec![&mut aa, &mut bb]; + let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); + } } From b7892c6a26adf6173758641d3f7deb0ae972959d Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Fri, 6 Nov 2020 22:54:38 +0900 Subject: [PATCH 020/118] Refactor to make getting position just before RArrow a common function --- clippy_lints/src/manual_async_fn.rs | 17 ++--------------- clippy_lints/src/unused_unit.rs | 29 ++++++++--------------------- clippy_lints/src/utils/mod.rs | 29 +++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs index e9d65abb44302..7b3b450ef93e9 100644 --- a/clippy_lints/src/manual_async_fn.rs +++ b/clippy_lints/src/manual_async_fn.rs @@ -1,5 +1,5 @@ use crate::utils::paths::FUTURE_FROM_GENERATOR; -use crate::utils::{match_function_call, snippet_block, snippet_opt, span_lint_and_then}; +use crate::utils::{match_function_call, position_before_rarrow, snippet_block, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -69,20 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { |diag| { if_chain! { if let Some(header_snip) = snippet_opt(cx, header_span); - if let Some(ret_pos) = header_snip.rfind("->").map(|rpos| { - let mut rpos = rpos; - let chars: Vec = header_snip.chars().collect(); - while rpos > 1 { - if let Some(c) = chars.get(rpos - 1) { - if c.is_whitespace() { - rpos -= 1; - continue; - } - } - break; - } - rpos - }); + if let Some(ret_pos) = position_before_rarrow(header_snip.clone()); if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output); then { let help = format!("make the function `async` and {}", ret_sugg); diff --git a/clippy_lints/src/unused_unit.rs b/clippy_lints/src/unused_unit.rs index b1339c3d6395d..f61fd2ecd735d 100644 --- a/clippy_lints/src/unused_unit.rs +++ b/clippy_lints/src/unused_unit.rs @@ -7,7 +7,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::BytePos; -use crate::utils::span_lint_and_sugg; +use crate::utils::{position_before_rarrow, span_lint_and_sugg}; declare_clippy_lint! { /// **What it does:** Checks for unit (`()`) expressions that can be removed. @@ -120,26 +120,13 @@ fn is_unit_expr(expr: &ast::Expr) -> bool { fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { let (ret_span, appl) = if let Ok(fn_source) = cx.sess().source_map().span_to_snippet(span.with_hi(ty.span.hi())) { - fn_source - .rfind("->") - .map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { - let mut rpos = rpos; - let chars: Vec = fn_source.chars().collect(); - while rpos > 1 { - if let Some(c) = chars.get(rpos - 1) { - if c.is_whitespace() { - rpos -= 1; - continue; - } - } - break; - } - ( - #[allow(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), - Applicability::MachineApplicable, - ) - }) + position_before_rarrow(fn_source).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + ( + #[allow(clippy::cast_possible_truncation)] + ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + Applicability::MachineApplicable, + ) + }) } else { (ty.span, Applicability::MaybeIncorrect) }; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 85e7f055e79de..8e4149df0328b 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -659,6 +659,35 @@ pub fn indent_of(cx: &T, span: Span) -> Option { snippet_opt(cx, line_span(cx, span)).and_then(|snip| snip.find(|c: char| !c.is_whitespace())) } +/// Returns the positon just before rarrow +/// +/// ```rust,ignore +/// fn into(self) -> () {} +/// ^ +/// // in case of unformatted code +/// fn into2(self)-> () {} +/// ^ +/// fn into3(self) -> () {} +/// ^ +/// ``` +#[allow(clippy::needless_pass_by_value)] +pub fn position_before_rarrow(s: String) -> Option { + s.rfind("->").map(|rpos| { + let mut rpos = rpos; + let chars: Vec = s.chars().collect(); + while rpos > 1 { + if let Some(c) = chars.get(rpos - 1) { + if c.is_whitespace() { + rpos -= 1; + continue; + } + } + break; + } + rpos + }) +} + /// Extends the span to the beginning of the spans line, incl. whitespaces. /// /// ```rust,ignore From 8242b2f0a4a53f066fa579d7497ae4574e291e2e Mon Sep 17 00:00:00 2001 From: ThibsG Date: Fri, 30 Oct 2020 18:43:27 +0100 Subject: [PATCH 021/118] Remove needless allow --- tests/ui/option_option.rs | 2 -- tests/ui/option_option.stderr | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index a2617a13ecace..2434483364151 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -72,8 +72,6 @@ mod issue_4298 { #[serde(skip_serializing_if = "Option::is_none")] #[serde(default)] #[serde(borrow)] - // FIXME: should not lint here - #[allow(clippy::option_option)] foo: Option>>, } diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 0cd4c96eb4f9a..8ae1d23a8e33e 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -59,7 +59,7 @@ LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:77:14 + --> $DIR/option_option.rs:75:14 | LL | foo: Option>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 5253595b3bb6a3cc6502bb2327590e582d1d27e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Fri, 6 Nov 2020 19:34:34 +0100 Subject: [PATCH 022/118] FROM_ITER_INSTEAD_OF_COLLECT: avoid unwrapping unconditionally Fixes #6302 --- clippy_lints/src/methods/mod.rs | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7186656f4e11a..a3fa3bdd36a56 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3901,21 +3901,24 @@ fn lint_from_iter(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr< let ty = cx.typeck_results().expr_ty(expr); let arg_ty = cx.typeck_results().expr_ty(&args[0]); - let from_iter_id = get_trait_def_id(cx, &paths::FROM_ITERATOR).unwrap(); - let iter_id = get_trait_def_id(cx, &paths::ITERATOR).unwrap(); + if_chain! { + if let Some(from_iter_id) = get_trait_def_id(cx, &paths::FROM_ITERATOR); + if let Some(iter_id) = get_trait_def_id(cx, &paths::ITERATOR); - if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]) { - // `expr` implements `FromIterator` trait - let iter_expr = snippet(cx, args[0].span, ".."); - span_lint_and_sugg( - cx, - FROM_ITER_INSTEAD_OF_COLLECT, - expr.span, - "usage of `FromIterator::from_iter`", - "use `.collect()` instead of `::from_iter()`", - format!("{}.collect()", iter_expr), - Applicability::MaybeIncorrect, - ); + if implements_trait(cx, ty, from_iter_id, &[]) && implements_trait(cx, arg_ty, iter_id, &[]); + then { + // `expr` implements `FromIterator` trait + let iter_expr = snippet(cx, args[0].span, ".."); + span_lint_and_sugg( + cx, + FROM_ITER_INSTEAD_OF_COLLECT, + expr.span, + "usage of `FromIterator::from_iter`", + "use `.collect()` instead of `::from_iter()`", + format!("{}.collect()", iter_expr), + Applicability::MaybeIncorrect, + ); + } } } From c6a91df838b17a2366346db664072d7914ab241a Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Thu, 22 Oct 2020 23:39:25 -0700 Subject: [PATCH 023/118] Enable empty_loop lint for no_std crates We skip the lint if the `loop {}` is in the `#[panic_handler]` as the main recommendation we give is to panic, which obviously isn't possible in a panic handler. Signed-off-by: Joe Richey --- clippy_lints/src/loops.rs | 28 +++++++++++++--------------- clippy_lints/src/utils/mod.rs | 7 +++++++ tests/ui/empty_loop_no_std.rs | 7 ++++++- tests/ui/empty_loop_no_std.stderr | 19 +++++++++++++++++++ 4 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 tests/ui/empty_loop_no_std.stderr diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 32c2562ee95b4..2a53210efe3d9 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -4,10 +4,10 @@ use crate::utils::sugg::Sugg; use crate::utils::usage::{is_unused, mutated_variables}; use crate::utils::{ contains_name, get_enclosing_block, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, - indent_of, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, last_path_segment, - match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, snippet, - snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, span_lint_and_sugg, - span_lint_and_then, sugg, SpanlessEq, + indent_of, is_in_panic_handler, is_integer_const, is_no_std_crate, is_refutable, is_type_diagnostic_item, + last_path_segment, match_trait_method, match_type, match_var, multispan_sugg, qpath_res, single_segment_path, + snippet, snippet_with_applicability, snippet_with_macro_callsite, span_lint, span_lint_and_help, + span_lint_and_sugg, span_lint_and_then, sugg, SpanlessEq, }; use if_chain::if_chain; use rustc_ast::ast; @@ -543,17 +543,15 @@ impl<'tcx> LateLintPass<'tcx> for Loops { // (also matches an explicit "match" instead of "if let") // (even if the "match" or "if let" is used for declaration) if let ExprKind::Loop(ref block, _, LoopSource::Loop) = expr.kind { - // also check for empty `loop {}` statements - // TODO(issue #6161): Enable for no_std crates (outside of #[panic_handler]) - if block.stmts.is_empty() && block.expr.is_none() && !is_no_std_crate(cx.tcx.hir().krate()) { - span_lint_and_help( - cx, - EMPTY_LOOP, - expr.span, - "empty `loop {}` wastes CPU cycles", - None, - "You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body.", - ); + // also check for empty `loop {}` statements, skipping those in #[panic_handler] + if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) { + let msg = "empty `loop {}` wastes CPU cycles"; + let help = if is_no_std_crate(cx.tcx.hir().krate()) { + "You should either use `panic!()` or add a call pausing or sleeping the thread to the loop body." + } else { + "You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body." + }; + span_lint_and_help(cx, EMPTY_LOOP, expr.span, msg, None, help); } // extract the expression from the first statement (if any) in a block diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 8e4149df0328b..cba3a05024995 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -468,6 +468,13 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool { .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id.to_def_id()) } +/// Returns `true` if the expression is in the program's `#[panic_handler]`. +pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { + let parent = cx.tcx.hir().get_parent_item(e.hir_id); + let def_id = cx.tcx.hir().local_def_id(parent).to_def_id(); + Some(def_id) == cx.tcx.lang_items().panic_impl() +} + /// Gets the name of the item the expression is in, if available. pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id); diff --git a/tests/ui/empty_loop_no_std.rs b/tests/ui/empty_loop_no_std.rs index 879d1d5d916e4..4553d3ec505a3 100644 --- a/tests/ui/empty_loop_no_std.rs +++ b/tests/ui/empty_loop_no_std.rs @@ -10,13 +10,18 @@ use core::panic::PanicInfo; #[start] fn main(argc: isize, argv: *const *const u8) -> isize { + // This should trigger the lint loop {} } #[panic_handler] fn panic(_info: &PanicInfo) -> ! { + // This should NOT trigger the lint loop {} } #[lang = "eh_personality"] -extern "C" fn eh_personality() {} +extern "C" fn eh_personality() { + // This should also trigger the lint + loop {} +} diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr new file mode 100644 index 0000000000000..1cb454c3bbe3b --- /dev/null +++ b/tests/ui/empty_loop_no_std.stderr @@ -0,0 +1,19 @@ +error: empty `loop {}` wastes CPU cycles + --> $DIR/empty_loop_no_std.rs:14:5 + | +LL | loop {} + | ^^^^^^^ + | + = note: `-D clippy::empty-loop` implied by `-D warnings` + = help: You should either use `panic!()` or add a call pausing or sleeping the thread to the loop body. + +error: empty `loop {}` wastes CPU cycles + --> $DIR/empty_loop_no_std.rs:26:5 + | +LL | loop {} + | ^^^^^^^ + | + = help: You should either use `panic!()` or add a call pausing or sleeping the thread to the loop body. + +error: aborting due to 2 previous errors + From 3579b7de24df6a617322ec07eae98618ef57e5ee Mon Sep 17 00:00:00 2001 From: Joseph Richey Date: Wed, 4 Nov 2020 03:27:30 -0800 Subject: [PATCH 024/118] Update clippy_lints/src/loops.rs Fix NITs Co-authored-by: Philipp Krones --- clippy_lints/src/loops.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 2a53210efe3d9..b246245af24ce 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -547,9 +547,9 @@ impl<'tcx> LateLintPass<'tcx> for Loops { if block.stmts.is_empty() && block.expr.is_none() && !is_in_panic_handler(cx, expr) { let msg = "empty `loop {}` wastes CPU cycles"; let help = if is_no_std_crate(cx.tcx.hir().krate()) { - "You should either use `panic!()` or add a call pausing or sleeping the thread to the loop body." + "you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body" } else { - "You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body." + "you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body" }; span_lint_and_help(cx, EMPTY_LOOP, expr.span, msg, None, help); } From 00dee9d9160e9030d387f2cef1ec2b6422478229 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 8 Nov 2020 12:40:41 +0100 Subject: [PATCH 025/118] Update reference files --- tests/ui/crashes/ice-360.stderr | 2 +- tests/ui/empty_loop.stderr | 6 +++--- tests/ui/empty_loop_no_std.stderr | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/ui/crashes/ice-360.stderr b/tests/ui/crashes/ice-360.stderr index bb03ce4035533..0eb7bb12b3546 100644 --- a/tests/ui/crashes/ice-360.stderr +++ b/tests/ui/crashes/ice-360.stderr @@ -19,7 +19,7 @@ LL | loop {} | ^^^^^^^ | = note: `-D clippy::empty-loop` implied by `-D warnings` - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: aborting due to 2 previous errors diff --git a/tests/ui/empty_loop.stderr b/tests/ui/empty_loop.stderr index fd3979f259a14..555f3d3d884a9 100644 --- a/tests/ui/empty_loop.stderr +++ b/tests/ui/empty_loop.stderr @@ -5,7 +5,7 @@ LL | loop {} | ^^^^^^^ | = note: `-D clippy::empty-loop` implied by `-D warnings` - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop.rs:11:9 @@ -13,7 +13,7 @@ error: empty `loop {}` wastes CPU cycles LL | loop {} | ^^^^^^^ | - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop.rs:15:9 @@ -21,7 +21,7 @@ error: empty `loop {}` wastes CPU cycles LL | 'inner: loop {} | ^^^^^^^^^^^^^^^ | - = help: You should either use `panic!()` or add `std::thread::sleep(..);` to the loop body. + = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: aborting due to 3 previous errors diff --git a/tests/ui/empty_loop_no_std.stderr b/tests/ui/empty_loop_no_std.stderr index 1cb454c3bbe3b..520248fcb689c 100644 --- a/tests/ui/empty_loop_no_std.stderr +++ b/tests/ui/empty_loop_no_std.stderr @@ -5,7 +5,7 @@ LL | loop {} | ^^^^^^^ | = note: `-D clippy::empty-loop` implied by `-D warnings` - = help: You should either use `panic!()` or add a call pausing or sleeping the thread to the loop body. + = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body error: empty `loop {}` wastes CPU cycles --> $DIR/empty_loop_no_std.rs:26:5 @@ -13,7 +13,7 @@ error: empty `loop {}` wastes CPU cycles LL | loop {} | ^^^^^^^ | - = help: You should either use `panic!()` or add a call pausing or sleeping the thread to the loop body. + = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body error: aborting due to 2 previous errors From f1f780c9422f038ae78e72a99b1ca2a0d7b392bc Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sat, 7 Nov 2020 18:26:14 -0500 Subject: [PATCH 026/118] Add let_underscore_drop --- CHANGELOG.md | 1 + clippy_lints/src/let_underscore.rs | 56 +++++++++++++++++++++++++++-- clippy_lints/src/lib.rs | 3 ++ src/lintlist/mod.rs | 7 ++++ tests/ui/let_underscore_drop.rs | 19 ++++++++++ tests/ui/let_underscore_drop.stderr | 27 ++++++++++++++ 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 tests/ui/let_underscore_drop.rs create mode 100644 tests/ui/let_underscore_drop.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index e0770a45c5334..816d25bcd93eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1787,6 +1787,7 @@ Released 2018-09-13 [`len_without_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_without_is_empty [`len_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#len_zero [`let_and_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_and_return +[`let_underscore_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_drop [`let_underscore_lock`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_lock [`let_underscore_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_underscore_must_use [`let_unit_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#let_unit_value diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index ae2f6131b5b8f..9c7fd63454767 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::utils::{is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; +use crate::utils::{implements_trait, is_must_use_func_call, is_must_use_ty, match_type, paths, span_lint_and_help}; declare_clippy_lint! { /// **What it does:** Checks for `let _ = ` @@ -58,7 +58,40 @@ declare_clippy_lint! { "non-binding let on a synchronization lock" } -declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK]); +declare_clippy_lint! { + /// **What it does:** Checks for `let _ = ` + /// where expr has a type that implements `Drop` + /// + /// **Why is this bad?** This statement immediately drops the initializer + /// expression instead of extending its lifetime to the end of the scope, which + /// is often not intended. To extend the expression's lifetime to the end of the + /// scope, use an underscore-prefixed name instead (i.e. _var). If you want to + /// explicitly drop the expression, `std::mem::drop` conveys your intention + /// better and is less error-prone. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// Bad: + /// ```rust,ignore + /// struct Droppable; + /// impl Drop for Droppable { + /// fn drop(&mut self) {} + /// } + /// let _ = Droppable; + /// ``` + /// + /// Good: + /// ```rust,ignore + /// let _droppable = Droppable; + /// ``` + pub LET_UNDERSCORE_DROP, + correctness, + "non-binding let on a type that implements `Drop`" +} + +declare_lint_pass!(LetUnderscore => [LET_UNDERSCORE_MUST_USE, LET_UNDERSCORE_LOCK, LET_UNDERSCORE_DROP]); const SYNC_GUARD_PATHS: [&[&str]; 3] = [ &paths::MUTEX_GUARD, @@ -84,6 +117,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, }); + let implements_drop = cx.tcx.lang_items().drop_trait().map_or(false, |drop_trait| + init_ty.walk().any(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => { + implements_trait(cx, inner_ty, drop_trait, &[]) + }, + + GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false, + }) + ); if contains_sync_guard { span_lint_and_help( cx, @@ -94,6 +136,16 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" ) + } else if implements_drop { + span_lint_and_help( + cx, + LET_UNDERSCORE_DROP, + local.span, + "non-binding let on a type that implements `Drop`", + None, + "consider using an underscore-prefixed named \ + binding or dropping explicitly with `std::mem::drop`" + ) } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( cx, diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 1f4bed92e695d..b44e28b4596f6 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -622,6 +622,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &len_zero::LEN_WITHOUT_IS_EMPTY, &len_zero::LEN_ZERO, &let_if_seq::USELESS_LET_IF_SEQ, + &let_underscore::LET_UNDERSCORE_DROP, &let_underscore::LET_UNDERSCORE_LOCK, &let_underscore::LET_UNDERSCORE_MUST_USE, &lifetimes::EXTRA_UNUSED_LIFETIMES, @@ -1383,6 +1384,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&len_zero::COMPARISON_TO_EMPTY), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), + LintId::of(&let_underscore::LET_UNDERSCORE_DROP), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(&lifetimes::NEEDLESS_LIFETIMES), @@ -1809,6 +1811,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&infinite_iter::INFINITE_ITER), LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), + LintId::of(&let_underscore::LET_UNDERSCORE_DROP), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index bc0a0ad2b179d..8b5e6cc916f9d 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1117,6 +1117,13 @@ vec![ deprecation: None, module: "returns", }, + Lint { + name: "let_underscore_drop", + group: "correctness", + desc: "non-binding let on a type that implements `Drop`", + deprecation: None, + module: "let_underscore", + }, Lint { name: "let_underscore_lock", group: "correctness", diff --git a/tests/ui/let_underscore_drop.rs b/tests/ui/let_underscore_drop.rs new file mode 100644 index 0000000000000..98593edb9c591 --- /dev/null +++ b/tests/ui/let_underscore_drop.rs @@ -0,0 +1,19 @@ +#![warn(clippy::let_underscore_drop)] + +struct Droppable; + +impl Drop for Droppable { + fn drop(&mut self) {} +} + +fn main() { + let unit = (); + let boxed = Box::new(()); + let droppable = Droppable; + let optional = Some(Droppable); + + let _ = (); + let _ = Box::new(()); + let _ = Droppable; + let _ = Some(Droppable); +} diff --git a/tests/ui/let_underscore_drop.stderr b/tests/ui/let_underscore_drop.stderr new file mode 100644 index 0000000000000..6dc8904c4fe95 --- /dev/null +++ b/tests/ui/let_underscore_drop.stderr @@ -0,0 +1,27 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:16:5 + | +LL | let _ = Box::new(()); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-drop` implied by `-D warnings` + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:17:5 + | +LL | let _ = Droppable; + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/let_underscore_drop.rs:18:5 + | +LL | let _ = Some(Droppable); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 3 previous errors + From 9c6a0b9c3490b321756c56d07c57f5537ea2b7fb Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sun, 8 Nov 2020 07:07:49 -0500 Subject: [PATCH 027/118] Update references --- tests/ui/borrow_box.stderr | 11 ++- .../others.stderr | 27 +++++++- tests/ui/box_vec.stderr | 15 ++++- tests/ui/crashes/ice-4968.stderr | 11 +++ tests/ui/crashes/ice-5223.stderr | 11 +++ tests/ui/escape_analysis.stderr | 23 ++++++- tests/ui/eta.stderr | 19 +++++- tests/ui/filter_methods.stderr | 47 ++++++++++++- tests/ui/get_unwrap.stderr | 19 +++++- tests/ui/into_iter_on_ref.stderr | 11 ++- tests/ui/iter_cloned_collect.stderr | 23 ++++++- tests/ui/map_clone.stderr | 59 +++++++++++++++- tests/ui/map_collect_result_unit.stderr | 19 +++++- tests/ui/map_flatten.stderr | 43 +++++++++++- tests/ui/map_identity.stderr | 35 +++++++++- tests/ui/match_single_binding.stderr | 16 ++++- tests/ui/needless_pass_by_value.stderr | 11 ++- tests/ui/redundant_clone.stderr | 11 ++- tests/ui/reversed_empty_ranges_fixable.stderr | 11 ++- tests/ui/transmute.stderr | 43 +++++++++++- tests/ui/transmute_collection.stderr | 67 ++++++++++++++++++- tests/ui/unnecessary_clone.stderr | 11 ++- tests/ui/useless_conversion.stderr | 11 ++- 23 files changed, 533 insertions(+), 21 deletions(-) create mode 100644 tests/ui/crashes/ice-4968.stderr create mode 100644 tests/ui/crashes/ice-5223.stderr diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index 3eac32815be3f..a40789cd42634 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -22,6 +22,15 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` +error: non-binding let on a type that implements `Drop` + --> $DIR/borrow_box.rs:63:5 + | +LL | let _ = foo; + | ^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: you seem to be trying to use `&Box`. Consider using just `&T` --> $DIR/borrow_box.rs:95:25 | @@ -64,5 +73,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index 9a908cf30e945..976c412c7a875 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -47,6 +47,15 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | = help: assign this const to a local or static variable, and use the variable here +error: non-binding let on a type that implements `Drop` + --> $DIR/others.rs:72:5 + | +LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:72:14 | @@ -95,6 +104,22 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | = help: assign this const to a local or static variable, and use the variable here +error: non-binding let on a type that implements `Drop` + --> $DIR/others.rs:83:5 + | +LL | let _ = ATOMIC_TUPLE.1.into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/others.rs:85:5 + | +LL | let _ = &{ ATOMIC_TUPLE }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:87:5 | @@ -111,5 +136,5 @@ LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | = help: assign this const to a local or static variable, and use the variable here -error: aborting due to 14 previous errors +error: aborting due to 17 previous errors diff --git a/tests/ui/box_vec.stderr b/tests/ui/box_vec.stderr index fca12eddd573f..a4983df1d3076 100644 --- a/tests/ui/box_vec.stderr +++ b/tests/ui/box_vec.stderr @@ -1,3 +1,16 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/box_vec.rs:7:9 + | +LL | let _: Box<$x> = Box::new($init); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | boxit!(Vec::new(), Vec); + | ---------------------------- in this macro invocation + | + = note: `-D clippy::let-underscore-drop` implied by `-D warnings` + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + error: you seem to be trying to use `Box>`. Consider using just `Vec` --> $DIR/box_vec.rs:14:18 | @@ -7,5 +20,5 @@ LL | pub fn test(foo: Box>) { = note: `-D clippy::box-vec` implied by `-D warnings` = help: `Vec` is already on the heap, `Box>` makes an extra allocation. -error: aborting due to previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/crashes/ice-4968.stderr b/tests/ui/crashes/ice-4968.stderr new file mode 100644 index 0000000000000..9ce39027451dc --- /dev/null +++ b/tests/ui/crashes/ice-4968.stderr @@ -0,0 +1,11 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/ice-4968.rs:16:9 + | +LL | let _: Vec> = mem::transmute(slice); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to previous error + diff --git a/tests/ui/crashes/ice-5223.stderr b/tests/ui/crashes/ice-5223.stderr new file mode 100644 index 0000000000000..3ae2dd5f7705f --- /dev/null +++ b/tests/ui/crashes/ice-5223.stderr @@ -0,0 +1,11 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/ice-5223.rs:14:9 + | +LL | let _ = self.arr.iter().cloned().collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to previous error + diff --git a/tests/ui/escape_analysis.stderr b/tests/ui/escape_analysis.stderr index c86a769a3da4b..6e1c1c07b6eac 100644 --- a/tests/ui/escape_analysis.stderr +++ b/tests/ui/escape_analysis.stderr @@ -12,5 +12,26 @@ error: local variable doesn't need to be boxed here LL | pub fn new(_needs_name: Box>) -> () {} | ^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: non-binding let on a type that implements `Drop` + --> $DIR/escape_analysis.rs:166:9 + | +LL | / let _ = move || { +LL | | consume(x); +LL | | }; + | |__________^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/escape_analysis.rs:172:9 + | +LL | / let _ = || { +LL | | borrow(&x); +LL | | }; + | |__________^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 4 previous errors diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index c4713ca8083dd..bc79caee887f6 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -64,6 +64,15 @@ error: redundant closure found LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_ascii_uppercase` +error: non-binding let on a type that implements `Drop` + --> $DIR/eta.rs:107:5 + | +LL | let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: redundant closure found --> $DIR/eta.rs:172:27 | @@ -76,5 +85,13 @@ error: redundant closure found LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `closure` -error: aborting due to 12 previous errors +error: non-binding let on a type that implements `Drop` + --> $DIR/eta.rs:203:5 + | +LL | let _ = [Bar].iter().map(|s| s.to_string()).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 14 previous errors diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index 91718dd11755b..08b781d73634e 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,3 +1,12 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/filter_methods.rs:5:5 + | +LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-drop` implied by `-D warnings` + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `filter(..).map(..)` on an `Iterator` --> $DIR/filter_methods.rs:5:21 | @@ -7,6 +16,18 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * = note: `-D clippy::filter-map` implied by `-D warnings` = help: this is more succinctly expressed by calling `.filter_map(..)` instead +error: non-binding let on a type that implements `Drop` + --> $DIR/filter_methods.rs:7:5 + | +LL | / let _: Vec<_> = vec![5_i8; 6] +LL | | .into_iter() +LL | | .filter(|&x| x == 0) +LL | | .flat_map(|x| x.checked_mul(2)) +LL | | .collect(); + | |___________________^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `filter(..).flat_map(..)` on an `Iterator` --> $DIR/filter_methods.rs:7:21 | @@ -19,6 +40,18 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` +error: non-binding let on a type that implements `Drop` + --> $DIR/filter_methods.rs:13:5 + | +LL | / let _: Vec<_> = vec![5_i8; 6] +LL | | .into_iter() +LL | | .filter_map(|x| x.checked_mul(2)) +LL | | .flat_map(|x| x.checked_mul(2)) +LL | | .collect(); + | |___________________^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `filter_map(..).flat_map(..)` on an `Iterator` --> $DIR/filter_methods.rs:13:21 | @@ -31,6 +64,18 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` +error: non-binding let on a type that implements `Drop` + --> $DIR/filter_methods.rs:19:5 + | +LL | / let _: Vec<_> = vec![5_i8; 6] +LL | | .into_iter() +LL | | .filter_map(|x| x.checked_mul(2)) +LL | | .map(|x| x.checked_mul(2)) +LL | | .collect(); + | |___________________^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `filter_map(..).map(..)` on an `Iterator` --> $DIR/filter_methods.rs:19:21 | @@ -43,5 +88,5 @@ LL | | .map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by only calling `.filter_map(..)` instead -error: aborting due to 4 previous errors +error: aborting due to 8 previous errors diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index 76a098df82aa1..6aa5452bac1c9 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -70,17 +70,34 @@ error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` +error: non-binding let on a type that implements `Drop` + --> $DIR/get_unwrap.rs:59:9 + | +LL | let _ = some_vec.get(0..1).unwrap().to_vec(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:59:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` +error: non-binding let on a type that implements `Drop` + --> $DIR/get_unwrap.rs:60:9 + | +LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:60:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` -error: aborting due to 13 previous errors +error: aborting due to 15 previous errors diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr index 28003b365bbd5..efe9d20920b74 100644 --- a/tests/ui/into_iter_on_ref.stderr +++ b/tests/ui/into_iter_on_ref.stderr @@ -1,3 +1,12 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/into_iter_on_ref.rs:13:5 + | +LL | let _ = vec![1, 2, 3].into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:14:30 | @@ -162,5 +171,5 @@ error: this `.into_iter()` call is equivalent to `.iter()` and will not consume LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: aborting due to 27 previous errors +error: aborting due to 28 previous errors diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr index b90a1e6c91967..f5cd43b3da542 100644 --- a/tests/ui/iter_cloned_collect.stderr +++ b/tests/ui/iter_cloned_collect.stderr @@ -6,12 +6,33 @@ LL | let v2: Vec = v.iter().cloned().collect(); | = note: `-D clippy::iter-cloned-collect` implied by `-D warnings` +error: non-binding let on a type that implements `Drop` + --> $DIR/iter_cloned_collect.rs:15:5 + | +LL | let _: Vec = vec![1, 2, 3].iter().cloned().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable --> $DIR/iter_cloned_collect.rs:15:38 | LL | let _: Vec = vec![1, 2, 3].iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` +error: non-binding let on a type that implements `Drop` + --> $DIR/iter_cloned_collect.rs:19:9 + | +LL | / let _: Vec = std::ffi::CStr::from_ptr(std::ptr::null()) +LL | | .to_bytes() +LL | | .iter() +LL | | .cloned() +LL | | .collect(); + | |_______________________^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable --> $DIR/iter_cloned_collect.rs:20:24 | @@ -22,5 +43,5 @@ LL | | .cloned() LL | | .collect(); | |______________________^ help: try: `.to_vec()` -error: aborting due to 3 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index 4f43cff502444..122a678f1188f 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,3 +1,12 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/map_clone.rs:10:5 + | +LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-drop` implied by `-D warnings` + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: you are using an explicit closure for copying elements --> $DIR/map_clone.rs:10:22 | @@ -6,12 +15,28 @@ LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); | = note: `-D clippy::map-clone` implied by `-D warnings` +error: non-binding let on a type that implements `Drop` + --> $DIR/map_clone.rs:11:5 + | +LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: you are using an explicit closure for cloning elements --> $DIR/map_clone.rs:11:26 | LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` +error: non-binding let on a type that implements `Drop` + --> $DIR/map_clone.rs:12:5 + | +LL | let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: you are using an explicit closure for copying elements --> $DIR/map_clone.rs:12:23 | @@ -36,5 +61,37 @@ error: you are needlessly cloning iterator elements LL | let _ = std::env::args().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call -error: aborting due to 6 previous errors +error: non-binding let on a type that implements `Drop` + --> $DIR/map_clone.rs:35:9 + | +LL | let _: Vec = v.into_iter().map(|x| *x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/map_clone.rs:42:9 + | +LL | let _: Vec = v.into_iter().map(|x| *x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/map_clone.rs:45:9 + | +LL | let _: Vec = v.into_iter().map(|&mut x| x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/map_clone.rs:53:9 + | +LL | let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 13 previous errors diff --git a/tests/ui/map_collect_result_unit.stderr b/tests/ui/map_collect_result_unit.stderr index 8b06e13baa6b4..26e876b18081b 100644 --- a/tests/ui/map_collect_result_unit.stderr +++ b/tests/ui/map_collect_result_unit.stderr @@ -12,5 +12,22 @@ error: `.map().collect()` can be replaced with `.try_for_each()` LL | let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))` -error: aborting due to 2 previous errors +error: non-binding let on a type that implements `Drop` + --> $DIR/map_collect_result_unit.rs:14:5 + | +LL | let _ = (0..3).map(|t| Err(t + 1)).collect::, _>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/map_collect_result_unit.rs:15:5 + | +LL | let _ = (0..3).map(|t| Err(t + 1)).collect::>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 4 previous errors diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index b6479cd69eac4..6159b5256ee82 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,3 +1,12 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/map_flatten.rs:14:5 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::let-underscore-drop` implied by `-D warnings` + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `map(..).flatten()` on an `Iterator` --> $DIR/map_flatten.rs:14:46 | @@ -6,24 +15,56 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll | = note: `-D clippy::map-flatten` implied by `-D warnings` +error: non-binding let on a type that implements `Drop` + --> $DIR/map_flatten.rs:15:5 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `map(..).flatten()` on an `Iterator` --> $DIR/map_flatten.rs:15:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` +error: non-binding let on a type that implements `Drop` + --> $DIR/map_flatten.rs:16:5 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `map(..).flatten()` on an `Iterator` --> $DIR/map_flatten.rs:16:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` +error: non-binding let on a type that implements `Drop` + --> $DIR/map_flatten.rs:17:5 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `map(..).flatten()` on an `Iterator` --> $DIR/map_flatten.rs:17:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` +error: non-binding let on a type that implements `Drop` + --> $DIR/map_flatten.rs:20:5 + | +LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: called `map(..).flatten()` on an `Iterator` --> $DIR/map_flatten.rs:20:46 | @@ -36,5 +77,5 @@ error: called `map(..).flatten()` on an `Option` LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` -error: aborting due to 6 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/map_identity.stderr b/tests/ui/map_identity.stderr index e4a0320cbda55..6bfeb186badcf 100644 --- a/tests/ui/map_identity.stderr +++ b/tests/ui/map_identity.stderr @@ -1,3 +1,12 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/map_identity.rs:8:5 + | +LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: unnecessary map of the identity function --> $DIR/map_identity.rs:8:47 | @@ -6,6 +15,14 @@ LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); | = note: `-D clippy::map-identity` implied by `-D warnings` +error: non-binding let on a type that implements `Drop` + --> $DIR/map_identity.rs:9:5 + | +LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: unnecessary map of the identity function --> $DIR/map_identity.rs:9:57 | @@ -33,5 +50,21 @@ LL | | return x; LL | | }); | |______^ help: remove the call to `map` -error: aborting due to 5 previous errors +error: non-binding let on a type that implements `Drop` + --> $DIR/map_identity.rs:15:5 + | +LL | let _: Vec<_> = x.iter().map(|x| 2 * x).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: non-binding let on a type that implements `Drop` + --> $DIR/map_identity.rs:16:5 + | +LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 9 previous errors diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 795c8c3e24d7e..8b07599817b68 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -150,6 +150,20 @@ LL | let Point { x, y } = coords(); LL | let product = x * y; | +error: non-binding let on a type that implements `Drop` + --> $DIR/match_single_binding.rs:96:5 + | +LL | / let _ = v +LL | | .iter() +LL | | .map(|i| match i.unwrap() { +LL | | unwrapped => unwrapped, +LL | | }) +LL | | .collect::>(); + | |______________________________^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: this match could be written as a `let` statement --> $DIR/match_single_binding.rs:98:18 | @@ -167,5 +181,5 @@ LL | unwrapped LL | }) | -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index 9aa783bf904e1..cf04ee4b25726 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -90,6 +90,15 @@ help: change `v.clone()` to LL | let _ = v.to_owned(); | ^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/needless_pass_by_value.rs:85:5 + | +LL | let _ = v.clone(); + | ^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: this argument is passed by value, but not consumed in the function body --> $DIR/needless_pass_by_value.rs:94:12 | @@ -174,5 +183,5 @@ error: this argument is passed by value, but not consumed in the function body LL | fn more_fun(_item: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` -error: aborting due to 22 previous errors +error: aborting due to 23 previous errors diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index 89b3925429910..270c3fac99099 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -167,5 +167,14 @@ note: cloned value is neither consumed nor mutated LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ -error: aborting due to 14 previous errors +error: non-binding let on a type that implements `Drop` + --> $DIR/redundant_clone.rs:180:5 + | +LL | let _ = a.clone(); // OK + | ^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + +error: aborting due to 15 previous errors diff --git a/tests/ui/reversed_empty_ranges_fixable.stderr b/tests/ui/reversed_empty_ranges_fixable.stderr index de83c4f3d633c..707a5d5032ecd 100644 --- a/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/tests/ui/reversed_empty_ranges_fixable.stderr @@ -10,6 +10,15 @@ help: consider using the following if you are attempting to iterate over this ra LL | (21..=42).rev().for_each(|x| println!("{}", x)); | ^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/reversed_empty_ranges_fixable.rs:10:5 + | +LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: this range is empty so it will yield no values --> $DIR/reversed_empty_ranges_fixable.rs:10:13 | @@ -43,5 +52,5 @@ help: consider using the following if you are attempting to iterate over this ra LL | for _ in (21u32..42u32).rev() {} | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index ad9953d12bcc6..d6767dc9f1569 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -24,30 +24,71 @@ error: transmute from a reference to a pointer LL | let _: *const U = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute.rs:34:9 + | +LL | let _: Vec = core::intrinsics::transmute(my_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:34:27 | LL | let _: Vec = core::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute.rs:36:9 + | +LL | let _: Vec = core::mem::transmute(my_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:36:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute.rs:38:9 + | +LL | let _: Vec = std::intrinsics::transmute(my_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:38:27 | LL | let _: Vec = std::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute.rs:40:9 + | +LL | let _: Vec = std::mem::transmute(my_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:40:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute.rs:42:9 + | +LL | let _: Vec = my_transmute(my_vec()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:42:27 | @@ -154,5 +195,5 @@ error: transmute from a `&mut [u8]` to a `&mut str` LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` -error: aborting due to 24 previous errors +error: aborting due to 29 previous errors diff --git a/tests/ui/transmute_collection.stderr b/tests/ui/transmute_collection.stderr index ebc05c402abf6..e89f6d8539f2f 100644 --- a/tests/ui/transmute_collection.stderr +++ b/tests/ui/transmute_collection.stderr @@ -1,3 +1,12 @@ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute_collection.rs:9:9 + | +LL | let _ = transmute::<_, Vec>(vec![0u8]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from `std::vec::Vec` to `std::vec::Vec` with mismatched layout is unsound --> $DIR/transmute_collection.rs:9:17 | @@ -6,18 +15,42 @@ LL | let _ = transmute::<_, Vec>(vec![0u8]); | = note: `-D clippy::unsound-collection-transmute` implied by `-D warnings` +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute_collection.rs:11:9 + | +LL | let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from `std::vec::Vec` to `std::vec::Vec<[u8; 4]>` with mismatched layout is unsound --> $DIR/transmute_collection.rs:11:17 | LL | let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute_collection.rs:14:9 + | +LL | let _ = transmute::<_, VecDeque>(VecDeque::::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from `std::collections::VecDeque` to `std::collections::VecDeque` with mismatched layout is unsound --> $DIR/transmute_collection.rs:14:17 | LL | let _ = transmute::<_, VecDeque>(VecDeque::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute_collection.rs:16:9 + | +LL | let _ = transmute::<_, VecDeque>(VecDeque::<[u8; 4]>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from `std::collections::VecDeque<[u8; 4]>` to `std::collections::VecDeque` with mismatched layout is unsound --> $DIR/transmute_collection.rs:16:17 | @@ -60,24 +93,56 @@ error: transmute from `std::collections::HashSet<[u8; 4]>` to `std::collections: LL | let _ = transmute::<_, HashSet>(HashSet::<[u8; 4]>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute_collection.rs:34:9 + | +LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound --> $DIR/transmute_collection.rs:34:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute_collection.rs:35:9 + | +LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound --> $DIR/transmute_collection.rs:35:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute_collection.rs:37:9 + | +LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound --> $DIR/transmute_collection.rs:37:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: non-binding let on a type that implements `Drop` + --> $DIR/transmute_collection.rs:38:9 + | +LL | let _ = transmute::<_, BTreeMap>(BTreeMap::<[u8; 4], u32>::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: transmute from `std::collections::BTreeMap<[u8; 4], u32>` to `std::collections::BTreeMap` with mismatched layout is unsound --> $DIR/transmute_collection.rs:38:17 | @@ -108,5 +173,5 @@ error: transmute from `std::collections::HashMap<[u8; 4], u32>` to `std::collect LL | let _ = transmute::<_, HashMap>(HashMap::<[u8; 4], u32>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 18 previous errors +error: aborting due to 26 previous errors diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 5ffa6c4fd0616..1f89cb0cdef2d 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -24,6 +24,15 @@ error: using `.clone()` on a ref-counted pointer LL | arc_weak.clone(); | ^^^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&arc_weak)` +error: non-binding let on a type that implements `Drop` + --> $DIR/unnecessary_clone.rs:36:5 + | +LL | let _: Arc = x.clone(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:36:33 | @@ -102,5 +111,5 @@ error: using `.clone()` on a ref-counted pointer LL | Some(try_opt!(Some(rc)).clone()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::::clone(&try_opt!(Some(rc)))` -error: aborting due to 12 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 11c6efb25ccea..ea3e96111cb3e 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -52,6 +52,15 @@ error: useless conversion to the same type: `std::str::Lines` LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` +error: non-binding let on a type that implements `Drop` + --> $DIR/useless_conversion.rs:65:5 + | +LL | let _ = vec![1, 2, 3].into_iter().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(clippy::let_underscore_drop)]` on by default + = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` + error: useless conversion to the same type: `std::vec::IntoIter` --> $DIR/useless_conversion.rs:65:13 | @@ -70,5 +79,5 @@ error: useless conversion to the same type: `i32` LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` -error: aborting due to 11 previous errors +error: aborting due to 12 previous errors From 7c612c1c5086fb52bed1e0c8f222af109c448267 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Sun, 8 Nov 2020 16:14:38 +0100 Subject: [PATCH 028/118] Force contributors/reviewers to set _some_ changelog entry --- .github/PULL_REQUEST_TEMPLATE.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 6c92e10522c99..a3f114e0bb34f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,8 @@ Thank you for making Clippy better! We're collecting our changelog from pull request descriptions. -If your PR only updates to the latest nightly, you can leave the -`changelog` entry as `none`. Otherwise, please write a short comment +If your PR only includes internal changes, you can just write +`changelog: none`. Otherwise, please write a short comment explaining your change. If your PR fixes an issue, you can add "fixes #issue_number" into this @@ -28,5 +28,5 @@ Delete this line and everything above before opening your PR. --- -*Please keep the line below* -changelog: none +*Please write a short comment explaining your change (or "none" for internal only changes)* +changelog: From b0994064b03f1f9f8bdb8f594bdaec9dbaa0788a Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 29 Oct 2020 16:21:01 -0500 Subject: [PATCH 029/118] Make KNOW_TYPES static --- clippy_lints/src/methods/mod.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index a3fa3bdd36a56..5309253531bc5 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1803,6 +1803,14 @@ fn lint_or_fun_call<'tcx>( or_has_args: bool, span: Span, ) { + // (path, fn_has_argument, methods, suffix) + static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ + (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), + (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), + (&paths::RESULT, true, &["or", "unwrap_or"], "else"), + ]; + if let hir::ExprKind::MethodCall(ref path, _, ref args, _) = &arg.kind { if path.ident.as_str() == "len" { let ty = cx.typeck_results().expr_ty(&args[0]).peel_refs(); @@ -1818,16 +1826,8 @@ fn lint_or_fun_call<'tcx>( } } - // (path, fn_has_argument, methods, suffix) - let know_types: &[(&[_], _, &[_], _)] = &[ - (&paths::BTREEMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::HASHMAP_ENTRY, false, &["or_insert"], "with"), - (&paths::OPTION, false, &["map_or", "ok_or", "or", "unwrap_or"], "else"), - (&paths::RESULT, true, &["or", "unwrap_or"], "else"), - ]; - if_chain! { - if know_types.iter().any(|k| k.2.contains(&name)); + if KNOW_TYPES.iter().any(|k| k.2.contains(&name)); if is_lazyness_candidate(cx, arg); if !contains_return(&arg); @@ -1835,7 +1835,7 @@ fn lint_or_fun_call<'tcx>( let self_ty = cx.typeck_results().expr_ty(self_expr); if let Some(&(_, fn_has_arguments, poss, suffix)) = - know_types.iter().find(|&&i| match_type(cx, self_ty, i.0)); + KNOW_TYPES.iter().find(|&&i| match_type(cx, self_ty, i.0)); if poss.contains(&name); From 9cab08465b5d5b4bb4f5ff406b2e18ca550f7d93 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Thu, 29 Oct 2020 15:30:20 -0500 Subject: [PATCH 030/118] Fix or_fun_call for index operator --- clippy_lints/src/methods/mod.rs | 45 +++++++++++-------------- clippy_lints/src/utils/eager_or_lazy.rs | 7 +++- tests/ui/or_fun_call.fixed | 9 +++++ tests/ui/or_fun_call.rs | 9 +++++ tests/ui/or_fun_call.stderr | 18 ++++++++-- 5 files changed, 58 insertions(+), 30 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 5309253531bc5..b6fb3d06934ed 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1797,11 +1797,11 @@ fn lint_or_fun_call<'tcx>( cx: &LateContext<'tcx>, name: &str, method_span: Span, - fun_span: Span, self_expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, - or_has_args: bool, span: Span, + // None if lambda is required + fun_span: Option, ) { // (path, fn_has_argument, methods, suffix) static KNOW_TYPES: [(&[&str], bool, &[&str], &str); 4] = [ @@ -1840,10 +1840,18 @@ fn lint_or_fun_call<'tcx>( if poss.contains(&name); then { - let sugg: Cow<'_, _> = match (fn_has_arguments, !or_has_args) { - (true, _) => format!("|_| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), - (false, false) => format!("|| {}", snippet_with_macro_callsite(cx, arg.span, "..")).into(), - (false, true) => snippet_with_macro_callsite(cx, fun_span, ".."), + let sugg: Cow<'_, str> = { + let (snippet_span, use_lambda) = match (fn_has_arguments, fun_span) { + (false, Some(fun_span)) => (fun_span, false), + _ => (arg.span, true), + }; + let snippet = snippet_with_macro_callsite(cx, snippet_span, ".."); + if use_lambda { + let l_arg = if fn_has_arguments { "_" } else { "" }; + format!("|{}| {}", l_arg, snippet).into() + } else { + snippet + } }; let span_replace_word = method_span.with_hi(span.hi()); span_lint_and_sugg( @@ -1864,28 +1872,13 @@ fn lint_or_fun_call<'tcx>( hir::ExprKind::Call(ref fun, ref or_args) => { let or_has_args = !or_args.is_empty(); if !check_unwrap_or_default(cx, name, fun, &args[0], &args[1], or_has_args, expr.span) { - check_general_case( - cx, - name, - method_span, - fun.span, - &args[0], - &args[1], - or_has_args, - expr.span, - ); + let fun_span = if or_has_args { None } else { Some(fun.span) }; + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, fun_span); } }, - hir::ExprKind::MethodCall(_, span, ref or_args, _) => check_general_case( - cx, - name, - method_span, - span, - &args[0], - &args[1], - !or_args.is_empty(), - expr.span, - ), + hir::ExprKind::Index(..) | hir::ExprKind::MethodCall(..) => { + check_general_case(cx, name, method_span, &args[0], &args[1], expr.span, None); + }, _ => {}, } } diff --git a/clippy_lints/src/utils/eager_or_lazy.rs b/clippy_lints/src/utils/eager_or_lazy.rs index 4ceea13df377d..8fe5ddee1ca8d 100644 --- a/clippy_lints/src/utils/eager_or_lazy.rs +++ b/clippy_lints/src/utils/eager_or_lazy.rs @@ -9,7 +9,7 @@ //! - or-fun-call //! - option-if-let-else -use crate::utils::is_ctor_or_promotable_const_function; +use crate::utils::{is_ctor_or_promotable_const_function, is_type_diagnostic_item, match_type, paths}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit; @@ -96,6 +96,11 @@ fn identify_some_potentially_expensive_patterns<'tcx>(cx: &LateContext<'tcx>, ex let call_found = match &expr.kind { // ignore enum and struct constructors ExprKind::Call(..) => !is_ctor_or_promotable_const_function(self.cx, expr), + ExprKind::Index(obj, _) => { + let ty = self.cx.typeck_results().expr_ty(obj); + is_type_diagnostic_item(self.cx, ty, sym!(hashmap_type)) + || match_type(self.cx, ty, &paths::BTREEMAP) + }, ExprKind::MethodCall(..) => true, _ => false, }; diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 2045ffdb5f09d..20e5016bc17a0 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -70,6 +70,15 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + + // index + let map = HashMap::::new(); + let _ = Some(1).unwrap_or_else(|| map[&1]); + let map = BTreeMap::::new(); + let _ = Some(1).unwrap_or_else(|| map[&1]); + // don't lint index vec + let vec = vec![1]; + let _ = Some(1).unwrap_or(vec[1]); } struct Foo(u8); diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index 522f31b72d01f..e7192deeebb36 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -70,6 +70,15 @@ fn or_fun_call() { let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + + // index + let map = HashMap::::new(); + let _ = Some(1).unwrap_or(map[&1]); + let map = BTreeMap::::new(); + let _ = Some(1).unwrap_or(map[&1]); + // don't lint index vec + let vec = vec![1]; + let _ = Some(1).unwrap_or(vec[1]); } struct Foo(u8); diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index bc5978b538f16..d0c4df0e00817 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -78,17 +78,29 @@ error: use of `unwrap_or` followed by a function call LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:76:21 + | +LL | let _ = Some(1).unwrap_or(map[&1]); + | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + +error: use of `unwrap_or` followed by a function call + --> $DIR/or_fun_call.rs:78:21 + | +LL | let _ = Some(1).unwrap_or(map[&1]); + | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` + error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:93:35 + --> $DIR/or_fun_call.rs:102:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:97:10 + --> $DIR/or_fun_call.rs:106:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` -error: aborting due to 15 previous errors +error: aborting due to 17 previous errors From aa6bf1f90d9191cdf4c6d925f8137fa8eac37889 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius" <35515885+smoelius@users.noreply.github.com> Date: Sun, 8 Nov 2020 17:24:55 -0500 Subject: [PATCH 031/118] Update clippy_lints/src/let_underscore.rs Co-authored-by: Philipp Krones --- clippy_lints/src/let_underscore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index 9c7fd63454767..e8e64bca535cb 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { cx, LET_UNDERSCORE_DROP, local.span, - "non-binding let on a type that implements `Drop`", + "non-binding `let` on a type that implements `Drop`", None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" From 9751cba2c675c2cd46742d2a81c891d4db4deacc Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius" <35515885+smoelius@users.noreply.github.com> Date: Sun, 8 Nov 2020 17:25:23 -0500 Subject: [PATCH 032/118] Update clippy_lints/src/let_underscore.rs Co-authored-by: Philipp Krones --- clippy_lints/src/let_underscore.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index e8e64bca535cb..fb2df9369dc97 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -79,12 +79,20 @@ declare_clippy_lint! { /// impl Drop for Droppable { /// fn drop(&mut self) {} /// } - /// let _ = Droppable; + /// { + /// let _ = Droppable; + /// // ^ dropped here + /// /* more code */ + /// } /// ``` /// /// Good: /// ```rust,ignore - /// let _droppable = Droppable; + /// { + /// let _droppable = Droppable; + /// /* more code */ + /// // dropped at end of scope + /// } /// ``` pub LET_UNDERSCORE_DROP, correctness, From 8211b597baff7d599df8c1fe42f4e7d15b7d3e95 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius" <35515885+smoelius@users.noreply.github.com> Date: Sun, 8 Nov 2020 17:25:50 -0500 Subject: [PATCH 033/118] Update clippy_lints/src/let_underscore.rs Co-authored-by: Philipp Krones --- clippy_lints/src/let_underscore.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/let_underscore.rs b/clippy_lints/src/let_underscore.rs index fb2df9369dc97..6a5a77f8690a9 100644 --- a/clippy_lints/src/let_underscore.rs +++ b/clippy_lints/src/let_underscore.rs @@ -95,7 +95,7 @@ declare_clippy_lint! { /// } /// ``` pub LET_UNDERSCORE_DROP, - correctness, + pedantic, "non-binding let on a type that implements `Drop`" } From 40d7af50ed9811e427aa65b0111bca261ecf1239 Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sun, 8 Nov 2020 17:33:54 -0500 Subject: [PATCH 034/118] Update lints --- clippy_lints/src/lib.rs | 3 +-- src/lintlist/mod.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index b44e28b4596f6..20b38cbb6d0d5 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1241,6 +1241,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&infinite_iter::MAYBE_INFINITE_ITER), LintId::of(&items_after_statements::ITEMS_AFTER_STATEMENTS), LintId::of(&large_stack_arrays::LARGE_STACK_ARRAYS), + LintId::of(&let_underscore::LET_UNDERSCORE_DROP), LintId::of(&literal_representation::LARGE_DIGIT_GROUPS), LintId::of(&literal_representation::UNREADABLE_LITERAL), LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP), @@ -1384,7 +1385,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&len_zero::COMPARISON_TO_EMPTY), LintId::of(&len_zero::LEN_WITHOUT_IS_EMPTY), LintId::of(&len_zero::LEN_ZERO), - LintId::of(&let_underscore::LET_UNDERSCORE_DROP), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&lifetimes::EXTRA_UNUSED_LIFETIMES), LintId::of(&lifetimes::NEEDLESS_LIFETIMES), @@ -1811,7 +1811,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&infinite_iter::INFINITE_ITER), LintId::of(&inherent_to_string::INHERENT_TO_STRING_SHADOW_DISPLAY), LintId::of(&inline_fn_without_body::INLINE_FN_WITHOUT_BODY), - LintId::of(&let_underscore::LET_UNDERSCORE_DROP), LintId::of(&let_underscore::LET_UNDERSCORE_LOCK), LintId::of(&literal_representation::MISTYPED_LITERAL_SUFFIXES), LintId::of(&loops::FOR_LOOPS_OVER_FALLIBLES), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 8b5e6cc916f9d..4f1b56ed9bee5 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1119,7 +1119,7 @@ vec![ }, Lint { name: "let_underscore_drop", - group: "correctness", + group: "pedantic", desc: "non-binding let on a type that implements `Drop`", deprecation: None, module: "let_underscore", From 8845f10e945927ba9234f7a6411101eb980d45a3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 5 Nov 2020 20:27:48 +0300 Subject: [PATCH 035/118] Do not collect tokens for doc comments --- clippy_lints/src/attrs.rs | 2 +- clippy_lints/src/utils/ast_utils.rs | 2 +- clippy_lints/src/utils/attrs.rs | 2 +- clippy_lints/src/utils/mod.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index a004abb58b83e..55904a0ec0a84 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -588,7 +588,7 @@ impl EarlyLintPass for EarlyAttributes { fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { for attr in &item.attrs { - let attr_item = if let AttrKind::Normal(ref attr) = attr.kind { + let attr_item = if let AttrKind::Normal(ref attr, _) = attr.kind { attr } else { return; diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 0e9feef3746e7..b68e33f101d2b 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -509,7 +509,7 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { l.style == r.style && match (&l.kind, &r.kind) { (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2, - (Normal(l), Normal(r)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args), + (Normal(l, _), Normal(r, _)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args), _ => false, } } diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs index a3975683cb302..e6d41341a55f3 100644 --- a/clippy_lints/src/utils/attrs.rs +++ b/clippy_lints/src/utils/attrs.rs @@ -57,7 +57,7 @@ pub fn get_attr<'a>( name: &'static str, ) -> impl Iterator { attrs.iter().filter(move |attr| { - let attr = if let ast::AttrKind::Normal(ref attr) = attr.kind { + let attr = if let ast::AttrKind::Normal(ref attr, _) = attr.kind { attr } else { return false; diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 85e7f055e79de..0d43fd0392eb2 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1349,7 +1349,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { pub fn is_no_std_crate(krate: &Crate<'_>) -> bool { krate.item.attrs.iter().any(|attr| { - if let ast::AttrKind::Normal(ref attr) = attr.kind { + if let ast::AttrKind::Normal(ref attr, _) = attr.kind { attr.path == symbol::sym::no_std } else { false From 06e81bb49370a0154c3fa7de0bbc8b31c7bbe37b Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Sun, 8 Nov 2020 18:32:12 -0500 Subject: [PATCH 036/118] Update references --- tests/ui/borrow_box.stderr | 11 +-- .../others.stderr | 27 +------ tests/ui/box_vec.stderr | 15 +--- tests/ui/crashes/ice-4968.stderr | 11 --- tests/ui/crashes/ice-5223.stderr | 11 --- tests/ui/escape_analysis.stderr | 23 +----- tests/ui/eta.stderr | 19 +---- tests/ui/filter_methods.stderr | 8 +-- tests/ui/get_unwrap.stderr | 19 +---- tests/ui/into_iter_on_ref.stderr | 11 +-- tests/ui/iter_cloned_collect.stderr | 23 +----- tests/ui/let_underscore_drop.stderr | 6 +- tests/ui/map_clone.fixed | 1 + tests/ui/map_clone.rs | 1 + tests/ui/map_clone.stderr | 71 ++----------------- tests/ui/map_collect_result_unit.stderr | 19 +---- tests/ui/map_flatten.fixed | 1 + tests/ui/map_flatten.rs | 1 + tests/ui/map_flatten.stderr | 55 ++------------ tests/ui/map_identity.stderr | 35 +-------- tests/ui/match_single_binding.stderr | 16 +---- tests/ui/needless_pass_by_value.stderr | 11 +-- tests/ui/redundant_clone.stderr | 11 +-- tests/ui/reversed_empty_ranges_fixable.stderr | 11 +-- tests/ui/transmute.stderr | 43 +---------- tests/ui/transmute_collection.stderr | 67 +---------------- tests/ui/unnecessary_clone.stderr | 11 +-- tests/ui/useless_conversion.stderr | 11 +-- 28 files changed, 43 insertions(+), 506 deletions(-) delete mode 100644 tests/ui/crashes/ice-4968.stderr delete mode 100644 tests/ui/crashes/ice-5223.stderr diff --git a/tests/ui/borrow_box.stderr b/tests/ui/borrow_box.stderr index a40789cd42634..3eac32815be3f 100644 --- a/tests/ui/borrow_box.stderr +++ b/tests/ui/borrow_box.stderr @@ -22,15 +22,6 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` LL | fn test4(a: &Box); | ^^^^^^^^^^ help: try: `&bool` -error: non-binding let on a type that implements `Drop` - --> $DIR/borrow_box.rs:63:5 - | -LL | let _ = foo; - | ^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: you seem to be trying to use `&Box`. Consider using just `&T` --> $DIR/borrow_box.rs:95:25 | @@ -73,5 +64,5 @@ error: you seem to be trying to use `&Box`. Consider using just `&T` LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` -error: aborting due to 11 previous errors +error: aborting due to 10 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index 976c412c7a875..9a908cf30e945 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -47,15 +47,6 @@ LL | let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability | = help: assign this const to a local or static variable, and use the variable here -error: non-binding let on a type that implements `Drop` - --> $DIR/others.rs:72:5 - | -LL | let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:72:14 | @@ -104,22 +95,6 @@ LL | let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability | = help: assign this const to a local or static variable, and use the variable here -error: non-binding let on a type that implements `Drop` - --> $DIR/others.rs:83:5 - | -LL | let _ = ATOMIC_TUPLE.1.into_iter(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: non-binding let on a type that implements `Drop` - --> $DIR/others.rs:85:5 - | -LL | let _ = &{ ATOMIC_TUPLE }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: a `const` item with interior mutability should not be borrowed --> $DIR/others.rs:87:5 | @@ -136,5 +111,5 @@ LL | assert_eq!(CELL.get(), 6); //~ ERROR interior mutability | = help: assign this const to a local or static variable, and use the variable here -error: aborting due to 17 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/box_vec.stderr b/tests/ui/box_vec.stderr index a4983df1d3076..fca12eddd573f 100644 --- a/tests/ui/box_vec.stderr +++ b/tests/ui/box_vec.stderr @@ -1,16 +1,3 @@ -error: non-binding let on a type that implements `Drop` - --> $DIR/box_vec.rs:7:9 - | -LL | let _: Box<$x> = Box::new($init); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | boxit!(Vec::new(), Vec); - | ---------------------------- in this macro invocation - | - = note: `-D clippy::let-underscore-drop` implied by `-D warnings` - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) - error: you seem to be trying to use `Box>`. Consider using just `Vec` --> $DIR/box_vec.rs:14:18 | @@ -20,5 +7,5 @@ LL | pub fn test(foo: Box>) { = note: `-D clippy::box-vec` implied by `-D warnings` = help: `Vec` is already on the heap, `Box>` makes an extra allocation. -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/tests/ui/crashes/ice-4968.stderr b/tests/ui/crashes/ice-4968.stderr deleted file mode 100644 index 9ce39027451dc..0000000000000 --- a/tests/ui/crashes/ice-4968.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: non-binding let on a type that implements `Drop` - --> $DIR/ice-4968.rs:16:9 - | -LL | let _: Vec> = mem::transmute(slice); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: aborting due to previous error - diff --git a/tests/ui/crashes/ice-5223.stderr b/tests/ui/crashes/ice-5223.stderr deleted file mode 100644 index 3ae2dd5f7705f..0000000000000 --- a/tests/ui/crashes/ice-5223.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: non-binding let on a type that implements `Drop` - --> $DIR/ice-5223.rs:14:9 - | -LL | let _ = self.arr.iter().cloned().collect::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: aborting due to previous error - diff --git a/tests/ui/escape_analysis.stderr b/tests/ui/escape_analysis.stderr index 6e1c1c07b6eac..c86a769a3da4b 100644 --- a/tests/ui/escape_analysis.stderr +++ b/tests/ui/escape_analysis.stderr @@ -12,26 +12,5 @@ error: local variable doesn't need to be boxed here LL | pub fn new(_needs_name: Box>) -> () {} | ^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/escape_analysis.rs:166:9 - | -LL | / let _ = move || { -LL | | consume(x); -LL | | }; - | |__________^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: non-binding let on a type that implements `Drop` - --> $DIR/escape_analysis.rs:172:9 - | -LL | / let _ = || { -LL | | borrow(&x); -LL | | }; - | |__________^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/eta.stderr b/tests/ui/eta.stderr index bc79caee887f6..c4713ca8083dd 100644 --- a/tests/ui/eta.stderr +++ b/tests/ui/eta.stderr @@ -64,15 +64,6 @@ error: redundant closure found LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove closure as shown: `char::to_ascii_uppercase` -error: non-binding let on a type that implements `Drop` - --> $DIR/eta.rs:107:5 - | -LL | let _: Vec<_> = arr.iter().map(|x| x.map_err(|e| some.take().unwrap()(e))).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: redundant closure found --> $DIR/eta.rs:172:27 | @@ -85,13 +76,5 @@ error: redundant closure found LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: remove closure as shown: `closure` -error: non-binding let on a type that implements `Drop` - --> $DIR/eta.rs:203:5 - | -LL | let _ = [Bar].iter().map(|s| s.to_string()).collect::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: aborting due to 14 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index 08b781d73634e..b5ac90282dc90 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,4 +1,4 @@ -error: non-binding let on a type that implements `Drop` +error: non-binding `let` on a type that implements `Drop` --> $DIR/filter_methods.rs:5:5 | LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); @@ -16,7 +16,7 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * = note: `-D clippy::filter-map` implied by `-D warnings` = help: this is more succinctly expressed by calling `.filter_map(..)` instead -error: non-binding let on a type that implements `Drop` +error: non-binding `let` on a type that implements `Drop` --> $DIR/filter_methods.rs:7:5 | LL | / let _: Vec<_> = vec![5_i8; 6] @@ -40,7 +40,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` -error: non-binding let on a type that implements `Drop` +error: non-binding `let` on a type that implements `Drop` --> $DIR/filter_methods.rs:13:5 | LL | / let _: Vec<_> = vec![5_i8; 6] @@ -64,7 +64,7 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` -error: non-binding let on a type that implements `Drop` +error: non-binding `let` on a type that implements `Drop` --> $DIR/filter_methods.rs:19:5 | LL | / let _: Vec<_> = vec![5_i8; 6] diff --git a/tests/ui/get_unwrap.stderr b/tests/ui/get_unwrap.stderr index 6aa5452bac1c9..76a098df82aa1 100644 --- a/tests/ui/get_unwrap.stderr +++ b/tests/ui/get_unwrap.stderr @@ -70,34 +70,17 @@ error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]` -error: non-binding let on a type that implements `Drop` - --> $DIR/get_unwrap.rs:59:9 - | -LL | let _ = some_vec.get(0..1).unwrap().to_vec(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:59:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` -error: non-binding let on a type that implements `Drop` - --> $DIR/get_unwrap.rs:60:9 - | -LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise --> $DIR/get_unwrap.rs:60:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]` -error: aborting due to 15 previous errors +error: aborting due to 13 previous errors diff --git a/tests/ui/into_iter_on_ref.stderr b/tests/ui/into_iter_on_ref.stderr index efe9d20920b74..28003b365bbd5 100644 --- a/tests/ui/into_iter_on_ref.stderr +++ b/tests/ui/into_iter_on_ref.stderr @@ -1,12 +1,3 @@ -error: non-binding let on a type that implements `Drop` - --> $DIR/into_iter_on_ref.rs:13:5 - | -LL | let _ = vec![1, 2, 3].into_iter(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` --> $DIR/into_iter_on_ref.rs:14:30 | @@ -171,5 +162,5 @@ error: this `.into_iter()` call is equivalent to `.iter()` and will not consume LL | let _ = (&[1, 2, 3]).into_iter().next(); //~ WARN equivalent to .iter() | ^^^^^^^^^ help: call directly: `iter` -error: aborting due to 28 previous errors +error: aborting due to 27 previous errors diff --git a/tests/ui/iter_cloned_collect.stderr b/tests/ui/iter_cloned_collect.stderr index f5cd43b3da542..b90a1e6c91967 100644 --- a/tests/ui/iter_cloned_collect.stderr +++ b/tests/ui/iter_cloned_collect.stderr @@ -6,33 +6,12 @@ LL | let v2: Vec = v.iter().cloned().collect(); | = note: `-D clippy::iter-cloned-collect` implied by `-D warnings` -error: non-binding let on a type that implements `Drop` - --> $DIR/iter_cloned_collect.rs:15:5 - | -LL | let _: Vec = vec![1, 2, 3].iter().cloned().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable --> $DIR/iter_cloned_collect.rs:15:38 | LL | let _: Vec = vec![1, 2, 3].iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` -error: non-binding let on a type that implements `Drop` - --> $DIR/iter_cloned_collect.rs:19:9 - | -LL | / let _: Vec = std::ffi::CStr::from_ptr(std::ptr::null()) -LL | | .to_bytes() -LL | | .iter() -LL | | .cloned() -LL | | .collect(); - | |_______________________^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable --> $DIR/iter_cloned_collect.rs:20:24 | @@ -43,5 +22,5 @@ LL | | .cloned() LL | | .collect(); | |______________________^ help: try: `.to_vec()` -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/let_underscore_drop.stderr b/tests/ui/let_underscore_drop.stderr index 6dc8904c4fe95..66069e0c5e13f 100644 --- a/tests/ui/let_underscore_drop.stderr +++ b/tests/ui/let_underscore_drop.stderr @@ -1,4 +1,4 @@ -error: non-binding let on a type that implements `Drop` +error: non-binding `let` on a type that implements `Drop` --> $DIR/let_underscore_drop.rs:16:5 | LL | let _ = Box::new(()); @@ -7,7 +7,7 @@ LL | let _ = Box::new(()); = note: `-D clippy::let-underscore-drop` implied by `-D warnings` = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` -error: non-binding let on a type that implements `Drop` +error: non-binding `let` on a type that implements `Drop` --> $DIR/let_underscore_drop.rs:17:5 | LL | let _ = Droppable; @@ -15,7 +15,7 @@ LL | let _ = Droppable; | = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` -error: non-binding let on a type that implements `Drop` +error: non-binding `let` on a type that implements `Drop` --> $DIR/let_underscore_drop.rs:18:5 | LL | let _ = Some(Droppable); diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index 6e3a8e67e811e..ce92b3c0c3039 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::iter_cloned_collect)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::redundant_closure_for_method_calls)] #![allow(clippy::many_single_char_names)] diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 6fd395710d4ba..324c776c3c9aa 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -2,6 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::iter_cloned_collect)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::redundant_closure_for_method_calls)] #![allow(clippy::many_single_char_names)] diff --git a/tests/ui/map_clone.stderr b/tests/ui/map_clone.stderr index 122a678f1188f..d84a5bf8d4de6 100644 --- a/tests/ui/map_clone.stderr +++ b/tests/ui/map_clone.stderr @@ -1,97 +1,40 @@ -error: non-binding let on a type that implements `Drop` - --> $DIR/map_clone.rs:10:5 - | -LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::let-underscore-drop` implied by `-D warnings` - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:10:22 + --> $DIR/map_clone.rs:11:22 | LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![5_i8; 6].iter().copied()` | = note: `-D clippy::map-clone` implied by `-D warnings` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_clone.rs:11:5 - | -LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: you are using an explicit closure for cloning elements - --> $DIR/map_clone.rs:11:26 + --> $DIR/map_clone.rs:12:26 | LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_clone.rs:12:5 - | -LL | let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: you are using an explicit closure for copying elements - --> $DIR/map_clone.rs:12:23 + --> $DIR/map_clone.rs:13:23 | LL | let _: Vec = 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:14:26 + --> $DIR/map_clone.rs:15:26 | LL | let _: Option = 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:15:25 + --> $DIR/map_clone.rs:16:25 | LL | let _: Option = 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:26:29 + --> $DIR/map_clone.rs:27:29 | LL | let _ = std::env::args().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call -error: non-binding let on a type that implements `Drop` - --> $DIR/map_clone.rs:35:9 - | -LL | let _: Vec = v.into_iter().map(|x| *x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: non-binding let on a type that implements `Drop` - --> $DIR/map_clone.rs:42:9 - | -LL | let _: Vec = v.into_iter().map(|x| *x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: non-binding let on a type that implements `Drop` - --> $DIR/map_clone.rs:45:9 - | -LL | let _: Vec = v.into_iter().map(|&mut x| x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: non-binding let on a type that implements `Drop` - --> $DIR/map_clone.rs:53:9 - | -LL | let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: aborting due to 13 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/map_collect_result_unit.stderr b/tests/ui/map_collect_result_unit.stderr index 26e876b18081b..8b06e13baa6b4 100644 --- a/tests/ui/map_collect_result_unit.stderr +++ b/tests/ui/map_collect_result_unit.stderr @@ -12,22 +12,5 @@ error: `.map().collect()` can be replaced with `.try_for_each()` LL | let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(0..3).try_for_each(|t| Err(t + 1))` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_collect_result_unit.rs:14:5 - | -LL | let _ = (0..3).map(|t| Err(t + 1)).collect::, _>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: non-binding let on a type that implements `Drop` - --> $DIR/map_collect_result_unit.rs:15:5 - | -LL | let _ = (0..3).map(|t| Err(t + 1)).collect::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed index a5fdf7df613d3..a7ab5a12cb765 100644 --- a/tests/ui/map_flatten.fixed +++ b/tests/ui/map_flatten.fixed @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index abbc4e16e5679..e364a05f37605 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -1,6 +1,7 @@ // run-rustfix #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index 6159b5256ee82..d4e27f9aa0750 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,81 +1,40 @@ -error: non-binding let on a type that implements `Drop` - --> $DIR/map_flatten.rs:14:5 - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::let-underscore-drop` implied by `-D warnings` - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:14:46 + --> $DIR/map_flatten.rs:15:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)` | = note: `-D clippy::map-flatten` implied by `-D warnings` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_flatten.rs:15:5 - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:15:46 + --> $DIR/map_flatten.rs:16:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_flatten.rs:16:5 - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:16:46 + --> $DIR/map_flatten.rs:17:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_flatten.rs:17:5 - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:17:46 + --> $DIR/map_flatten.rs:18:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_flatten.rs:20:5 - | -LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:20:46 + --> $DIR/map_flatten.rs:21:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)` error: called `map(..).flatten()` on an `Option` - --> $DIR/map_flatten.rs:23:39 + --> $DIR/map_flatten.rs:24:39 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` -error: aborting due to 11 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/map_identity.stderr b/tests/ui/map_identity.stderr index 6bfeb186badcf..e4a0320cbda55 100644 --- a/tests/ui/map_identity.stderr +++ b/tests/ui/map_identity.stderr @@ -1,12 +1,3 @@ -error: non-binding let on a type that implements `Drop` - --> $DIR/map_identity.rs:8:5 - | -LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: unnecessary map of the identity function --> $DIR/map_identity.rs:8:47 | @@ -15,14 +6,6 @@ LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); | = note: `-D clippy::map-identity` implied by `-D warnings` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_identity.rs:9:5 - | -LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: unnecessary map of the identity function --> $DIR/map_identity.rs:9:57 | @@ -50,21 +33,5 @@ LL | | return x; LL | | }); | |______^ help: remove the call to `map` -error: non-binding let on a type that implements `Drop` - --> $DIR/map_identity.rs:15:5 - | -LL | let _: Vec<_> = x.iter().map(|x| 2 * x).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: non-binding let on a type that implements `Drop` - --> $DIR/map_identity.rs:16:5 - | -LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: aborting due to 9 previous errors +error: aborting due to 5 previous errors diff --git a/tests/ui/match_single_binding.stderr b/tests/ui/match_single_binding.stderr index 8b07599817b68..795c8c3e24d7e 100644 --- a/tests/ui/match_single_binding.stderr +++ b/tests/ui/match_single_binding.stderr @@ -150,20 +150,6 @@ LL | let Point { x, y } = coords(); LL | let product = x * y; | -error: non-binding let on a type that implements `Drop` - --> $DIR/match_single_binding.rs:96:5 - | -LL | / let _ = v -LL | | .iter() -LL | | .map(|i| match i.unwrap() { -LL | | unwrapped => unwrapped, -LL | | }) -LL | | .collect::>(); - | |______________________________^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: this match could be written as a `let` statement --> $DIR/match_single_binding.rs:98:18 | @@ -181,5 +167,5 @@ LL | unwrapped LL | }) | -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/needless_pass_by_value.stderr b/tests/ui/needless_pass_by_value.stderr index cf04ee4b25726..9aa783bf904e1 100644 --- a/tests/ui/needless_pass_by_value.stderr +++ b/tests/ui/needless_pass_by_value.stderr @@ -90,15 +90,6 @@ help: change `v.clone()` to LL | let _ = v.to_owned(); | ^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/needless_pass_by_value.rs:85:5 - | -LL | let _ = v.clone(); - | ^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: this argument is passed by value, but not consumed in the function body --> $DIR/needless_pass_by_value.rs:94:12 | @@ -183,5 +174,5 @@ error: this argument is passed by value, but not consumed in the function body LL | fn more_fun(_item: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` -error: aborting due to 23 previous errors +error: aborting due to 22 previous errors diff --git a/tests/ui/redundant_clone.stderr b/tests/ui/redundant_clone.stderr index 270c3fac99099..89b3925429910 100644 --- a/tests/ui/redundant_clone.stderr +++ b/tests/ui/redundant_clone.stderr @@ -167,14 +167,5 @@ note: cloned value is neither consumed nor mutated LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/redundant_clone.rs:180:5 - | -LL | let _ = a.clone(); // OK - | ^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors diff --git a/tests/ui/reversed_empty_ranges_fixable.stderr b/tests/ui/reversed_empty_ranges_fixable.stderr index 707a5d5032ecd..de83c4f3d633c 100644 --- a/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/tests/ui/reversed_empty_ranges_fixable.stderr @@ -10,15 +10,6 @@ help: consider using the following if you are attempting to iterate over this ra LL | (21..=42).rev().for_each(|x| println!("{}", x)); | ^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/reversed_empty_ranges_fixable.rs:10:5 - | -LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: this range is empty so it will yield no values --> $DIR/reversed_empty_ranges_fixable.rs:10:13 | @@ -52,5 +43,5 @@ help: consider using the following if you are attempting to iterate over this ra LL | for _ in (21u32..42u32).rev() {} | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/transmute.stderr b/tests/ui/transmute.stderr index d6767dc9f1569..ad9953d12bcc6 100644 --- a/tests/ui/transmute.stderr +++ b/tests/ui/transmute.stderr @@ -24,71 +24,30 @@ error: transmute from a reference to a pointer LL | let _: *const U = core::intrinsics::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute.rs:34:9 - | -LL | let _: Vec = core::intrinsics::transmute(my_vec()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:34:27 | LL | let _: Vec = core::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute.rs:36:9 - | -LL | let _: Vec = core::mem::transmute(my_vec()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:36:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute.rs:38:9 - | -LL | let _: Vec = std::intrinsics::transmute(my_vec()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:38:27 | LL | let _: Vec = std::intrinsics::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute.rs:40:9 - | -LL | let _: Vec = std::mem::transmute(my_vec()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:40:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute.rs:42:9 - | -LL | let _: Vec = my_transmute(my_vec()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from a type (`std::vec::Vec`) to itself --> $DIR/transmute.rs:42:27 | @@ -195,5 +154,5 @@ error: transmute from a `&mut [u8]` to a `&mut str` LL | let _: &mut str = unsafe { std::mem::transmute(mb) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()` -error: aborting due to 29 previous errors +error: aborting due to 24 previous errors diff --git a/tests/ui/transmute_collection.stderr b/tests/ui/transmute_collection.stderr index e89f6d8539f2f..ebc05c402abf6 100644 --- a/tests/ui/transmute_collection.stderr +++ b/tests/ui/transmute_collection.stderr @@ -1,12 +1,3 @@ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute_collection.rs:9:9 - | -LL | let _ = transmute::<_, Vec>(vec![0u8]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from `std::vec::Vec` to `std::vec::Vec` with mismatched layout is unsound --> $DIR/transmute_collection.rs:9:17 | @@ -15,42 +6,18 @@ LL | let _ = transmute::<_, Vec>(vec![0u8]); | = note: `-D clippy::unsound-collection-transmute` implied by `-D warnings` -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute_collection.rs:11:9 - | -LL | let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from `std::vec::Vec` to `std::vec::Vec<[u8; 4]>` with mismatched layout is unsound --> $DIR/transmute_collection.rs:11:17 | LL | let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute_collection.rs:14:9 - | -LL | let _ = transmute::<_, VecDeque>(VecDeque::::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from `std::collections::VecDeque` to `std::collections::VecDeque` with mismatched layout is unsound --> $DIR/transmute_collection.rs:14:17 | LL | let _ = transmute::<_, VecDeque>(VecDeque::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute_collection.rs:16:9 - | -LL | let _ = transmute::<_, VecDeque>(VecDeque::<[u8; 4]>::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from `std::collections::VecDeque<[u8; 4]>` to `std::collections::VecDeque` with mismatched layout is unsound --> $DIR/transmute_collection.rs:16:17 | @@ -93,56 +60,24 @@ error: transmute from `std::collections::HashSet<[u8; 4]>` to `std::collections: LL | let _ = transmute::<_, HashSet>(HashSet::<[u8; 4]>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute_collection.rs:34:9 - | -LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound --> $DIR/transmute_collection.rs:34:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute_collection.rs:35:9 - | -LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound --> $DIR/transmute_collection.rs:35:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute_collection.rs:37:9 - | -LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from `std::collections::BTreeMap` to `std::collections::BTreeMap` with mismatched layout is unsound --> $DIR/transmute_collection.rs:37:17 | LL | let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: non-binding let on a type that implements `Drop` - --> $DIR/transmute_collection.rs:38:9 - | -LL | let _ = transmute::<_, BTreeMap>(BTreeMap::<[u8; 4], u32>::new()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: transmute from `std::collections::BTreeMap<[u8; 4], u32>` to `std::collections::BTreeMap` with mismatched layout is unsound --> $DIR/transmute_collection.rs:38:17 | @@ -173,5 +108,5 @@ error: transmute from `std::collections::HashMap<[u8; 4], u32>` to `std::collect LL | let _ = transmute::<_, HashMap>(HashMap::<[u8; 4], u32>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 26 previous errors +error: aborting due to 18 previous errors diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr index 1f89cb0cdef2d..5ffa6c4fd0616 100644 --- a/tests/ui/unnecessary_clone.stderr +++ b/tests/ui/unnecessary_clone.stderr @@ -24,15 +24,6 @@ error: using `.clone()` on a ref-counted pointer LL | arc_weak.clone(); | ^^^^^^^^^^^^^^^^ help: try this: `Weak::::clone(&arc_weak)` -error: non-binding let on a type that implements `Drop` - --> $DIR/unnecessary_clone.rs:36:5 - | -LL | let _: Arc = x.clone(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: using `.clone()` on a ref-counted pointer --> $DIR/unnecessary_clone.rs:36:33 | @@ -111,5 +102,5 @@ error: using `.clone()` on a ref-counted pointer LL | Some(try_opt!(Some(rc)).clone()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::::clone(&try_opt!(Some(rc)))` -error: aborting due to 13 previous errors +error: aborting due to 12 previous errors diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index ea3e96111cb3e..11c6efb25ccea 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -52,15 +52,6 @@ error: useless conversion to the same type: `std::str::Lines` LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` -error: non-binding let on a type that implements `Drop` - --> $DIR/useless_conversion.rs:65:5 - | -LL | let _ = vec![1, 2, 3].into_iter().into_iter(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(clippy::let_underscore_drop)]` on by default - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: useless conversion to the same type: `std::vec::IntoIter` --> $DIR/useless_conversion.rs:65:13 | @@ -79,5 +70,5 @@ error: useless conversion to the same type: `i32` LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors From 4852cca61bb989adf77b1d202eae6b40067fa9ab Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Mon, 9 Nov 2020 07:49:14 -0500 Subject: [PATCH 037/118] Allow `let_underscore_drop` in `filter_methods` test --- tests/ui/filter_methods.rs | 1 + tests/ui/filter_methods.stderr | 55 ++++------------------------------ 2 files changed, 6 insertions(+), 50 deletions(-) diff --git a/tests/ui/filter_methods.rs b/tests/ui/filter_methods.rs index ef434245fd70c..5145024161926 100644 --- a/tests/ui/filter_methods.rs +++ b/tests/ui/filter_methods.rs @@ -1,4 +1,5 @@ #![warn(clippy::all, clippy::pedantic)] +#![allow(clippy::clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] fn main() { diff --git a/tests/ui/filter_methods.stderr b/tests/ui/filter_methods.stderr index b5ac90282dc90..119226813793c 100644 --- a/tests/ui/filter_methods.stderr +++ b/tests/ui/filter_methods.stderr @@ -1,14 +1,5 @@ -error: non-binding `let` on a type that implements `Drop` - --> $DIR/filter_methods.rs:5:5 - | -LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `-D clippy::let-underscore-drop` implied by `-D warnings` - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `filter(..).map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:5:21 + --> $DIR/filter_methods.rs:6:21 | LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * 2).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,20 +7,8 @@ LL | let _: Vec<_> = vec![5; 6].into_iter().filter(|&x| x == 0).map(|x| x * = note: `-D clippy::filter-map` implied by `-D warnings` = help: this is more succinctly expressed by calling `.filter_map(..)` instead -error: non-binding `let` on a type that implements `Drop` - --> $DIR/filter_methods.rs:7:5 - | -LL | / let _: Vec<_> = vec![5_i8; 6] -LL | | .into_iter() -LL | | .filter(|&x| x == 0) -LL | | .flat_map(|x| x.checked_mul(2)) -LL | | .collect(); - | |___________________^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `filter(..).flat_map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:7:21 + --> $DIR/filter_methods.rs:8:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -40,20 +19,8 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` -error: non-binding `let` on a type that implements `Drop` - --> $DIR/filter_methods.rs:13:5 - | -LL | / let _: Vec<_> = vec![5_i8; 6] -LL | | .into_iter() -LL | | .filter_map(|x| x.checked_mul(2)) -LL | | .flat_map(|x| x.checked_mul(2)) -LL | | .collect(); - | |___________________^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `filter_map(..).flat_map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:13:21 + --> $DIR/filter_methods.rs:14:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -64,20 +31,8 @@ LL | | .flat_map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by calling `.flat_map(..)` and filtering by returning `iter::empty()` -error: non-binding `let` on a type that implements `Drop` - --> $DIR/filter_methods.rs:19:5 - | -LL | / let _: Vec<_> = vec![5_i8; 6] -LL | | .into_iter() -LL | | .filter_map(|x| x.checked_mul(2)) -LL | | .map(|x| x.checked_mul(2)) -LL | | .collect(); - | |___________________^ - | - = help: consider using an underscore-prefixed named binding or dropping explicitly with `std::mem::drop` - error: called `filter_map(..).map(..)` on an `Iterator` - --> $DIR/filter_methods.rs:19:21 + --> $DIR/filter_methods.rs:20:21 | LL | let _: Vec<_> = vec![5_i8; 6] | _____________________^ @@ -88,5 +43,5 @@ LL | | .map(|x| x.checked_mul(2)) | = help: this is more succinctly expressed by only calling `.filter_map(..)` instead -error: aborting due to 8 previous errors +error: aborting due to 4 previous errors From effcb52bbf818ca39c57f9beb7d7d63b1e47d1fd Mon Sep 17 00:00:00 2001 From: Eduardo Broto Date: Tue, 10 Nov 2020 22:33:02 +0100 Subject: [PATCH 038/118] Run cargo dev fmt --- clippy_lints/src/non_expressive_names.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs index 6b175490cc833..5b42b61fcde90 100644 --- a/clippy_lints/src/non_expressive_names.rs +++ b/clippy_lints/src/non_expressive_names.rs @@ -1,7 +1,5 @@ use crate::utils::{span_lint, span_lint_and_then}; -use rustc_ast::ast::{ - Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind, -}; +use rustc_ast::ast::{Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind}; use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_middle::lint::in_external_macro; From 769094410a22849c426972dd421a1937463a48e7 Mon Sep 17 00:00:00 2001 From: Cameron Steffen Date: Fri, 30 Oct 2020 09:18:16 -0500 Subject: [PATCH 039/118] Fix map_clone with deref and clone --- clippy_lints/src/map_clone.rs | 14 +++++++++----- tests/ui/map_clone.fixed | 7 +++++++ tests/ui/map_clone.rs | 7 +++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 9a00608ce3947..3f34dd5112eff 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -8,6 +8,7 @@ use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir::Mutability; use rustc_middle::ty; +use rustc_middle::ty::adjustment::Adjust; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span}; @@ -75,11 +76,14 @@ impl<'tcx> LateLintPass<'tcx> for MapClone { } } }, - hir::ExprKind::MethodCall(ref method, _, ref obj, _) => { - if ident_eq(name, &obj[0]) && method.ident.as_str() == "clone" - && match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT) { - - let obj_ty = cx.typeck_results().expr_ty(&obj[0]); + hir::ExprKind::MethodCall(ref method, _, [obj], _) => if_chain! { + if ident_eq(name, obj) && method.ident.name == sym::clone; + if match_trait_method(cx, closure_expr, &paths::CLONE_TRAIT); + // no autoderefs + if !cx.typeck_results().expr_adjustments(obj).iter() + .any(|a| matches!(a.kind, Adjust::Deref(Some(..)))); + then { + let obj_ty = cx.typeck_results().expr_ty(obj); if let ty::Ref(_, ty, mutability) = obj_ty.kind() { if matches!(mutability, Mutability::Not) { let copy = is_copy(cx, ty); diff --git a/tests/ui/map_clone.fixed b/tests/ui/map_clone.fixed index 6e3a8e67e811e..504ae281fe7c6 100644 --- a/tests/ui/map_clone.fixed +++ b/tests/ui/map_clone.fixed @@ -52,4 +52,11 @@ fn main() { let items = vec![&mut aa, &mut bb]; let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); } + + // Issue #6239 deref coercion and clone deref + { + use std::cell::RefCell; + + let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone()); + } } diff --git a/tests/ui/map_clone.rs b/tests/ui/map_clone.rs index 6fd395710d4ba..9348e6bae7a57 100644 --- a/tests/ui/map_clone.rs +++ b/tests/ui/map_clone.rs @@ -52,4 +52,11 @@ fn main() { let items = vec![&mut aa, &mut bb]; let _: Vec<_> = items.into_iter().map(|x| x.clone()).collect(); } + + // Issue #6239 deref coercion and clone deref + { + use std::cell::RefCell; + + let _ = Some(RefCell::new(String::new()).borrow()).map(|s| s.clone()); + } } From a1cf2d334d685fa11fdc96fc98f35292254e5651 Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Mon, 5 Oct 2020 21:23:36 -0700 Subject: [PATCH 040/118] Added a lint as suggested in 6010 which recommends using `contains()` instead of `find()` follows by `is_some()` on strings Update clippy_lints/src/find_is_some_on_strs.rs Co-authored-by: Takayuki Nakata Update clippy_lints/src/methods/mod.rs Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 38 ++++++++++++++++++++++++++++++--- src/lintlist/mod.rs | 2 +- tests/ui/methods.rs | 23 ++++++++++++++++++-- tests/ui/methods.stderr | 2 -- 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index b6fb3d06934ed..bd04a95e4a193 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -515,11 +515,11 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for an iterator search (such as `find()`, + /// **What it does:** Checks for an iterator or string search (such as `find()`, /// `position()`, or `rposition()`) followed by a call to `is_some()`. /// /// **Why is this bad?** Readability, this can be written more concisely as - /// `_.any(_)`. + /// `_.any(_)` or `_.contains(_)`. /// /// **Known problems:** None. /// @@ -535,7 +535,7 @@ declare_clippy_lint! { /// ``` pub SEARCH_IS_SOME, complexity, - "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`" + "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`" } declare_clippy_lint! { @@ -3041,6 +3041,7 @@ fn lint_flat_map_identity<'tcx>( } /// lint searching an Iterator followed by `is_some()` +/// or calling `find()` on a string followed by `is_some()` fn lint_search_is_some<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, @@ -3094,6 +3095,37 @@ fn lint_search_is_some<'tcx>( span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); } } + // lint if `find()` is called by `String` or `&str` + else if search_method == "find" { + let is_string_or_str_slice = |e| { + let self_ty = cx.typeck_results().expr_ty(e).peel_refs(); + if is_type_diagnostic_item(cx, self_ty, sym!(string_type)) { + true + } else { + *self_ty.kind() == ty::Str + } + }; + if_chain! { + if is_string_or_str_slice(&search_args[0]); + if is_string_or_str_slice(&search_args[1]); + then { + let msg = "called `is_some()` after calling `find()` \ + on a string. This is more succinctly expressed by calling \ + `contains()`.".to_string(); + let mut applicability = Applicability::MachineApplicable; + let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); + span_lint_and_sugg( + cx, + SEARCH_IS_SOME, + method_span.with_hi(expr.span.hi()), + &msg, + "try this", + format!("contains({})", find_arg), + applicability, + ); + } + } + } } /// Used for `lint_binary_expr_with_method_call`. diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 4f1b56ed9bee5..69acd3d9b8bc5 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2121,7 +2121,7 @@ vec![ Lint { name: "search_is_some", group: "complexity", - desc: "using an iterator search followed by `is_some()`, which is more succinctly expressed as a call to `any()`", + desc: "using an iterator or string search followed by `is_some()`, which is more succinctly expressed as a call to `any()` or `contains()`", deprecation: None, module: "methods", }, diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index d93e5b114ecfa..92ec00a11d27e 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -168,8 +168,27 @@ fn search_is_some() { x < 0 } ).is_some(); - - // Check that we don't lint if the caller is not an `Iterator`. + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + // Check caller `find()` is a &`static str case + let _ = "hello world".find("world").is_some(); + let _ = "hello world".find(&s2).is_some(); + let _ = "hello world".find(&s2[2..]).is_some(); + // Check caller of `find()` is a String case + let _ = s1.find("world").is_some(); + let _ = s1.find(&s2).is_some(); + let _ = s1.find(&s2[2..]).is_some(); + // Check caller of `find()` is a slice of String case + let _ = s1[2..].find("world").is_some(); + let _ = s1[2..].find(&s2).is_some(); + let _ = s1[2..].find(&s2[2..]).is_some(); + + // Check that we don't lint if `find()` is called with + // Pattern that is not a string + let _ = s1.find(|c: char| c == 'o' || c == 'l').is_some(); + + // Check that we don't lint if the caller is not an `Iterator` or string let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.find().is_some(); let _ = foo.position().is_some(); diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index 8a281c2dbd25c..b2b551bd5f868 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -88,5 +88,3 @@ LL | | } LL | | ).is_some(); | |______________________________^ -error: aborting due to 11 previous errors - From 431fcbcc00eb4634178406c1afdf955e5b3be07a Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Sat, 17 Oct 2020 14:07:22 -0700 Subject: [PATCH 041/118] Moved the tests for lint `search_is_some` to new files `search_is_some.rs` and `search_is_some_fixable.rs` --- tests/ui/methods.rs | 63 ------------------------------ tests/ui/search_is_some.rs | 39 ++++++++++++++++++ tests/ui/search_is_some_fixable.rs | 35 +++++++++++++++++ 3 files changed, 74 insertions(+), 63 deletions(-) create mode 100644 tests/ui/search_is_some.rs create mode 100644 tests/ui/search_is_some_fixable.rs diff --git a/tests/ui/methods.rs b/tests/ui/methods.rs index 92ec00a11d27e..513d930e05687 100644 --- a/tests/ui/methods.rs +++ b/tests/ui/methods.rs @@ -133,69 +133,6 @@ fn filter_next() { let _ = foo.filter().next(); } -/// Checks implementation of `SEARCH_IS_SOME` lint. -#[rustfmt::skip] -fn search_is_some() { - let v = vec![3, 2, 1, 0, -1, -2, -3]; - let y = &&42; - - // Check `find().is_some()`, single-line case. - let _ = v.iter().find(|&x| *x < 0).is_some(); - let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - let _ = (0..1).find(|x| *x == 0).is_some(); - let _ = v.iter().find(|x| **x == 0).is_some(); - - // Check `find().is_some()`, multi-line case. - let _ = v.iter().find(|&x| { - *x < 0 - } - ).is_some(); - - // Check `position().is_some()`, single-line case. - let _ = v.iter().position(|&x| x < 0).is_some(); - - // Check `position().is_some()`, multi-line case. - let _ = v.iter().position(|&x| { - x < 0 - } - ).is_some(); - - // Check `rposition().is_some()`, single-line case. - let _ = v.iter().rposition(|&x| x < 0).is_some(); - - // Check `rposition().is_some()`, multi-line case. - let _ = v.iter().rposition(|&x| { - x < 0 - } - ).is_some(); - - let s1 = String::from("hello world"); - let s2 = String::from("world"); - // Check caller `find()` is a &`static str case - let _ = "hello world".find("world").is_some(); - let _ = "hello world".find(&s2).is_some(); - let _ = "hello world".find(&s2[2..]).is_some(); - // Check caller of `find()` is a String case - let _ = s1.find("world").is_some(); - let _ = s1.find(&s2).is_some(); - let _ = s1.find(&s2[2..]).is_some(); - // Check caller of `find()` is a slice of String case - let _ = s1[2..].find("world").is_some(); - let _ = s1[2..].find(&s2).is_some(); - let _ = s1[2..].find(&s2[2..]).is_some(); - - // Check that we don't lint if `find()` is called with - // Pattern that is not a string - let _ = s1.find(|c: char| c == 'o' || c == 'l').is_some(); - - // Check that we don't lint if the caller is not an `Iterator` or string - let foo = IteratorFalsePositives { foo: 0 }; - let _ = foo.find().is_some(); - let _ = foo.position().is_some(); - let _ = foo.rposition().is_some(); -} - fn main() { filter_next(); - search_is_some(); } diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs new file mode 100644 index 0000000000000..1ce372ab1d374 --- /dev/null +++ b/tests/ui/search_is_some.rs @@ -0,0 +1,39 @@ +#[macro_use] +extern crate option_helpers; +use option_helpers::IteratorFalsePositives; + +#[warn(clippy::search_is_some)] +#[rustfmt::skip] +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + + // Check `find().is_some()`, multi-line case. + let _ = v.iter().find(|&x| { + *x < 0 + } + ).is_some(); + + // Check `position().is_some()`, multi-line case. + let _ = v.iter().position(|&x| { + x < 0 + } + ).is_some(); + + // Check `rposition().is_some()`, multi-line case. + let _ = v.iter().rposition(|&x| { + x < 0 + } + ).is_some(); + + // Check that we don't lint if the caller is not an `Iterator` or string + let foo = IteratorFalsePositives { foo: 0 }; + let _ = foo.find().is_some(); + let _ = foo.position().is_some(); + let _ = foo.rposition().is_some(); + // check that we don't lint if `find()` is called with + // `Pattern` that is not a string + let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); +} + diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs new file mode 100644 index 0000000000000..5bffb7e849fed --- /dev/null +++ b/tests/ui/search_is_some_fixable.rs @@ -0,0 +1,35 @@ +// run-rustfix + +#![warn(clippy::search_is_some)] + +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_some()`, single-line case. + let _ = v.iter().find(|&x| *x < 0).is_some(); + let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + let _ = (0..1).find(|x| *x == 0).is_some(); + let _ = v.iter().find(|x| **x == 0).is_some(); + + // Check `position().is_some()`, single-line case. + let _ = v.iter().position(|&x| x < 0).is_some(); + + // Check `rposition().is_some()`, single-line case. + let _ = v.iter().rposition(|&x| x < 0).is_some(); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + // caller of `find()` is a `&`static str` + let _ = "hello world".find("world").is_some(); + let _ = "hello world".find(&s2).is_some(); + let _ = "hello world".find(&s2[2..]).is_some(); + // caller of `find()` is a `String` + let _ = s1.find("world").is_some(); + let _ = s1.find(&s2).is_some(); + let _ = s1.find(&s2[2..]).is_some(); + // caller of `find()` is slice of `String` + let _ = s1[2..].find("world").is_some(); + let _ = s1[2..].find(&s2).is_some(); + let _ = s1[2..].find(&s2[2..]).is_some(); +} From 55dc822062eb760afff0d242dea193aabc2c9771 Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Sat, 17 Oct 2020 14:28:00 -0700 Subject: [PATCH 042/118] Ran `tests/ui/update-all-references.sh" and `cargo dev fmt` --- tests/ui/methods.stderr | 68 ------------------- tests/ui/search_is_some.rs | 3 +- tests/ui/search_is_some.stderr | 42 ++++++++++++ tests/ui/search_is_some_fixable.fixed | 35 ++++++++++ tests/ui/search_is_some_fixable.rs | 6 +- tests/ui/search_is_some_fixable.stderr | 94 ++++++++++++++++++++++++++ 6 files changed, 175 insertions(+), 73 deletions(-) create mode 100644 tests/ui/search_is_some.stderr create mode 100644 tests/ui/search_is_some_fixable.fixed create mode 100644 tests/ui/search_is_some_fixable.stderr diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index b2b551bd5f868..bf4675966df08 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -20,71 +20,3 @@ LL | | ).next(); | = note: `-D clippy::filter-next` implied by `-D warnings` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:143:22 - | -LL | let _ = v.iter().find(|&x| *x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` - | - = note: `-D clippy::search-is-some` implied by `-D warnings` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:144:20 - | -LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:145:20 - | -LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:146:22 - | -LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` - -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:149:13 - | -LL | let _ = v.iter().find(|&x| { - | _____________^ -LL | | *x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:155:22 - | -LL | let _ = v.iter().position(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` - -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:158:13 - | -LL | let _ = v.iter().position(|&x| { - | _____________^ -LL | | x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:164:22 - | -LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` - -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. - --> $DIR/methods.rs:167:13 - | -LL | let _ = v.iter().rposition(|&x| { - | _____________^ -LL | | x < 0 -LL | | } -LL | | ).is_some(); - | |______________________________^ - diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index 1ce372ab1d374..1399138a0d27b 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -1,4 +1,4 @@ -#[macro_use] +// aux-build:option_helpers.rs extern crate option_helpers; use option_helpers::IteratorFalsePositives; @@ -36,4 +36,3 @@ fn main() { // `Pattern` that is not a string let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); } - diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr new file mode 100644 index 0000000000000..a124ab1dfd44e --- /dev/null +++ b/tests/ui/search_is_some.stderr @@ -0,0 +1,42 @@ +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some.rs:13:13 + | +LL | let _ = v.iter().find(|&x| { + | _____________^ +LL | | *x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + | + = note: `-D clippy::search-is-some` implied by `-D warnings` + +error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some.rs:19:13 + | +LL | let _ = v.iter().position(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + +error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some.rs:25:13 + | +LL | let _ = v.iter().rposition(|&x| { + | _____________^ +LL | | x < 0 +LL | | } +LL | | ).is_some(); + | |______________________________^ + +error: use of a blacklisted/placeholder name `foo` + --> $DIR/search_is_some.rs:31:9 + | +LL | let foo = IteratorFalsePositives { foo: 0 }; + | ^^^ + | + = note: `-D clippy::blacklisted-name` implied by `-D warnings` + +error: aborting due to 4 previous errors + diff --git a/tests/ui/search_is_some_fixable.fixed b/tests/ui/search_is_some_fixable.fixed new file mode 100644 index 0000000000000..dc3f290e56246 --- /dev/null +++ b/tests/ui/search_is_some_fixable.fixed @@ -0,0 +1,35 @@ +// run-rustfix + +#![warn(clippy::search_is_some)] + +fn main() { + let v = vec![3, 2, 1, 0, -1, -2, -3]; + let y = &&42; + + // Check `find().is_some()`, single-line case. + let _ = v.iter().any(|x| *x < 0); + let _ = (0..1).any(|x| **y == x); // one dereference less + let _ = (0..1).any(|x| x == 0); + let _ = v.iter().any(|x| *x == 0); + + // Check `position().is_some()`, single-line case. + let _ = v.iter().any(|&x| x < 0); + + // Check `rposition().is_some()`, single-line case. + let _ = v.iter().any(|&x| x < 0); + + let s1 = String::from("hello world"); + let s2 = String::from("world"); + // caller of `find()` is a `&`static str` + let _ = "hello world".contains("world"); + let _ = "hello world".contains(&s2); + let _ = "hello world".contains(&s2[2..]); + // caller of `find()` is a `String` + let _ = s1.contains("world"); + let _ = s1.contains(&s2); + let _ = s1.contains(&s2[2..]); + // caller of `find()` is slice of `String` + let _ = s1[2..].contains("world"); + let _ = s1[2..].contains(&s2); + let _ = s1[2..].contains(&s2[2..]); +} diff --git a/tests/ui/search_is_some_fixable.rs b/tests/ui/search_is_some_fixable.rs index 5bffb7e849fed..146cf5adf1b0f 100644 --- a/tests/ui/search_is_some_fixable.rs +++ b/tests/ui/search_is_some_fixable.rs @@ -5,16 +5,16 @@ fn main() { let v = vec![3, 2, 1, 0, -1, -2, -3]; let y = &&42; - + // Check `find().is_some()`, single-line case. let _ = v.iter().find(|&x| *x < 0).is_some(); let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less let _ = (0..1).find(|x| *x == 0).is_some(); let _ = v.iter().find(|x| **x == 0).is_some(); - + // Check `position().is_some()`, single-line case. let _ = v.iter().position(|&x| x < 0).is_some(); - + // Check `rposition().is_some()`, single-line case. let _ = v.iter().rposition(|&x| x < 0).is_some(); diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr new file mode 100644 index 0000000000000..7a2c063fee82c --- /dev/null +++ b/tests/ui/search_is_some_fixable.stderr @@ -0,0 +1,94 @@ +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some_fixable.rs:10:22 + | +LL | let _ = v.iter().find(|&x| *x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` + | + = note: `-D clippy::search-is-some` implied by `-D warnings` + +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some_fixable.rs:11:20 + | +LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` + +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some_fixable.rs:12:20 + | +LL | let _ = (0..1).find(|x| *x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` + +error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some_fixable.rs:13:22 + | +LL | let _ = v.iter().find(|x| **x == 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` + +error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some_fixable.rs:16:22 + | +LL | let _ = v.iter().position(|&x| x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` + +error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. + --> $DIR/search_is_some_fixable.rs:19:22 + | +LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:24:27 + | +LL | let _ = "hello world".find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:25:27 + | +LL | let _ = "hello world".find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:26:27 + | +LL | let _ = "hello world".find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:28:16 + | +LL | let _ = s1.find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:29:16 + | +LL | let _ = s1.find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:30:16 + | +LL | let _ = s1.find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:32:21 + | +LL | let _ = s1[2..].find("world").is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:33:21 + | +LL | let _ = s1[2..].find(&s2).is_some(); + | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + +error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. + --> $DIR/search_is_some_fixable.rs:34:21 + | +LL | let _ = s1[2..].find(&s2[2..]).is_some(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + +error: aborting due to 15 previous errors + From e9612f3eca5566b601dda60c999be69e50f89cac Mon Sep 17 00:00:00 2001 From: rsulli55 Date: Sun, 25 Oct 2020 18:11:38 -0700 Subject: [PATCH 043/118] Remove `to_string` on msg Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index bd04a95e4a193..4df1b3d197f88 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3111,7 +3111,7 @@ fn lint_search_is_some<'tcx>( then { let msg = "called `is_some()` after calling `find()` \ on a string. This is more succinctly expressed by calling \ - `contains()`.".to_string(); + `contains()`"; let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); span_lint_and_sugg( From fb74b4802eda6da49f0ea9f2bc1ef238306c1329 Mon Sep 17 00:00:00 2001 From: rsulli55 Date: Sun, 25 Oct 2020 18:11:57 -0700 Subject: [PATCH 044/118] Remove borrow Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 4df1b3d197f88..fc66bf0422fef 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3118,7 +3118,7 @@ fn lint_search_is_some<'tcx>( cx, SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), - &msg, + msg, "try this", format!("contains({})", find_arg), applicability, From ee1b959054aaf69968d440915766e834568de8fd Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Sat, 31 Oct 2020 12:40:56 -0700 Subject: [PATCH 045/118] Added period back to lint `search_is_some` and ran `update-all-references.sh` --- clippy_lints/src/methods/mod.rs | 2 +- tests/ui/methods.stderr | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index fc66bf0422fef..19e63fbddf74f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3111,7 +3111,7 @@ fn lint_search_is_some<'tcx>( then { let msg = "called `is_some()` after calling `find()` \ on a string. This is more succinctly expressed by calling \ - `contains()`"; + `contains()`."; let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); span_lint_and_sugg( diff --git a/tests/ui/methods.stderr b/tests/ui/methods.stderr index bf4675966df08..33aba630a5304 100644 --- a/tests/ui/methods.stderr +++ b/tests/ui/methods.stderr @@ -20,3 +20,5 @@ LL | | ).next(); | = note: `-D clippy::filter-next` implied by `-D warnings` +error: aborting due to 2 previous errors + From fd303132a27f0fa9bbbfb3282200f8190353574b Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Sat, 7 Nov 2020 00:21:22 -0700 Subject: [PATCH 046/118] Cleaned up message and suggestion for `lint_search_is_some` --- clippy_lints/src/methods/mod.rs | 14 +++--- tests/ui/search_is_some.stderr | 11 +++-- tests/ui/search_is_some_fixable.stderr | 60 +++++++++++++------------- 3 files changed, 44 insertions(+), 41 deletions(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 19e63fbddf74f..66f5aa0c6a00a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3053,10 +3053,10 @@ fn lint_search_is_some<'tcx>( // lint if caller of search is an Iterator if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { let msg = format!( - "called `is_some()` after searching an `Iterator` with {}. This is more succinctly \ - expressed by calling `any()`.", + "called `is_some()` after searching an `Iterator` with {}", search_method ); + let hint = "this is more succinctly expressed by calling `any()`"; let search_snippet = snippet(cx, search_args[1].span, ".."); if search_snippet.lines().count() <= 1 { // suggest `any(|x| ..)` instead of `any(|&x| ..)` for `find(|&x| ..).is_some()` @@ -3084,7 +3084,7 @@ fn lint_search_is_some<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), &msg, - "try this", + "use `any()` instead", format!( "any({})", any_search_snippet.as_ref().map_or(&*search_snippet, String::as_str) @@ -3092,7 +3092,7 @@ fn lint_search_is_some<'tcx>( Applicability::MachineApplicable, ); } else { - span_lint(cx, SEARCH_IS_SOME, expr.span, &msg); + span_lint_and_help(cx, SEARCH_IS_SOME, expr.span, &msg, None, hint); } } // lint if `find()` is called by `String` or `&str` @@ -3109,9 +3109,7 @@ fn lint_search_is_some<'tcx>( if is_string_or_str_slice(&search_args[0]); if is_string_or_str_slice(&search_args[1]); then { - let msg = "called `is_some()` after calling `find()` \ - on a string. This is more succinctly expressed by calling \ - `contains()`."; + let msg = "called `is_some()` after calling `find()` on a string"; let mut applicability = Applicability::MachineApplicable; let find_arg = snippet_with_applicability(cx, search_args[1].span, "..", &mut applicability); span_lint_and_sugg( @@ -3119,7 +3117,7 @@ fn lint_search_is_some<'tcx>( SEARCH_IS_SOME, method_span.with_hi(expr.span.hi()), msg, - "try this", + "use `contains()` instead", format!("contains({})", find_arg), applicability, ); diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index a124ab1dfd44e..43827a6a98dc2 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -1,4 +1,4 @@ -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some.rs:13:13 | LL | let _ = v.iter().find(|&x| { @@ -9,8 +9,9 @@ LL | | ).is_some(); | |______________________________^ | = note: `-D clippy::search-is-some` implied by `-D warnings` + = help: this is more succinctly expressed by calling `any()` -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with position --> $DIR/search_is_some.rs:19:13 | LL | let _ = v.iter().position(|&x| { @@ -19,8 +20,10 @@ LL | | x < 0 LL | | } LL | | ).is_some(); | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with rposition --> $DIR/search_is_some.rs:25:13 | LL | let _ = v.iter().rposition(|&x| { @@ -29,6 +32,8 @@ LL | | x < 0 LL | | } LL | | ).is_some(); | |______________________________^ + | + = help: this is more succinctly expressed by calling `any()` error: use of a blacklisted/placeholder name `foo` --> $DIR/search_is_some.rs:31:9 diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr index 7a2c063fee82c..f4c5d7a3389fe 100644 --- a/tests/ui/search_is_some_fixable.stderr +++ b/tests/ui/search_is_some_fixable.stderr @@ -1,94 +1,94 @@ -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some_fixable.rs:10:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x < 0)` | = note: `-D clippy::search-is-some` implied by `-D warnings` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some_fixable.rs:11:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| **y == x)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some_fixable.rs:12:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` -error: called `is_some()` after searching an `Iterator` with find. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with find --> $DIR/search_is_some_fixable.rs:13:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|x| *x == 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` -error: called `is_some()` after searching an `Iterator` with position. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with position --> $DIR/search_is_some_fixable.rs:16:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` -error: called `is_some()` after searching an `Iterator` with rposition. This is more succinctly expressed by calling `any()`. +error: called `is_some()` after searching an `Iterator` with rposition --> $DIR/search_is_some_fixable.rs:19:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `any(|&x| x < 0)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:24:27 | LL | let _ = "hello world".find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:25:27 | LL | let _ = "hello world".find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:26:27 | LL | let _ = "hello world".find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:28:16 | LL | let _ = s1.find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:29:16 | LL | let _ = s1.find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:30:16 | LL | let _ = s1.find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:32:21 | LL | let _ = s1[2..].find("world").is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains("world")` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains("world")` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:33:21 | LL | let _ = s1[2..].find(&s2).is_some(); - | ^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2)` + | ^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2)` -error: called `is_some()` after calling `find()` on a string. This is more succinctly expressed by calling `contains()`. +error: called `is_some()` after calling `find()` on a string --> $DIR/search_is_some_fixable.rs:34:21 | LL | let _ = s1[2..].find(&s2[2..]).is_some(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `contains(&s2[2..])` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use `contains()` instead: `contains(&s2[2..])` error: aborting due to 15 previous errors From 56d252c53d1d4f7822b336d086659c26a8f0bb4d Mon Sep 17 00:00:00 2001 From: rsulli55 Date: Tue, 10 Nov 2020 23:17:46 -0700 Subject: [PATCH 047/118] Update clippy_lints/src/methods/mod.rs Co-authored-by: Philipp Krones --- clippy_lints/src/methods/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 66f5aa0c6a00a..5c1c1594f7dc9 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -3053,7 +3053,7 @@ fn lint_search_is_some<'tcx>( // lint if caller of search is an Iterator if match_trait_method(cx, &is_some_args[0], &paths::ITERATOR) { let msg = format!( - "called `is_some()` after searching an `Iterator` with {}", + "called `is_some()` after searching an `Iterator` with `{}`", search_method ); let hint = "this is more succinctly expressed by calling `any()`"; From 5c1c50ee174f20574ddbf67b43ab0e9bb5b2c60d Mon Sep 17 00:00:00 2001 From: Ryan Sullivant Date: Tue, 10 Nov 2020 23:48:01 -0700 Subject: [PATCH 048/118] Change variable named `foo` and rerun `update-all-references` --- tests/ui/search_is_some.rs | 8 ++++---- tests/ui/search_is_some.stderr | 16 ++++------------ tests/ui/search_is_some_fixable.stderr | 12 ++++++------ 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/tests/ui/search_is_some.rs b/tests/ui/search_is_some.rs index 1399138a0d27b..f0dc3b3d06bbc 100644 --- a/tests/ui/search_is_some.rs +++ b/tests/ui/search_is_some.rs @@ -28,10 +28,10 @@ fn main() { ).is_some(); // Check that we don't lint if the caller is not an `Iterator` or string - let foo = IteratorFalsePositives { foo: 0 }; - let _ = foo.find().is_some(); - let _ = foo.position().is_some(); - let _ = foo.rposition().is_some(); + let falsepos = IteratorFalsePositives { foo: 0 }; + let _ = falsepos.find().is_some(); + let _ = falsepos.position().is_some(); + let _ = falsepos.rposition().is_some(); // check that we don't lint if `find()` is called with // `Pattern` that is not a string let _ = "hello world".find(|c: char| c == 'o' || c == 'l').is_some(); diff --git a/tests/ui/search_is_some.stderr b/tests/ui/search_is_some.stderr index 43827a6a98dc2..c601f568c609b 100644 --- a/tests/ui/search_is_some.stderr +++ b/tests/ui/search_is_some.stderr @@ -1,4 +1,4 @@ -error: called `is_some()` after searching an `Iterator` with find +error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some.rs:13:13 | LL | let _ = v.iter().find(|&x| { @@ -11,7 +11,7 @@ LL | | ).is_some(); = note: `-D clippy::search-is-some` implied by `-D warnings` = help: this is more succinctly expressed by calling `any()` -error: called `is_some()` after searching an `Iterator` with position +error: called `is_some()` after searching an `Iterator` with `position` --> $DIR/search_is_some.rs:19:13 | LL | let _ = v.iter().position(|&x| { @@ -23,7 +23,7 @@ LL | | ).is_some(); | = help: this is more succinctly expressed by calling `any()` -error: called `is_some()` after searching an `Iterator` with rposition +error: called `is_some()` after searching an `Iterator` with `rposition` --> $DIR/search_is_some.rs:25:13 | LL | let _ = v.iter().rposition(|&x| { @@ -35,13 +35,5 @@ LL | | ).is_some(); | = help: this is more succinctly expressed by calling `any()` -error: use of a blacklisted/placeholder name `foo` - --> $DIR/search_is_some.rs:31:9 - | -LL | let foo = IteratorFalsePositives { foo: 0 }; - | ^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/search_is_some_fixable.stderr b/tests/ui/search_is_some_fixable.stderr index f4c5d7a3389fe..23c1d9a901b97 100644 --- a/tests/ui/search_is_some_fixable.stderr +++ b/tests/ui/search_is_some_fixable.stderr @@ -1,4 +1,4 @@ -error: called `is_some()` after searching an `Iterator` with find +error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable.rs:10:22 | LL | let _ = v.iter().find(|&x| *x < 0).is_some(); @@ -6,31 +6,31 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); | = note: `-D clippy::search-is-some` implied by `-D warnings` -error: called `is_some()` after searching an `Iterator` with find +error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable.rs:11:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| **y == x)` -error: called `is_some()` after searching an `Iterator` with find +error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable.rs:12:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| x == 0)` -error: called `is_some()` after searching an `Iterator` with find +error: called `is_some()` after searching an `Iterator` with `find` --> $DIR/search_is_some_fixable.rs:13:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|x| *x == 0)` -error: called `is_some()` after searching an `Iterator` with position +error: called `is_some()` after searching an `Iterator` with `position` --> $DIR/search_is_some_fixable.rs:16:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|&x| x < 0)` -error: called `is_some()` after searching an `Iterator` with rposition +error: called `is_some()` after searching an `Iterator` with `rposition` --> $DIR/search_is_some_fixable.rs:19:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); From f92f8d095d30e05a3fdf6fdeaab4c8e4d626ef6a Mon Sep 17 00:00:00 2001 From: Ikko Ashimine Date: Wed, 11 Nov 2020 20:23:08 +0900 Subject: [PATCH 049/118] Fix typo in comment occurences -> occurrences --- clippy_lints/src/loops.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 32c2562ee95b4..5a4264f9b5c4e 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -3089,7 +3089,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor { } } -/// Detect the occurences of calls to `iter` or `into_iter` for the +/// Detect the occurrences of calls to `iter` or `into_iter` for the /// given identifier fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, identifier: Ident) -> Option> { let mut visitor = IterFunctionVisitor { From 5f310d9b83b172c0b6ba36e6878a5e5e6254de02 Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Sat, 7 Nov 2020 14:28:55 +0000 Subject: [PATCH 050/118] Implement destructuring assignment for structs and slices Co-authored-by: varkor --- clippy_lints/src/utils/ast_utils.rs | 11 ++++++++++- tests/ui/crashes/ice-6250.stderr | 29 ++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 0e9feef3746e7..7b65e664867ff 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -107,6 +107,15 @@ pub fn eq_expr_opt(l: &Option>, r: &Option>) -> bool { both(l, r, |l, r| eq_expr(l, r)) } +pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool { + match (l, r) { + (StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb), + (StructRest::Rest(_), StructRest::Rest(_)) => true, + (StructRest::None, StructRest::None) => true, + _ => false, + } +} + pub fn eq_expr(l: &Expr, r: &Expr) -> bool { use ExprKind::*; if !over(&l.attrs, &r.attrs, |l, r| eq_attr(l, r)) { @@ -150,7 +159,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (Struct(lp, lfs, lb), Struct(rp, rfs, rb)) => { - eq_path(lp, rp) && eq_expr_opt(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r)) + eq_path(lp, rp) && eq_struct_rest(lb, rb) && unordered_over(lfs, rfs, |l, r| eq_field(l, r)) }, _ => false, } diff --git a/tests/ui/crashes/ice-6250.stderr b/tests/ui/crashes/ice-6250.stderr index 8241dcd8feb7b..c38727316cd4e 100644 --- a/tests/ui/crashes/ice-6250.stderr +++ b/tests/ui/crashes/ice-6250.stderr @@ -1,3 +1,14 @@ +error[E0658]: destructuring assignments are unstable + --> $DIR/ice-6250.rs:12:25 + | +LL | Some(reference) = cache.data.get(key) { + | --------------- ^ + | | + | cannot assign to this expression + | + = note: see issue #71126 for more information + = help: add `#![feature(destructuring_assignment)]` to the crate attributes to enable + error[E0601]: `main` function not found in crate `ice_6250` --> $DIR/ice-6250.rs:4:1 | @@ -10,18 +21,22 @@ LL | | } LL | | } | |_^ consider adding a `main` function to `$DIR/ice-6250.rs` +error[E0308]: mismatched types + --> $DIR/ice-6250.rs:12:14 + | +LL | Some(reference) = cache.data.get(key) { + | ^^^^^^^^^ + | | + | expected integer, found `&i32` + | help: consider dereferencing the borrow: `*reference` + error[E0308]: mismatched types --> $DIR/ice-6250.rs:12:9 | LL | Some(reference) = cache.data.get(key) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` - | -help: you might have meant to use pattern matching - | -LL | let Some(reference) = cache.data.get(key) { - | ^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0308, E0601. +Some errors have detailed explanations: E0308, E0601, E0658. For more information about an error, try `rustc --explain E0308`. From 5f64867e1d5344da8ff7526308d4b63676242c0d Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Wed, 11 Nov 2020 22:36:53 +0900 Subject: [PATCH 051/118] Fix suggestion in `manual_range_contains` when using float --- clippy_lints/src/ranges.rs | 6 ++++-- tests/ui/range_contains.fixed | 5 +++++ tests/ui/range_contains.rs | 5 +++++ tests/ui/range_contains.stderr | 14 +++++++++++++- 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs index 79e9a56af9a19..4b514bbd42ca7 100644 --- a/clippy_lints/src/ranges.rs +++ b/clippy_lints/src/ranges.rs @@ -222,13 +222,14 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' let name = snippet_with_applicability(cx, name_span, "_", &mut applicability); let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability); let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability); + let space = if lo.ends_with('.') { " " } else { "" }; span_lint_and_sugg( cx, MANUAL_RANGE_CONTAINS, span, &format!("manual `{}::contains` implementation", range_type), "use", - format!("({}{}{}).contains(&{})", lo, range_op, hi, name), + format!("({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), applicability, ); } else if !combine_and && ord == Some(lord) { @@ -251,13 +252,14 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<' let name = snippet_with_applicability(cx, name_span, "_", &mut applicability); let lo = snippet_with_applicability(cx, l_span, "_", &mut applicability); let hi = snippet_with_applicability(cx, u_span, "_", &mut applicability); + let space = if lo.ends_with('.') { " " } else { "" }; span_lint_and_sugg( cx, MANUAL_RANGE_CONTAINS, span, &format!("manual `!{}::contains` implementation", range_type), "use", - format!("!({}{}{}).contains(&{})", lo, range_op, hi, name), + format!("!({}{}{}{}).contains(&{})", lo, space, range_op, hi, name), applicability, ); } diff --git a/tests/ui/range_contains.fixed b/tests/ui/range_contains.fixed index 632a6592a28b8..048874a7f8294 100644 --- a/tests/ui/range_contains.fixed +++ b/tests/ui/range_contains.fixed @@ -38,4 +38,9 @@ fn main() { x >= 8 || x >= 12; x < 12 || 12 < x; x >= 8 || x <= 12; + + // Fix #6315 + let y = 3.; + (0. ..1.).contains(&y); + !(0. ..=1.).contains(&y); } diff --git a/tests/ui/range_contains.rs b/tests/ui/range_contains.rs index 6af0d034ef617..60ad259f404d8 100644 --- a/tests/ui/range_contains.rs +++ b/tests/ui/range_contains.rs @@ -38,4 +38,9 @@ fn main() { x >= 8 || x >= 12; x < 12 || 12 < x; x >= 8 || x <= 12; + + // Fix #6315 + let y = 3.; + y >= 0. && y < 1.; + y < 0. || y > 1.; } diff --git a/tests/ui/range_contains.stderr b/tests/ui/range_contains.stderr index 69b009eafc30a..bc79f1bca8463 100644 --- a/tests/ui/range_contains.stderr +++ b/tests/ui/range_contains.stderr @@ -72,5 +72,17 @@ error: manual `!RangeInclusive::contains` implementation LL | 999 < x || 1 > x; | ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)` -error: aborting due to 12 previous errors +error: manual `Range::contains` implementation + --> $DIR/range_contains.rs:44:5 + | +LL | y >= 0. && y < 1.; + | ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)` + +error: manual `!RangeInclusive::contains` implementation + --> $DIR/range_contains.rs:45:5 + | +LL | y < 0. || y > 1.; + | ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)` + +error: aborting due to 14 previous errors From d56969656eb0c933e9a7b442ebdc48b565f11f04 Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Wed, 11 Nov 2020 10:36:54 -0800 Subject: [PATCH 052/118] Add Metadata in std::os::fortanix_sgx::io::FromRawFd --- library/std/src/sys/sgx/ext/io.rs | 37 +++++++++++++++++++++++++------ library/std/src/sys/sgx/net.rs | 6 ++--- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/library/std/src/sys/sgx/ext/io.rs b/library/std/src/sys/sgx/ext/io.rs index f79874a4aec97..ffa926417e306 100644 --- a/library/std/src/sys/sgx/ext/io.rs +++ b/library/std/src/sys/sgx/ext/io.rs @@ -25,8 +25,11 @@ pub trait AsRawFd { /// descriptor. #[unstable(feature = "sgx_platform", issue = "56975")] pub trait FromRawFd { + /// An associated type that contains relevant metadata for `Self`. + type Metadata: Default; + /// Constructs a new instance of `Self` from the given raw file - /// descriptor. + /// descriptor and metadata. /// /// This function **consumes ownership** of the specified file /// descriptor. The returned object will take responsibility for closing @@ -38,7 +41,7 @@ pub trait FromRawFd { /// accidentally allow violating this contract which can cause memory /// unsafety in code that relies on it being true. #[unstable(feature = "sgx_platform", issue = "56975")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self; } /// A trait to express the ability to consume an object and acquire ownership of @@ -71,18 +74,38 @@ impl AsRawFd for net::TcpListener { } } +/// Metadata for `TcpStream`. +#[derive(Debug, Clone, Default)] +pub struct TcpStreamMetadata { + /// Local address of the TCP stream + pub local_addr: Option, + /// Peer address of the TCP stream + pub peer_addr: Option, +} + impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { + type Metadata = TcpStreamMetadata; + + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpStream { let fd = sys::fd::FileDesc::from_inner(fd); - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, None))) + let socket = sys::net::Socket::from_inner((fd, metadata.local_addr)); + net::TcpStream::from_inner(sys::net::TcpStream::from_inner((socket, metadata.peer_addr))) } } +/// Metadata for `TcpListener`. +#[derive(Debug, Clone, Default)] +pub struct TcpListenerMetadata { + /// Local address of the TCP listener + pub local_addr: Option, +} + impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { + type Metadata = TcpListenerMetadata; + + unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> net::TcpListener { let fd = sys::fd::FileDesc::from_inner(fd); - let socket = sys::net::Socket::from_inner(fd); + let socket = sys::net::Socket::from_inner((fd, metadata.local_addr)); net::TcpListener::from_inner(sys::net::TcpListener::from_inner(socket)) } } diff --git a/library/std/src/sys/sgx/net.rs b/library/std/src/sys/sgx/net.rs index 666a157b09cd0..3dd8267921e5e 100644 --- a/library/std/src/sys/sgx/net.rs +++ b/library/std/src/sys/sgx/net.rs @@ -37,9 +37,9 @@ impl TryIntoInner for Socket { } } -impl FromInner for Socket { - fn from_inner(inner: FileDesc) -> Socket { - Socket { inner: Arc::new(inner), local_addr: None } +impl FromInner<(FileDesc, Option)> for Socket { + fn from_inner((inner, local_addr): (FileDesc, Option)) -> Socket { + Socket { inner: Arc::new(inner), local_addr } } } From 084b0da933c2430e2ef80ae0e00ddf76e2bc5f10 Mon Sep 17 00:00:00 2001 From: Mohsen Zohrevandi Date: Thu, 12 Nov 2020 09:11:05 -0800 Subject: [PATCH 053/118] Add missing stability attribute --- library/std/src/sys/sgx/ext/io.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/sys/sgx/ext/io.rs b/library/std/src/sys/sgx/ext/io.rs index ffa926417e306..795a4d190cf4e 100644 --- a/library/std/src/sys/sgx/ext/io.rs +++ b/library/std/src/sys/sgx/ext/io.rs @@ -76,6 +76,7 @@ impl AsRawFd for net::TcpListener { /// Metadata for `TcpStream`. #[derive(Debug, Clone, Default)] +#[unstable(feature = "sgx_platform", issue = "56975")] pub struct TcpStreamMetadata { /// Local address of the TCP stream pub local_addr: Option, @@ -95,6 +96,7 @@ impl FromRawFd for net::TcpStream { /// Metadata for `TcpListener`. #[derive(Debug, Clone, Default)] +#[unstable(feature = "sgx_platform", issue = "56975")] pub struct TcpListenerMetadata { /// Local address of the TCP listener pub local_addr: Option, From c6b74df6807792aae1b18031017a3d154c770173 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Fri, 13 Nov 2020 14:47:23 +0900 Subject: [PATCH 054/118] Fix dogfood test --- clippy_lints/src/utils/ast_utils.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 9050b9b2d9ab8..fcf7a4b1367e3 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -110,8 +110,7 @@ pub fn eq_expr_opt(l: &Option>, r: &Option>) -> bool { pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool { match (l, r) { (StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb), - (StructRest::Rest(_), StructRest::Rest(_)) => true, - (StructRest::None, StructRest::None) => true, + (StructRest::Rest(_), StructRest::Rest(_)) | (StructRest::None, StructRest::None) => true, _ => false, } } From 7987f39ad544ba2c788fed5ea4d9cda19cde63c2 Mon Sep 17 00:00:00 2001 From: Vishnunarayan K I Date: Fri, 13 Nov 2020 17:11:13 +0530 Subject: [PATCH 055/118] update clippy test ouput --- tests/ui/crashes/ice-6252.stderr | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/tests/ui/crashes/ice-6252.stderr b/tests/ui/crashes/ice-6252.stderr index 440973e24398e..eaa5e6f51cb4a 100644 --- a/tests/ui/crashes/ice-6252.stderr +++ b/tests/ui/crashes/ice-6252.stderr @@ -26,21 +26,7 @@ LL | const VAL: T; LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation -error: any use of this value will cause an error - --> $DIR/ice-6252.rs:5:5 - | -LL | const VAL: T; - | ^^^^^^^^^^^^^ no MIR body is available for DefId(0:5 ~ ice_6252[317d]::TypeVal::VAL) - | - = note: `#[deny(const_err)]` on by default - -error[E0080]: evaluation of constant value failed - --> $DIR/ice-6252.rs:14:9 - | -LL | [1; >::VAL]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0046, E0080, E0412. +Some errors have detailed explanations: E0046, E0412. For more information about an error, try `rustc --explain E0046`. From 864e554b9a994f9448a6acb956d77838b949fe6e Mon Sep 17 00:00:00 2001 From: Fabian Zaiser Date: Wed, 11 Nov 2020 13:15:15 +0000 Subject: [PATCH 056/118] Add underscore expressions for destructuring assignments Co-authored-by: varkor --- clippy_lints/src/utils/sugg.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 625120b880eb5..1fcd41e4dbfed 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -170,6 +170,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::MacCall(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Paren(..) + | ast::ExprKind::Underscore | ast::ExprKind::Path(..) | ast::ExprKind::Repeat(..) | ast::ExprKind::Ret(..) From cbb6b1c338953e01ad8cea0ed86a9ca4153592b8 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Thu, 5 Nov 2020 17:30:39 +0100 Subject: [PATCH 057/118] Introduce `TypeVisitor::BreakTy` --- clippy_lints/src/redundant_clone.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index b4a9804fb25a5..64b12980af66b 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -563,7 +563,7 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { struct ContainsRegion; impl TypeVisitor<'_> for ContainsRegion { - fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<()> { + fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow { ControlFlow::BREAK } } From 1b55cc79cc4c5e1c109ef5797a824ca4f158124c Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sat, 14 Nov 2020 21:46:39 +0100 Subject: [PATCH 058/118] Set the default `BreakTy` to `!` --- clippy_lints/src/redundant_clone.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index 64b12980af66b..602facbe062ac 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -563,6 +563,8 @@ impl<'a, 'tcx> mir::visit::Visitor<'tcx> for PossibleBorrowerVisitor<'a, 'tcx> { struct ContainsRegion; impl TypeVisitor<'_> for ContainsRegion { + type BreakTy = (); + fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow { ControlFlow::BREAK } From 0e803417f997ba35c0045704dd347e64c2a1786c Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Mon, 16 Nov 2020 12:14:10 +0900 Subject: [PATCH 059/118] Add `rustfmt::skip` as a work around because comments are checked and removed by rustfmt for some reason --- tests/ui/cast_ref_to_mut.rs | 4 ++++ tests/ui/cast_ref_to_mut.stderr | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/ui/cast_ref_to_mut.rs b/tests/ui/cast_ref_to_mut.rs index 089e5cfabe4b9..0ede958d17069 100644 --- a/tests/ui/cast_ref_to_mut.rs +++ b/tests/ui/cast_ref_to_mut.rs @@ -2,6 +2,10 @@ #![allow(clippy::no_effect)] extern "C" { + #[rustfmt::skip] + // TODO: This `rustfmt::skip` is a work around of #6336 because + // the following comments are checked by rustfmt for some reason. + // // N.B., mutability can be easily incorrect in FFI calls -- as // in C, the default is mutable pointers. fn ffi(c: *mut u8); diff --git a/tests/ui/cast_ref_to_mut.stderr b/tests/ui/cast_ref_to_mut.stderr index aacd99437d9fc..d36aa0e00eecc 100644 --- a/tests/ui/cast_ref_to_mut.stderr +++ b/tests/ui/cast_ref_to_mut.stderr @@ -1,5 +1,5 @@ error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell` - --> $DIR/cast_ref_to_mut.rs:18:9 + --> $DIR/cast_ref_to_mut.rs:22:9 | LL | (*(a as *const _ as *mut String)).push_str(" world"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | (*(a as *const _ as *mut String)).push_str(" world"); = note: `-D clippy::cast-ref-to-mut` implied by `-D warnings` error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell` - --> $DIR/cast_ref_to_mut.rs:19:9 + --> $DIR/cast_ref_to_mut.rs:23:9 | LL | *(a as *const _ as *mut _) = String::from("Replaced"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell` - --> $DIR/cast_ref_to_mut.rs:20:9 + --> $DIR/cast_ref_to_mut.rs:24:9 | LL | *(a as *const _ as *mut String) += " world"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 3567ea546f9bdfb71ed107cff176df08b2da985f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 24 Oct 2020 02:21:27 +0200 Subject: [PATCH 060/118] clippy: fold by value --- clippy_lints/src/eval_order_dependence.rs | 2 +- clippy_lints/src/methods/mod.rs | 4 ++-- clippy_lints/src/mut_key.rs | 2 +- clippy_lints/src/needless_pass_by_value.rs | 2 +- clippy_lints/src/pass_by_ref_or_value.rs | 2 +- clippy_lints/src/transmute.rs | 2 +- clippy_lints/src/unit_return_expecting_ord.rs | 8 ++++---- clippy_lints/src/use_self.rs | 2 +- clippy_lints/src/utils/mod.rs | 6 +++--- 9 files changed, 15 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/eval_order_dependence.rs b/clippy_lints/src/eval_order_dependence.rs index 4240147f498db..bc2b2904698c7 100644 --- a/clippy_lints/src/eval_order_dependence.rs +++ b/clippy_lints/src/eval_order_dependence.rs @@ -141,7 +141,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> { match typ.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let sig = typ.fn_sig(self.cx.tcx); - if let ty::Never = self.cx.tcx.erase_late_bound_regions(&sig).output().kind() { + if let ty::Never = self.cx.tcx.erase_late_bound_regions(sig).output().kind() { self.report_diverging_sub_expr(e); } }, diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 7186656f4e11a..30f4c0c56d27b 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1615,7 +1615,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let method_def_id = cx.tcx.hir().local_def_id(impl_item.hir_id); let method_sig = cx.tcx.fn_sig(method_def_id); - let method_sig = cx.tcx.erase_late_bound_regions(&method_sig); + let method_sig = cx.tcx.erase_late_bound_regions(method_sig); let first_arg_ty = &method_sig.inputs().iter().next(); @@ -2681,7 +2681,7 @@ fn lint_map_flatten<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, map ty::Closure(_, substs) => substs.as_closure().sig(), _ => map_closure_ty.fn_sig(cx.tcx), }; - let map_closure_return_ty = cx.tcx.erase_late_bound_regions(&map_closure_sig.output()); + let map_closure_return_ty = cx.tcx.erase_late_bound_regions(map_closure_sig.output()); is_type_diagnostic_item(cx, map_closure_return_ty, sym::option_type) }, _ => false, diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 4525b12689fa7..9cceecc785a28 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -92,7 +92,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: check_ty( cx, decl.output.span(), - cx.tcx.erase_late_bound_regions(&fn_sig.output()), + cx.tcx.erase_late_bound_regions(fn_sig.output()), ); } diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs index 1d0e230c6a777..532c0266946b3 100644 --- a/clippy_lints/src/needless_pass_by_value.rs +++ b/clippy_lints/src/needless_pass_by_value.rs @@ -141,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { }; let fn_sig = cx.tcx.fn_sig(fn_def_id); - let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig); + let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig); for (idx, ((input, &ty), arg)) in decl.inputs.iter().zip(fn_sig.inputs()).zip(body.params).enumerate() { // All spans generated from a proc-macro invocation are the same... diff --git a/clippy_lints/src/pass_by_ref_or_value.rs b/clippy_lints/src/pass_by_ref_or_value.rs index 030650c3256c0..f03facc235e28 100644 --- a/clippy_lints/src/pass_by_ref_or_value.rs +++ b/clippy_lints/src/pass_by_ref_or_value.rs @@ -115,7 +115,7 @@ impl<'tcx> PassByRefOrValue { let fn_def_id = cx.tcx.hir().local_def_id(hir_id); let fn_sig = cx.tcx.fn_sig(fn_def_id); - let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig); + let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig); let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id)); diff --git a/clippy_lints/src/transmute.rs b/clippy_lints/src/transmute.rs index 47c650ac27d4c..b0909f7317740 100644 --- a/clippy_lints/src/transmute.rs +++ b/clippy_lints/src/transmute.rs @@ -491,7 +491,7 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { Applicability::Unspecified, ); } else { - if (cx.tcx.erase_regions(&from_ty) != cx.tcx.erase_regions(&to_ty)) + if (cx.tcx.erase_regions(from_ty) != cx.tcx.erase_regions(to_ty)) && !const_context { span_lint_and_then( cx, diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index 0d5a5017331b7..ade5fff5ffc06 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -43,7 +43,7 @@ fn get_trait_predicates_for_trait_id<'tcx>( for (pred, _) in generics.predicates { if_chain! { if let PredicateAtom::Trait(poly_trait_pred, _) = pred.skip_binders(); - let trait_pred = cx.tcx.erase_late_bound_regions(&ty::Binder::bind(poly_trait_pred)); + let trait_pred = cx.tcx.erase_late_bound_regions(ty::Binder::bind(poly_trait_pred)); if let Some(trait_def_id) = trait_id; if trait_def_id == trait_pred.trait_ref.def_id; then { @@ -61,7 +61,7 @@ fn get_projection_pred<'tcx>( ) -> Option> { generics.predicates.iter().find_map(|(proj_pred, _)| { if let ty::PredicateAtom::Projection(proj_pred) = proj_pred.skip_binders() { - let projection_pred = cx.tcx.erase_late_bound_regions(&ty::Binder::bind(proj_pred)); + let projection_pred = cx.tcx.erase_late_bound_regions(ty::Binder::bind(proj_pred)); if projection_pred.projection_ty.substs == pred.trait_ref.substs { return Some(projection_pred); } @@ -81,7 +81,7 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait()); // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for `&[&rustc::ty::TyS<'_>]` - let inputs_output = cx.tcx.erase_late_bound_regions(&fn_sig.inputs_and_output()); + let inputs_output = cx.tcx.erase_late_bound_regions(fn_sig.inputs_and_output()); inputs_output .iter() .rev() @@ -112,7 +112,7 @@ fn check_arg<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'tcx>) -> Option<(Spa if let ExprKind::Closure(_, _fn_decl, body_id, span, _) = arg.kind; if let ty::Closure(_def_id, substs) = &cx.typeck_results().node_type(arg.hir_id).kind(); let ret_ty = substs.as_closure().sig().output(); - let ty = cx.tcx.erase_late_bound_regions(&ret_ty); + let ty = cx.tcx.erase_late_bound_regions(ret_ty); if ty.is_unit(); then { if_chain! { diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs index 427a1b6577315..5ac4797680bc1 100644 --- a/clippy_lints/src/use_self.rs +++ b/clippy_lints/src/use_self.rs @@ -123,7 +123,7 @@ fn check_trait_method_impl_decl<'tcx>( .expect("impl method matches a trait method"); let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id); - let trait_method_sig = cx.tcx.erase_late_bound_regions(&trait_method_sig); + let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig); let output_hir_ty = if let FnRetTy::Return(ty) = &impl_decl.output { Some(&**ty) diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 0d43fd0392eb2..b027bfebacb6a 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -363,7 +363,7 @@ pub fn implements_trait<'tcx>( if ty.has_infer_types() { return false; } - let ty = cx.tcx.erase_regions(&ty); + let ty = cx.tcx.erase_regions(ty); let ty_params = cx.tcx.mk_substs(ty_params.iter()); cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } @@ -887,7 +887,7 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option { pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> { let fn_def_id = cx.tcx.hir().local_def_id(fn_item); let ret_ty = cx.tcx.fn_sig(fn_def_id).output(); - cx.tcx.erase_late_bound_regions(&ret_ty) + cx.tcx.erase_late_bound_regions(ret_ty) } /// Walks into `ty` and returns `true` if any inner type is the same as `other_ty` @@ -1220,7 +1220,7 @@ pub fn match_function_call<'tcx>( pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { cx.tcx.infer_ctxt().enter(|infcx| { let cause = rustc_middle::traits::ObligationCause::dummy(); - infcx.at(&cause, param_env).normalize(&ty).is_ok() + infcx.at(&cause, param_env).normalize(ty).is_ok() }) } From 5b8f2b6c93ea819cd6d6e02ad7e2b8b9da23fd67 Mon Sep 17 00:00:00 2001 From: ThibsG Date: Mon, 16 Nov 2020 18:32:01 +0100 Subject: [PATCH 061/118] Remove `expect()` calls to avoid ICEs in `deref_addrof` lint --- clippy_lints/src/reference.rs | 48 ++++++++++++++++++++--------------- tests/ui/crashes/ice-6332.rs | 11 ++++++++ 2 files changed, 39 insertions(+), 20 deletions(-) create mode 100644 tests/ui/crashes/ice-6332.rs diff --git a/clippy_lints/src/reference.rs b/clippy_lints/src/reference.rs index 35a1310d68b84..efe3237990d43 100644 --- a/clippy_lints/src/reference.rs +++ b/clippy_lints/src/reference.rs @@ -60,30 +60,38 @@ impl EarlyLintPass for DerefAddrOf { }).map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) }; - let rpos = if *mutability == Mutability::Mut { - macro_source.rfind("mut").expect("already checked this is a mutable reference") + "mut".len() - } else { - macro_source.rfind('&').expect("already checked this is a reference") + "&".len() + let mut generate_snippet = |pattern: &str| { + #[allow(clippy::cast_possible_truncation)] + macro_source.rfind(pattern).map(|pattern_pos| { + let rpos = pattern_pos + pattern.len(); + let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); + let span = trim_leading_whitespaces(span_after_ref); + snippet_with_applicability(cx, span, "_", &mut applicability) + }) }; - #[allow(clippy::cast_possible_truncation)] - let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); - let span = trim_leading_whitespaces(span_after_ref); - snippet_with_applicability(cx, span, "_", &mut applicability) + + if *mutability == Mutability::Mut { + generate_snippet("mut") + } else { + generate_snippet("&") + } } else { - snippet_with_applicability(cx, e.span, "_", &mut applicability) + Some(snippet_with_applicability(cx, e.span, "_", &mut applicability)) } } else { - snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability) - }.to_string(); - span_lint_and_sugg( - cx, - DEREF_ADDROF, - e.span, - "immediately dereferencing a reference", - "try this", - sugg, - applicability, - ); + Some(snippet_with_applicability(cx, addrof_target.span, "_", &mut applicability)) + }; + if let Some(sugg) = sugg { + span_lint_and_sugg( + cx, + DEREF_ADDROF, + e.span, + "immediately dereferencing a reference", + "try this", + sugg.to_string(), + applicability, + ); + } } } } diff --git a/tests/ui/crashes/ice-6332.rs b/tests/ui/crashes/ice-6332.rs new file mode 100644 index 0000000000000..9dc92aa500b2f --- /dev/null +++ b/tests/ui/crashes/ice-6332.rs @@ -0,0 +1,11 @@ +fn cmark_check() { + let mut link_err = false; + macro_rules! cmark_error { + ($bad:expr) => { + *$bad = true; + }; + } + cmark_error!(&mut link_err); +} + +pub fn main() {} From a7ac441760ae034ff7401439b38da821f4e2df3a Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 20 Sep 2020 02:03:14 +0900 Subject: [PATCH 062/118] Add new lint to detect unnecessarily wrapped value --- CHANGELOG.md | 1 + clippy_lints/src/lib.rs | 5 + clippy_lints/src/unnecessary_wrap.rs | 177 +++++++++++++++++++++++++++ src/lintlist/mod.rs | 7 ++ tests/ui/unnecessary_wrap.fixed | 47 +++++++ tests/ui/unnecessary_wrap.rs | 47 +++++++ tests/ui/unnecessary_wrap.stderr | 34 +++++ 7 files changed, 318 insertions(+) create mode 100644 clippy_lints/src/unnecessary_wrap.rs create mode 100644 tests/ui/unnecessary_wrap.fixed create mode 100644 tests/ui/unnecessary_wrap.rs create mode 100644 tests/ui/unnecessary_wrap.stderr diff --git a/CHANGELOG.md b/CHANGELOG.md index 816d25bcd93eb..02b862d319659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2008,6 +2008,7 @@ Released 2018-09-13 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap +[`unnecessary_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wrap [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern [`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 20b38cbb6d0d5..2d1f75391bb56 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -323,6 +323,7 @@ mod unicode; mod unit_return_expecting_ord; mod unnamed_address; mod unnecessary_sort_by; +mod unnecessary_wrap; mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_io_amount; @@ -892,6 +893,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, &unnecessary_sort_by::UNNECESSARY_SORT_BY, + &unnecessary_wrap::UNNECESSARY_WRAP, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, @@ -1064,6 +1066,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box redundant_clone::RedundantClone); store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy); + store.register_late_pass(|| box unnecessary_wrap::UnnecessaryWrap); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); @@ -1571,6 +1574,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(&unnecessary_wrap::UNNECESSARY_WRAP), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), @@ -1775,6 +1779,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), + LintId::of(&unnecessary_wrap::UNNECESSARY_WRAP), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs new file mode 100644 index 0000000000000..26a5751725841 --- /dev/null +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -0,0 +1,177 @@ +use crate::utils::{ + is_type_diagnostic_item, match_qpath, multispan_sugg_with_applicability, paths, return_ty, snippet, + span_lint_and_then, +}; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::intravisit::{FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::*; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for private functions that only return `Ok` or `Some`. + /// + /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned. + /// + /// **Known problems:** Since this lint changes function type signature, you may need to + /// adjust some codes at callee side. + /// + /// **Example:** + /// + /// ```rust + /// pub fn get_cool_number(a: bool, b: bool) -> Option { + /// if a && b { + /// return Some(50); + /// } + /// if a { + /// Some(0) + /// } else { + /// Some(10) + /// } + /// } + /// ``` + /// Use instead: + /// ```rust + /// pub fn get_cool_number(a: bool, b: bool) -> i32 { + /// if a && b { + /// return 50; + /// } + /// if a { + /// 0 + /// } else { + /// 10 + /// } + /// } + /// ``` + pub UNNECESSARY_WRAP, + complexity, + "functions that only return `Ok` or `Some`" +} + +declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]); + +impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &FnDecl<'tcx>, + body: &Body<'tcx>, + span: Span, + hir_id: HirId, + ) { + if_chain! { + if let FnKind::ItemFn(.., visibility, _) = fn_kind; + if visibility.node.is_pub(); + then { + return; + } + } + + if let ExprKind::Block(ref block, ..) = body.value.kind { + let path = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { + &paths::OPTION_SOME + } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { + &paths::RESULT_OK + } else { + return; + }; + + let mut visitor = UnnecessaryWrapVisitor { result: Vec::new() }; + visitor.visit_block(block); + let result = visitor.result; + + if result.iter().any(|expr| { + if_chain! { + if let ExprKind::Call(ref func, ref args) = expr.kind; + if let ExprKind::Path(ref qpath) = func.kind; + if match_qpath(qpath, path); + if args.len() == 1; + then { + false + } else { + true + } + } + }) { + return; + } + + let suggs = result.iter().filter_map(|expr| { + let snippet = if let ExprKind::Call(_, ref args) = expr.kind { + Some(snippet(cx, args[0].span, "..").to_string()) + } else { + None + }; + snippet.map(|snip| (expr.span, snip)) + }); + + span_lint_and_then( + cx, + UNNECESSARY_WRAP, + span, + "this function returns unnecessarily wrapping data", + move |diag| { + multispan_sugg_with_applicability( + diag, + "factor this out to", + Applicability::MachineApplicable, + suggs, + ); + }, + ); + } + } +} + +struct UnnecessaryWrapVisitor<'tcx> { + result: Vec<&'tcx Expr<'tcx>>, +} + +impl<'tcx> Visitor<'tcx> for UnnecessaryWrapVisitor<'tcx> { + type Map = Map<'tcx>; + + fn visit_block(&mut self, block: &'tcx Block<'tcx>) { + for stmt in block.stmts { + self.visit_stmt(stmt); + } + if let Some(expr) = block.expr { + self.visit_expr(expr) + } + } + + fn visit_stmt(&mut self, stmt: &'tcx Stmt<'tcx>) { + match stmt.kind { + StmtKind::Semi(ref expr) => { + if let ExprKind::Ret(Some(value)) = expr.kind { + self.result.push(value); + } + }, + StmtKind::Expr(ref expr) => self.visit_expr(expr), + _ => (), + } + } + + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + match expr.kind { + ExprKind::Ret(Some(value)) => self.result.push(value), + ExprKind::Call(..) | ExprKind::Path(..) => self.result.push(expr), + ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => { + self.visit_block(block); + }, + ExprKind::Match(_, arms, _) => { + for arm in arms { + self.visit_expr(arm.body); + } + }, + _ => intravisit::walk_expr(self, expr), + } + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } +} diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 69acd3d9b8bc5..4a0cdc5d82f9b 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2608,6 +2608,13 @@ vec![ deprecation: None, module: "unwrap", }, + Lint { + name: "unnecessary_wrap", + group: "complexity", + desc: "functions that only return `Ok` or `Some`", + deprecation: None, + module: "unnecessary_wrap", + }, Lint { name: "unneeded_field_pattern", group: "restriction", diff --git a/tests/ui/unnecessary_wrap.fixed b/tests/ui/unnecessary_wrap.fixed new file mode 100644 index 0000000000000..1657a3173dbfd --- /dev/null +++ b/tests/ui/unnecessary_wrap.fixed @@ -0,0 +1,47 @@ +// run-rustfix +#![warn(clippy::unnecessary_wrap)] +#![allow(clippy::no_effect)] +#![allow(clippy::needless_return)] +#![allow(clippy::if_same_then_else)] + +// should be linted +fn func1(a: bool, b: bool) -> Option { + if a && b { + return Some(42); + } + if a { + Some(-1); + Some(2) + } else { + return Some(1337); + } +} + +// public fns should not be linted +pub fn func2(a: bool) -> Option { + if a { + Some(1) + } else { + Some(1) + } +} + +// should not be linted +fn func3(a: bool) -> Option { + if a { + Some(1) + } else { + None + } +} + +// should be linted +fn func4() -> Option { + 1 +} + +fn main() { + // method calls are not linted + func1(true, true); + func2(true); +} diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs new file mode 100644 index 0000000000000..edf41dad79056 --- /dev/null +++ b/tests/ui/unnecessary_wrap.rs @@ -0,0 +1,47 @@ +// run-rustfix +#![warn(clippy::unnecessary_wrap)] +#![allow(clippy::no_effect)] +#![allow(clippy::needless_return)] +#![allow(clippy::if_same_then_else)] + +// should be linted +fn func1(a: bool, b: bool) -> Option { + if a && b { + return Some(42); + } + if a { + Some(-1); + Some(2) + } else { + return Some(1337); + } +} + +// public fns should not be linted +pub fn func2(a: bool) -> Option { + if a { + Some(1) + } else { + Some(1) + } +} + +// should not be linted +fn func3(a: bool) -> Option { + if a { + Some(1) + } else { + None + } +} + +// should be linted +fn func4() -> Option { + Some(1) +} + +fn main() { + // method calls are not linted + func1(true, true); + func2(true); +} diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr new file mode 100644 index 0000000000000..8473bd818396f --- /dev/null +++ b/tests/ui/unnecessary_wrap.stderr @@ -0,0 +1,34 @@ +error: this function unnecessarily wrapping data + --> $DIR/unnecessary_wrap.rs:8:1 + | +LL | / fn func1(a: bool, b: bool) -> Option { +LL | | if a && b { +LL | | return Some(42); +LL | | } +... | +LL | | } +LL | | } + | |_^ + | + = note: `-D clippy::unnecessary-wrap` implied by `-D warnings` +help: factor this out to + | +LL | return 42; +LL | } +LL | if a { +LL | Some(-1); +LL | 2 +LL | } else { + ... + +error: this function unnecessarily wrapping data + --> $DIR/unnecessary_wrap.rs:39:1 + | +LL | / fn func4() -> Option { +LL | | Some(1) + | | ------- help: factor this out to: `1` +LL | | } + | |_^ + +error: aborting due to 2 previous errors + From 750c118b347af938383c5bff53040480e0974071 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 20 Sep 2020 18:22:01 +0900 Subject: [PATCH 063/118] Add suggestion on type signatures --- clippy_lints/src/unnecessary_wrap.rs | 31 +++++++++++++++++------- tests/ui/unnecessary_wrap.fixed | 18 +++++++++++++- tests/ui/unnecessary_wrap.rs | 16 +++++++++++++ tests/ui/unnecessary_wrap.stderr | 35 +++++++++++++++++++++------- 4 files changed, 82 insertions(+), 18 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 26a5751725841..7b586c1df0c2c 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -7,7 +7,7 @@ use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, NestedVisitorMap, Visitor}; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::hir::map::Map; +use rustc_middle::{hir::map::Map, ty::subst::GenericArgKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; @@ -100,14 +100,27 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { return; } - let suggs = result.iter().filter_map(|expr| { - let snippet = if let ExprKind::Call(_, ref args) = expr.kind { - Some(snippet(cx, args[0].span, "..").to_string()) - } else { - None - }; - snippet.map(|snip| (expr.span, snip)) - }); + let suggs = result + .iter() + .filter_map(|expr| { + let snippet = if let ExprKind::Call(_, ref args) = expr.kind { + Some(snippet(cx, args[0].span, "..").to_string()) + } else { + None + }; + snippet.map(|snip| (expr.span, snip)) + }) + .chain({ + let inner_ty = return_ty(cx, hir_id) + .walk() + .skip(1) // skip `std::option::Option` or `std::result::Result` + .take(1) // first outermost inner type is needed + .filter_map(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), + _ => None, + }); + inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty)) + }); span_lint_and_then( cx, diff --git a/tests/ui/unnecessary_wrap.fixed b/tests/ui/unnecessary_wrap.fixed index 1657a3173dbfd..749bb95c41782 100644 --- a/tests/ui/unnecessary_wrap.fixed +++ b/tests/ui/unnecessary_wrap.fixed @@ -1,8 +1,10 @@ // run-rustfix + #![warn(clippy::unnecessary_wrap)] #![allow(clippy::no_effect)] #![allow(clippy::needless_return)] #![allow(clippy::if_same_then_else)] +#![allow(dead_code)] // should be linted fn func1(a: bool, b: bool) -> Option { @@ -37,7 +39,21 @@ fn func3(a: bool) -> Option { // should be linted fn func4() -> Option { - 1 + Some(1) +} + +// should be linted +fn func5() -> Result { + Ok(1) +} + +// should not be linted +fn func6(a: bool) -> Result { + if a { + Ok(1) + } else { + Err(()) + } } fn main() { diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs index edf41dad79056..749bb95c41782 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wrap.rs @@ -1,8 +1,10 @@ // run-rustfix + #![warn(clippy::unnecessary_wrap)] #![allow(clippy::no_effect)] #![allow(clippy::needless_return)] #![allow(clippy::if_same_then_else)] +#![allow(dead_code)] // should be linted fn func1(a: bool, b: bool) -> Option { @@ -40,6 +42,20 @@ fn func4() -> Option { Some(1) } +// should be linted +fn func5() -> Result { + Ok(1) +} + +// should not be linted +fn func6(a: bool) -> Result { + if a { + Ok(1) + } else { + Err(()) + } +} + fn main() { // method calls are not linted func1(true, true); diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr index 8473bd818396f..511d085c82fe5 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wrap.stderr @@ -1,5 +1,5 @@ -error: this function unnecessarily wrapping data - --> $DIR/unnecessary_wrap.rs:8:1 +error: this function returns unnecessarily wrapping data + --> $DIR/unnecessary_wrap.rs:10:1 | LL | / fn func1(a: bool, b: bool) -> Option { LL | | if a && b { @@ -13,22 +13,41 @@ LL | | } = note: `-D clippy::unnecessary-wrap` implied by `-D warnings` help: factor this out to | +LL | fn func1(a: bool, b: bool) -> i32 { +LL | if a && b { LL | return 42; LL | } LL | if a { LL | Some(-1); -LL | 2 -LL | } else { ... -error: this function unnecessarily wrapping data - --> $DIR/unnecessary_wrap.rs:39:1 +error: this function returns unnecessarily wrapping data + --> $DIR/unnecessary_wrap.rs:41:1 | LL | / fn func4() -> Option { LL | | Some(1) - | | ------- help: factor this out to: `1` LL | | } | |_^ + | +help: factor this out to + | +LL | fn func4() -> i32 { +LL | 1 + | + +error: this function returns unnecessarily wrapping data + --> $DIR/unnecessary_wrap.rs:46:1 + | +LL | / fn func5() -> Result { +LL | | Ok(1) +LL | | } + | |_^ + | +help: factor this out to + | +LL | fn func5() -> i32 { +LL | 1 + | -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors From 0335b8d6a747672c0a4ff6cb14b12eced3848325 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Mon, 21 Sep 2020 00:06:25 +0900 Subject: [PATCH 064/118] Fix lint example --- clippy_lints/src/unnecessary_wrap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 7b586c1df0c2c..c5d0d51007964 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -22,7 +22,7 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// pub fn get_cool_number(a: bool, b: bool) -> Option { + /// fn get_cool_number(a: bool, b: bool) -> Option { /// if a && b { /// return Some(50); /// } @@ -35,7 +35,7 @@ declare_clippy_lint! { /// ``` /// Use instead: /// ```rust - /// pub fn get_cool_number(a: bool, b: bool) -> i32 { + /// fn get_cool_number(a: bool, b: bool) -> i32 { /// if a && b { /// return 50; /// } From 0e9d227c043c1b990912508662e2e5158383ea54 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Mon, 21 Sep 2020 00:11:28 +0900 Subject: [PATCH 065/118] Add test cases --- tests/ui/unnecessary_wrap.fixed | 14 ++++++++++++-- tests/ui/unnecessary_wrap.rs | 14 ++++++++++++-- tests/ui/unnecessary_wrap.stderr | 6 +++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/tests/ui/unnecessary_wrap.fixed b/tests/ui/unnecessary_wrap.fixed index 749bb95c41782..e7e3120f82f32 100644 --- a/tests/ui/unnecessary_wrap.fixed +++ b/tests/ui/unnecessary_wrap.fixed @@ -42,13 +42,18 @@ fn func4() -> Option { Some(1) } +// should not be linted +fn func5() -> Option { + None +} + // should be linted -fn func5() -> Result { +fn func6() -> Result { Ok(1) } // should not be linted -fn func6(a: bool) -> Result { +fn func7(a: bool) -> Result { if a { Ok(1) } else { @@ -56,6 +61,11 @@ fn func6(a: bool) -> Result { } } +// should not be linted +fn func8(a: bool) -> Result { + Err(()) +} + fn main() { // method calls are not linted func1(true, true); diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs index 749bb95c41782..e7e3120f82f32 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wrap.rs @@ -42,13 +42,18 @@ fn func4() -> Option { Some(1) } +// should not be linted +fn func5() -> Option { + None +} + // should be linted -fn func5() -> Result { +fn func6() -> Result { Ok(1) } // should not be linted -fn func6(a: bool) -> Result { +fn func7(a: bool) -> Result { if a { Ok(1) } else { @@ -56,6 +61,11 @@ fn func6(a: bool) -> Result { } } +// should not be linted +fn func8(a: bool) -> Result { + Err(()) +} + fn main() { // method calls are not linted func1(true, true); diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr index 511d085c82fe5..76859fac589fb 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wrap.stderr @@ -36,16 +36,16 @@ LL | 1 | error: this function returns unnecessarily wrapping data - --> $DIR/unnecessary_wrap.rs:46:1 + --> $DIR/unnecessary_wrap.rs:51:1 | -LL | / fn func5() -> Result { +LL | / fn func6() -> Result { LL | | Ok(1) LL | | } | |_^ | help: factor this out to | -LL | fn func5() -> i32 { +LL | fn func6() -> i32 { LL | 1 | From ebdd4e2c723c6902851a050ec8bdc7b966dc2c64 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Wed, 23 Sep 2020 02:53:55 +0900 Subject: [PATCH 066/118] Refactor code according to reivews --- clippy_lints/src/unnecessary_wrap.rs | 224 +++++++++++++++++---------- 1 file changed, 141 insertions(+), 83 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index c5d0d51007964..53ade7baec7be 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -4,7 +4,7 @@ use crate::utils::{ }; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::intravisit::{FnKind, Visitor}; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::{hir::map::Map, ty::subst::GenericArgKind}; @@ -71,57 +71,31 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { } } - if let ExprKind::Block(ref block, ..) = body.value.kind { - let path = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { - &paths::OPTION_SOME - } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { - &paths::RESULT_OK - } else { - return; - }; - - let mut visitor = UnnecessaryWrapVisitor { result: Vec::new() }; - visitor.visit_block(block); - let result = visitor.result; - - if result.iter().any(|expr| { - if_chain! { - if let ExprKind::Call(ref func, ref args) = expr.kind; - if let ExprKind::Path(ref qpath) = func.kind; - if match_qpath(qpath, path); - if args.len() == 1; - then { - false - } else { - true - } + let path = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { + &paths::OPTION_SOME + } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { + &paths::RESULT_OK + } else { + return; + }; + + let mut suggs = Vec::new(); + let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| { + if_chain! { + if let ExprKind::Call(ref func, ref args) = ret_expr.kind; + if let ExprKind::Path(ref qpath) = func.kind; + if match_qpath(qpath, path); + if args.len() == 1; + then { + suggs.push((ret_expr.span, snippet(cx, args[0].span.source_callsite(), "..").to_string())); + true + } else { + false } - }) { - return; } + }); - let suggs = result - .iter() - .filter_map(|expr| { - let snippet = if let ExprKind::Call(_, ref args) = expr.kind { - Some(snippet(cx, args[0].span, "..").to_string()) - } else { - None - }; - snippet.map(|snip| (expr.span, snip)) - }) - .chain({ - let inner_ty = return_ty(cx, hir_id) - .walk() - .skip(1) // skip `std::option::Option` or `std::result::Result` - .take(1) // first outermost inner type is needed - .filter_map(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), - _ => None, - }); - inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty)) - }); - + if can_sugg { span_lint_and_then( cx, UNNECESSARY_WRAP, @@ -132,7 +106,17 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { diag, "factor this out to", Applicability::MachineApplicable, - suggs, + suggs.into_iter().chain({ + let inner_ty = return_ty(cx, hir_id) + .walk() + .skip(1) // skip `std::option::Option` or `std::result::Result` + .take(1) // take the first outermost inner type + .filter_map(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), + _ => None, + }); + inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty)) + }), ); }, ); @@ -140,51 +124,125 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { } } -struct UnnecessaryWrapVisitor<'tcx> { - result: Vec<&'tcx Expr<'tcx>>, -} +// code below is copied from `bind_instead_of_map` + +fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir Expr<'hir>, callback: F) -> bool +where + F: FnMut(&'hir Expr<'hir>) -> bool, +{ + struct RetFinder { + in_stmt: bool, + failed: bool, + cb: F, + } + + struct WithStmtGuarg<'a, F> { + val: &'a mut RetFinder, + prev_in_stmt: bool, + } -impl<'tcx> Visitor<'tcx> for UnnecessaryWrapVisitor<'tcx> { - type Map = Map<'tcx>; + impl RetFinder { + fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { + let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); + WithStmtGuarg { + val: self, + prev_in_stmt, + } + } + } - fn visit_block(&mut self, block: &'tcx Block<'tcx>) { - for stmt in block.stmts { - self.visit_stmt(stmt); + impl std::ops::Deref for WithStmtGuarg<'_, F> { + type Target = RetFinder; + + fn deref(&self) -> &Self::Target { + self.val } - if let Some(expr) = block.expr { - self.visit_expr(expr) + } + + impl std::ops::DerefMut for WithStmtGuarg<'_, F> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.val } } - fn visit_stmt(&mut self, stmt: &'tcx Stmt<'tcx>) { - match stmt.kind { - StmtKind::Semi(ref expr) => { - if let ExprKind::Ret(Some(value)) = expr.kind { - self.result.push(value); - } - }, - StmtKind::Expr(ref expr) => self.visit_expr(expr), - _ => (), + impl Drop for WithStmtGuarg<'_, F> { + fn drop(&mut self) { + self.val.in_stmt = self.prev_in_stmt; } } - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - match expr.kind { - ExprKind::Ret(Some(value)) => self.result.push(value), - ExprKind::Call(..) | ExprKind::Path(..) => self.result.push(expr), - ExprKind::Block(ref block, _) | ExprKind::Loop(ref block, ..) => { - self.visit_block(block); - }, - ExprKind::Match(_, arms, _) => { - for arm in arms { - self.visit_expr(arm.body); + impl<'hir, F: FnMut(&'hir Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_stmt(&mut self, stmt: &'hir Stmt<'_>) { + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) + } + + fn visit_expr(&mut self, expr: &'hir Expr<'_>) { + if self.failed { + return; + } + if self.in_stmt { + match expr.kind { + ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), + _ => intravisit::walk_expr(self, expr), + } + } else { + match expr.kind { + ExprKind::Match(cond, arms, _) => { + self.inside_stmt(true).visit_expr(cond); + for arm in arms { + self.visit_expr(arm.body); + } + }, + ExprKind::Block(..) => intravisit::walk_expr(self, expr), + ExprKind::Ret(Some(expr)) => self.visit_expr(expr), + _ => self.failed |= !(self.cb)(expr), } - }, - _ => intravisit::walk_expr(self, expr), + } } } - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None + !contains_try(expr) && { + let mut ret_finder = RetFinder { + in_stmt: false, + failed: false, + cb: callback, + }; + ret_finder.visit_expr(expr); + !ret_finder.failed + } +} + +/// returns `true` if expr contains match expr desugared from try +fn contains_try(expr: &Expr<'_>) -> bool { + struct TryFinder { + found: bool, + } + + impl<'hir> intravisit::Visitor<'hir> for TryFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { + if self.found { + return; + } + match expr.kind { + ExprKind::Match(_, _, MatchSource::TryDesugar) => self.found = true, + _ => intravisit::walk_expr(self, expr), + } + } } + + let mut visitor = TryFinder { found: false }; + visitor.visit_expr(expr); + visitor.found } From 6a62390c86cb9f72465f1c314b64c94c273956b7 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Wed, 23 Sep 2020 02:57:47 +0900 Subject: [PATCH 067/118] Optout rustfix test --- tests/ui/unnecessary_wrap.fixed | 73 -------------------------------- tests/ui/unnecessary_wrap.rs | 2 - tests/ui/unnecessary_wrap.stderr | 6 +-- 3 files changed, 3 insertions(+), 78 deletions(-) delete mode 100644 tests/ui/unnecessary_wrap.fixed diff --git a/tests/ui/unnecessary_wrap.fixed b/tests/ui/unnecessary_wrap.fixed deleted file mode 100644 index e7e3120f82f32..0000000000000 --- a/tests/ui/unnecessary_wrap.fixed +++ /dev/null @@ -1,73 +0,0 @@ -// run-rustfix - -#![warn(clippy::unnecessary_wrap)] -#![allow(clippy::no_effect)] -#![allow(clippy::needless_return)] -#![allow(clippy::if_same_then_else)] -#![allow(dead_code)] - -// should be linted -fn func1(a: bool, b: bool) -> Option { - if a && b { - return Some(42); - } - if a { - Some(-1); - Some(2) - } else { - return Some(1337); - } -} - -// public fns should not be linted -pub fn func2(a: bool) -> Option { - if a { - Some(1) - } else { - Some(1) - } -} - -// should not be linted -fn func3(a: bool) -> Option { - if a { - Some(1) - } else { - None - } -} - -// should be linted -fn func4() -> Option { - Some(1) -} - -// should not be linted -fn func5() -> Option { - None -} - -// should be linted -fn func6() -> Result { - Ok(1) -} - -// should not be linted -fn func7(a: bool) -> Result { - if a { - Ok(1) - } else { - Err(()) - } -} - -// should not be linted -fn func8(a: bool) -> Result { - Err(()) -} - -fn main() { - // method calls are not linted - func1(true, true); - func2(true); -} diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs index e7e3120f82f32..f78a7604a5a35 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wrap.rs @@ -1,5 +1,3 @@ -// run-rustfix - #![warn(clippy::unnecessary_wrap)] #![allow(clippy::no_effect)] #![allow(clippy::needless_return)] diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr index 76859fac589fb..cd05104f4900f 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wrap.stderr @@ -1,5 +1,5 @@ error: this function returns unnecessarily wrapping data - --> $DIR/unnecessary_wrap.rs:10:1 + --> $DIR/unnecessary_wrap.rs:8:1 | LL | / fn func1(a: bool, b: bool) -> Option { LL | | if a && b { @@ -22,7 +22,7 @@ LL | Some(-1); ... error: this function returns unnecessarily wrapping data - --> $DIR/unnecessary_wrap.rs:41:1 + --> $DIR/unnecessary_wrap.rs:39:1 | LL | / fn func4() -> Option { LL | | Some(1) @@ -36,7 +36,7 @@ LL | 1 | error: this function returns unnecessarily wrapping data - --> $DIR/unnecessary_wrap.rs:51:1 + --> $DIR/unnecessary_wrap.rs:49:1 | LL | / fn func6() -> Result { LL | | Ok(1) From 3ed89026231a17beed9e93b055ea1b6192997a68 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Wed, 23 Sep 2020 03:06:52 +0900 Subject: [PATCH 068/118] Fix typo Co-authored-by: Philipp Krones --- clippy_lints/src/unnecessary_wrap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 53ade7baec7be..e5ef7cde7891f 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// **Why is this bad?** It is not meaningful to wrap values when no `None` or `Err` is returned. /// /// **Known problems:** Since this lint changes function type signature, you may need to - /// adjust some codes at callee side. + /// adjust some code at callee side. /// /// **Example:** /// From c77585672720285db5180b2ee4207c7ee9b51072 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Wed, 23 Sep 2020 03:42:58 +0900 Subject: [PATCH 069/118] Call `diag.multipart_suggestion` instead --- clippy_lints/src/unnecessary_wrap.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index e5ef7cde7891f..d581912284f9e 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -1,5 +1,5 @@ use crate::utils::{ - is_type_diagnostic_item, match_qpath, multispan_sugg_with_applicability, paths, return_ty, snippet, + is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, }; use if_chain::if_chain; @@ -102,10 +102,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { span, "this function returns unnecessarily wrapping data", move |diag| { - multispan_sugg_with_applicability( - diag, + diag.multipart_suggestion( "factor this out to", - Applicability::MachineApplicable, suggs.into_iter().chain({ let inner_ty = return_ty(cx, hir_id) .walk() @@ -116,7 +114,8 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { _ => None, }); inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty)) - }), + }).collect(), + Applicability::MachineApplicable, ); }, ); From a433d4690e04c8c8eceb1f59c78fded1f04cf6f0 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Wed, 23 Sep 2020 03:48:15 +0900 Subject: [PATCH 070/118] Run rustfmt --- clippy_lints/src/unnecessary_wrap.rs | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index d581912284f9e..1c8a08172a3dd 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -1,7 +1,4 @@ -use crate::utils::{ - is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, - span_lint_and_then, -}; +use crate::utils::{is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{FnKind, Visitor}; @@ -104,17 +101,20 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { move |diag| { diag.multipart_suggestion( "factor this out to", - suggs.into_iter().chain({ - let inner_ty = return_ty(cx, hir_id) - .walk() - .skip(1) // skip `std::option::Option` or `std::result::Result` - .take(1) // take the first outermost inner type - .filter_map(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), - _ => None, - }); - inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty)) - }).collect(), + suggs + .into_iter() + .chain({ + let inner_ty = return_ty(cx, hir_id) + .walk() + .skip(1) // skip `std::option::Option` or `std::result::Result` + .take(1) // take the first outermost inner type + .filter_map(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), + _ => None, + }); + inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty)) + }) + .collect(), Applicability::MachineApplicable, ); }, From cdb72df6f9f9d6946b0614b01e70bc9c46edfe89 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sat, 26 Sep 2020 15:39:39 +0900 Subject: [PATCH 071/118] Split lint suggestion into two --- clippy_lints/src/unnecessary_wrap.rs | 41 +++++++++++++++------------- tests/ui/unnecessary_wrap.stderr | 18 +++++++++--- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 1c8a08172a3dd..3ddf921a04b94 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -68,10 +68,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { } } - let path = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { - &paths::OPTION_SOME + let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { + ("Option", &paths::OPTION_SOME) } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { - &paths::RESULT_OK + ("Result", &paths::RESULT_OK) } else { return; }; @@ -98,23 +98,26 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { UNNECESSARY_WRAP, span, "this function returns unnecessarily wrapping data", - move |diag| { + |diag| { + let inner_ty = return_ty(cx, hir_id) + .walk() + .skip(1) // skip `std::option::Option` or `std::result::Result` + .take(1) // take the first outermost inner type + .filter_map(|inner| match inner.unpack() { + GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), + _ => None, + }); + inner_ty.for_each(|inner_ty| { + diag.span_suggestion( + fn_decl.output.span(), + format!("remove `{}` from the return type...", return_type).as_str(), + inner_ty, + Applicability::MachineApplicable, + ); + }); diag.multipart_suggestion( - "factor this out to", - suggs - .into_iter() - .chain({ - let inner_ty = return_ty(cx, hir_id) - .walk() - .skip(1) // skip `std::option::Option` or `std::result::Result` - .take(1) // take the first outermost inner type - .filter_map(|inner| match inner.unpack() { - GenericArgKind::Type(inner_ty) => Some(inner_ty.to_string()), - _ => None, - }); - inner_ty.map(|inner_ty| (fn_decl.output.span(), inner_ty)) - }) - .collect(), + "...and change the returning expressions", + suggs, Applicability::MachineApplicable, ); }, diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr index cd05104f4900f..7833ee4b213a0 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wrap.stderr @@ -11,14 +11,18 @@ LL | | } | |_^ | = note: `-D clippy::unnecessary-wrap` implied by `-D warnings` -help: factor this out to +help: remove `Option` from the return type... | LL | fn func1(a: bool, b: bool) -> i32 { -LL | if a && b { + | ^^^ +help: ...and change the returning expressions + | LL | return 42; LL | } LL | if a { LL | Some(-1); +LL | 2 +LL | } else { ... error: this function returns unnecessarily wrapping data @@ -29,9 +33,12 @@ LL | | Some(1) LL | | } | |_^ | -help: factor this out to +help: remove `Option` from the return type... | LL | fn func4() -> i32 { + | ^^^ +help: ...and change the returning expressions + | LL | 1 | @@ -43,9 +50,12 @@ LL | | Ok(1) LL | | } | |_^ | -help: factor this out to +help: remove `Result` from the return type... | LL | fn func6() -> i32 { + | ^^^ +help: ...and change the returning expressions + | LL | 1 | From 6b55f3fec98fa8fd4ca15edbf1cc1ab86d22f08f Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sat, 26 Sep 2020 16:27:10 +0900 Subject: [PATCH 072/118] Add test case --- tests/ui/unnecessary_wrap.rs | 28 +++++++++++++++------- tests/ui/unnecessary_wrap.stderr | 40 ++++++++++++++++++++++++++------ 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs index f78a7604a5a35..6037f5807d3e2 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wrap.rs @@ -17,8 +17,20 @@ fn func1(a: bool, b: bool) -> Option { } } +// should be linted +fn func2(a: bool, b: bool) -> Option { + if a && b { + return Some(10); + } + if a { + Some(20) + } else { + Some(30) + } +} + // public fns should not be linted -pub fn func2(a: bool) -> Option { +pub fn func3(a: bool) -> Option { if a { Some(1) } else { @@ -27,7 +39,7 @@ pub fn func2(a: bool) -> Option { } // should not be linted -fn func3(a: bool) -> Option { +fn func4(a: bool) -> Option { if a { Some(1) } else { @@ -36,22 +48,22 @@ fn func3(a: bool) -> Option { } // should be linted -fn func4() -> Option { +fn func5() -> Option { Some(1) } // should not be linted -fn func5() -> Option { +fn func6() -> Option { None } // should be linted -fn func6() -> Result { +fn func7() -> Result { Ok(1) } // should not be linted -fn func7(a: bool) -> Result { +fn func8(a: bool) -> Result { if a { Ok(1) } else { @@ -60,12 +72,12 @@ fn func7(a: bool) -> Result { } // should not be linted -fn func8(a: bool) -> Result { +fn func9(a: bool) -> Result { Err(()) } fn main() { // method calls are not linted func1(true, true); - func2(true); + func2(true, true); } diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr index 7833ee4b213a0..a3481330e99b5 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wrap.stderr @@ -26,16 +26,42 @@ LL | } else { ... error: this function returns unnecessarily wrapping data - --> $DIR/unnecessary_wrap.rs:39:1 + --> $DIR/unnecessary_wrap.rs:21:1 | -LL | / fn func4() -> Option { +LL | / fn func2(a: bool, b: bool) -> Option { +LL | | if a && b { +LL | | return Some(10); +LL | | } +... | +LL | | } +LL | | } + | |_^ + | +help: remove `Option` from the return type... + | +LL | fn func2(a: bool, b: bool) -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | return 10; +LL | } +LL | if a { +LL | 20 +LL | } else { +LL | 30 + | + +error: this function returns unnecessarily wrapping data + --> $DIR/unnecessary_wrap.rs:51:1 + | +LL | / fn func5() -> Option { LL | | Some(1) LL | | } | |_^ | help: remove `Option` from the return type... | -LL | fn func4() -> i32 { +LL | fn func5() -> i32 { | ^^^ help: ...and change the returning expressions | @@ -43,21 +69,21 @@ LL | 1 | error: this function returns unnecessarily wrapping data - --> $DIR/unnecessary_wrap.rs:49:1 + --> $DIR/unnecessary_wrap.rs:61:1 | -LL | / fn func6() -> Result { +LL | / fn func7() -> Result { LL | | Ok(1) LL | | } | |_^ | help: remove `Result` from the return type... | -LL | fn func6() -> i32 { +LL | fn func7() -> i32 { | ^^^ help: ...and change the returning expressions | LL | 1 | -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors From df0d565e597ad9c436fadfb8e11a16a92bcb4114 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Fri, 2 Oct 2020 18:21:17 +0900 Subject: [PATCH 073/118] Move `find_all_ret_expressions` into `utils` --- .../src/methods/bind_instead_of_map.rs | 125 +---------------- clippy_lints/src/unnecessary_wrap.rs | 132 +----------------- clippy_lints/src/utils/mod.rs | 1 + clippy_lints/src/utils/visitors.rs | 125 +++++++++++++++++ 4 files changed, 133 insertions(+), 250 deletions(-) create mode 100644 clippy_lints/src/utils/visitors.rs diff --git a/clippy_lints/src/methods/bind_instead_of_map.rs b/clippy_lints/src/methods/bind_instead_of_map.rs index ae37942e55a1b..540a1484a8558 100644 --- a/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/clippy_lints/src/methods/bind_instead_of_map.rs @@ -1,14 +1,12 @@ use super::{contains_return, BIND_INSTEAD_OF_MAP}; use crate::utils::{ in_macro, match_qpath, match_type, method_calls, multispan_sugg_with_applicability, paths, remove_blocks, snippet, - snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, + snippet_with_macro_callsite, span_lint_and_sugg, span_lint_and_then, visitors::find_all_ret_expressions, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; -use rustc_hir::intravisit::{self, Visitor}; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; use rustc_span::Span; pub(crate) struct OptionAndThenSome; @@ -193,124 +191,3 @@ pub(crate) trait BindInsteadOfMap { } } } - -/// returns `true` if expr contains match expr desugared from try -fn contains_try(expr: &hir::Expr<'_>) -> bool { - struct TryFinder { - found: bool, - } - - impl<'hir> intravisit::Visitor<'hir> for TryFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - if self.found { - return; - } - match expr.kind { - hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, - _ => intravisit::walk_expr(self, expr), - } - } - } - - let mut visitor = TryFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} - -fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool -where - F: FnMut(&'hir hir::Expr<'hir>) -> bool, -{ - struct RetFinder { - in_stmt: bool, - failed: bool, - cb: F, - } - - struct WithStmtGuarg<'a, F> { - val: &'a mut RetFinder, - prev_in_stmt: bool, - } - - impl RetFinder { - fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { - let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); - WithStmtGuarg { - val: self, - prev_in_stmt, - } - } - } - - impl std::ops::Deref for WithStmtGuarg<'_, F> { - type Target = RetFinder; - - fn deref(&self) -> &Self::Target { - self.val - } - } - - impl std::ops::DerefMut for WithStmtGuarg<'_, F> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.val - } - } - - impl Drop for WithStmtGuarg<'_, F> { - fn drop(&mut self) { - self.val.in_stmt = self.prev_in_stmt; - } - } - - impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) - } - - fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { - if self.failed { - return; - } - if self.in_stmt { - match expr.kind { - hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), - _ => intravisit::walk_expr(self, expr), - } - } else { - match expr.kind { - hir::ExprKind::Match(cond, arms, _) => { - self.inside_stmt(true).visit_expr(cond); - for arm in arms { - self.visit_expr(arm.body); - } - }, - hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), - hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), - _ => self.failed |= !(self.cb)(expr), - } - } - } - } - - !contains_try(expr) && { - let mut ret_finder = RetFinder { - in_stmt: false, - failed: false, - cb: callback, - }; - ret_finder.visit_expr(expr); - !ret_finder.failed - } -} diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 3ddf921a04b94..de13301381e2b 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -1,10 +1,13 @@ -use crate::utils::{is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then}; +use crate::utils::{ + is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + visitors::find_all_ret_expressions, +}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{FnKind, Visitor}; +use rustc_hir::intravisit::FnKind; use rustc_hir::*; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::{hir::map::Map, ty::subst::GenericArgKind}; +use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; @@ -125,126 +128,3 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { } } } - -// code below is copied from `bind_instead_of_map` - -fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir Expr<'hir>, callback: F) -> bool -where - F: FnMut(&'hir Expr<'hir>) -> bool, -{ - struct RetFinder { - in_stmt: bool, - failed: bool, - cb: F, - } - - struct WithStmtGuarg<'a, F> { - val: &'a mut RetFinder, - prev_in_stmt: bool, - } - - impl RetFinder { - fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { - let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); - WithStmtGuarg { - val: self, - prev_in_stmt, - } - } - } - - impl std::ops::Deref for WithStmtGuarg<'_, F> { - type Target = RetFinder; - - fn deref(&self) -> &Self::Target { - self.val - } - } - - impl std::ops::DerefMut for WithStmtGuarg<'_, F> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.val - } - } - - impl Drop for WithStmtGuarg<'_, F> { - fn drop(&mut self) { - self.val.in_stmt = self.prev_in_stmt; - } - } - - impl<'hir, F: FnMut(&'hir Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_stmt(&mut self, stmt: &'hir Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) - } - - fn visit_expr(&mut self, expr: &'hir Expr<'_>) { - if self.failed { - return; - } - if self.in_stmt { - match expr.kind { - ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), - _ => intravisit::walk_expr(self, expr), - } - } else { - match expr.kind { - ExprKind::Match(cond, arms, _) => { - self.inside_stmt(true).visit_expr(cond); - for arm in arms { - self.visit_expr(arm.body); - } - }, - ExprKind::Block(..) => intravisit::walk_expr(self, expr), - ExprKind::Ret(Some(expr)) => self.visit_expr(expr), - _ => self.failed |= !(self.cb)(expr), - } - } - } - } - - !contains_try(expr) && { - let mut ret_finder = RetFinder { - in_stmt: false, - failed: false, - cb: callback, - }; - ret_finder.visit_expr(expr); - !ret_finder.failed - } -} - -/// returns `true` if expr contains match expr desugared from try -fn contains_try(expr: &Expr<'_>) -> bool { - struct TryFinder { - found: bool, - } - - impl<'hir> intravisit::Visitor<'hir> for TryFinder { - type Map = Map<'hir>; - - fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { - intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, expr: &'hir Expr<'hir>) { - if self.found { - return; - } - match expr.kind { - ExprKind::Match(_, _, MatchSource::TryDesugar) => self.found = true, - _ => intravisit::walk_expr(self, expr), - } - } - } - - let mut visitor = TryFinder { found: false }; - visitor.visit_expr(expr); - visitor.found -} diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 253b7823bd9d9..bd62e67f80e38 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -21,6 +21,7 @@ pub mod ptr; pub mod qualify_min_const_fn; pub mod sugg; pub mod usage; +pub mod visitors; pub use self::attrs::*; pub use self::diagnostics::*; diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs new file mode 100644 index 0000000000000..b0837b6c43e76 --- /dev/null +++ b/clippy_lints/src/utils/visitors.rs @@ -0,0 +1,125 @@ +use rustc_hir as hir; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_lint::LateContext; +use rustc_middle::hir::map::Map; + +/// returns `true` if expr contains match expr desugared from try +fn contains_try(expr: &hir::Expr<'_>) -> bool { + struct TryFinder { + found: bool, + } + + impl<'hir> intravisit::Visitor<'hir> for TryFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { + if self.found { + return; + } + match expr.kind { + hir::ExprKind::Match(_, _, hir::MatchSource::TryDesugar) => self.found = true, + _ => intravisit::walk_expr(self, expr), + } + } + } + + let mut visitor = TryFinder { found: false }; + visitor.visit_expr(expr); + visitor.found +} + +pub fn find_all_ret_expressions<'hir, F>(_cx: &LateContext<'_>, expr: &'hir hir::Expr<'hir>, callback: F) -> bool +where + F: FnMut(&'hir hir::Expr<'hir>) -> bool, +{ + struct RetFinder { + in_stmt: bool, + failed: bool, + cb: F, + } + + struct WithStmtGuarg<'a, F> { + val: &'a mut RetFinder, + prev_in_stmt: bool, + } + + impl RetFinder { + fn inside_stmt(&mut self, in_stmt: bool) -> WithStmtGuarg<'_, F> { + let prev_in_stmt = std::mem::replace(&mut self.in_stmt, in_stmt); + WithStmtGuarg { + val: self, + prev_in_stmt, + } + } + } + + impl std::ops::Deref for WithStmtGuarg<'_, F> { + type Target = RetFinder; + + fn deref(&self) -> &Self::Target { + self.val + } + } + + impl std::ops::DerefMut for WithStmtGuarg<'_, F> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.val + } + } + + impl Drop for WithStmtGuarg<'_, F> { + fn drop(&mut self) { + self.val.in_stmt = self.prev_in_stmt; + } + } + + impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder { + type Map = Map<'hir>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) + } + + fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { + if self.failed { + return; + } + if self.in_stmt { + match expr.kind { + hir::ExprKind::Ret(Some(expr)) => self.inside_stmt(false).visit_expr(expr), + _ => intravisit::walk_expr(self, expr), + } + } else { + match expr.kind { + hir::ExprKind::Match(cond, arms, _) => { + self.inside_stmt(true).visit_expr(cond); + for arm in arms { + self.visit_expr(arm.body); + } + }, + hir::ExprKind::Block(..) => intravisit::walk_expr(self, expr), + hir::ExprKind::Ret(Some(expr)) => self.visit_expr(expr), + _ => self.failed |= !(self.cb)(expr), + } + } + } + } + + !contains_try(expr) && { + let mut ret_finder = RetFinder { + in_stmt: false, + failed: false, + cb: callback, + }; + ret_finder.visit_expr(expr); + !ret_finder.failed + } +} From eec7f5c1113d3d49dd7f42462ea25d0b36b4b49b Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Mon, 12 Oct 2020 19:21:04 +0900 Subject: [PATCH 074/118] Update clippy_lints/src/unnecessary_wrap.rs Co-authored-by: Philipp Krones --- clippy_lints/src/unnecessary_wrap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index de13301381e2b..28762b8d26588 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { cx, UNNECESSARY_WRAP, span, - "this function returns unnecessarily wrapping data", + format!("this function's return value is unnecessarily wrapped by `{}`, return_type)", |diag| { let inner_ty = return_ty(cx, hir_id) .walk() From 1bdac8712868e1418dcb13e817254620a8c01158 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Mon, 12 Oct 2020 19:27:47 +0900 Subject: [PATCH 075/118] Improve lint message --- clippy_lints/src/unnecessary_wrap.rs | 2 +- tests/ui/unnecessary_wrap.stderr | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 28762b8d26588..db51ee681ef2d 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { cx, UNNECESSARY_WRAP, span, - format!("this function's return value is unnecessarily wrapped by `{}`, return_type)", + format!("this function's return value is unnecessarily wrapped by `{}`", return_type).as_str(), |diag| { let inner_ty = return_ty(cx, hir_id) .walk() diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr index a3481330e99b5..958bc99802250 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wrap.stderr @@ -1,4 +1,4 @@ -error: this function returns unnecessarily wrapping data +error: this function's return value is unnecessarily wrapped by `Option` --> $DIR/unnecessary_wrap.rs:8:1 | LL | / fn func1(a: bool, b: bool) -> Option { @@ -25,7 +25,7 @@ LL | 2 LL | } else { ... -error: this function returns unnecessarily wrapping data +error: this function's return value is unnecessarily wrapped by `Option` --> $DIR/unnecessary_wrap.rs:21:1 | LL | / fn func2(a: bool, b: bool) -> Option { @@ -51,7 +51,7 @@ LL | } else { LL | 30 | -error: this function returns unnecessarily wrapping data +error: this function's return value is unnecessarily wrapped by `Option` --> $DIR/unnecessary_wrap.rs:51:1 | LL | / fn func5() -> Option { @@ -68,7 +68,7 @@ help: ...and change the returning expressions LL | 1 | -error: this function returns unnecessarily wrapping data +error: this function's return value is unnecessarily wrapped by `Result` --> $DIR/unnecessary_wrap.rs:61:1 | LL | / fn func7() -> Result { From 8392bc7946a212a85bc5a411f5321a1f76d5ccf6 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Mon, 12 Oct 2020 19:37:27 +0900 Subject: [PATCH 076/118] Run `cargo dev fmt` --- clippy_lints/src/unnecessary_wrap.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index db51ee681ef2d..fc1a33fc6cd7f 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -100,7 +100,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { cx, UNNECESSARY_WRAP, span, - format!("this function's return value is unnecessarily wrapped by `{}`", return_type).as_str(), + format!( + "this function's return value is unnecessarily wrapped by `{}`", + return_type + ) + .as_str(), |diag| { let inner_ty = return_ty(cx, hir_id) .walk() From 2f85aa736e85544803ff6d3e6b13e44c0729bbdd Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 16:30:46 +0900 Subject: [PATCH 077/118] Make lint skip closures --- clippy_lints/src/unnecessary_wrap.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index fc1a33fc6cd7f..a20d1f82e9efd 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -63,12 +63,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { span: Span, hir_id: HirId, ) { - if_chain! { - if let FnKind::ItemFn(.., visibility, _) = fn_kind; - if visibility.node.is_pub(); - then { - return; - } + match fn_kind { + FnKind::ItemFn(.., visibility, _) if visibility.node.is_pub() => return, + FnKind::Closure(..) => return, + _ => (), } let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { From 12474c62ff89ab122c2e6881b00680913fdf1d35 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 16:53:18 +0900 Subject: [PATCH 078/118] Add support for methods --- clippy_lints/src/unnecessary_wrap.rs | 6 +++++- tests/ui/unnecessary_wrap.rs | 14 ++++++++++++++ tests/ui/unnecessary_wrap.stderr | 19 ++++++++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index a20d1f82e9efd..365e9c9984e82 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -64,7 +64,11 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { hir_id: HirId, ) { match fn_kind { - FnKind::ItemFn(.., visibility, _) if visibility.node.is_pub() => return, + FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => { + if visibility.node.is_pub() { + return; + } + }, FnKind::Closure(..) => return, _ => (), } diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs index 6037f5807d3e2..0ced20b7a566d 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wrap.rs @@ -76,6 +76,20 @@ fn func9(a: bool) -> Result { Err(()) } +struct A; + +impl A { + // should not be linted + pub fn func10() -> Option { + Some(1) + } + + // should be linted + fn func11() -> Option { + Some(1) + } +} + fn main() { // method calls are not linted func1(true, true); diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr index 958bc99802250..dbc5748c29ec4 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wrap.stderr @@ -85,5 +85,22 @@ help: ...and change the returning expressions LL | 1 | -error: aborting due to 4 previous errors +error: this function's return value is unnecessarily wrapped by `Option` + --> $DIR/unnecessary_wrap.rs:88:5 + | +LL | / fn func11() -> Option { +LL | | Some(1) +LL | | } + | |_____^ + | +help: remove `Option` from the return type... + | +LL | fn func11() -> i32 { + | ^^^ +help: ...and change the returning expressions + | +LL | 1 + | + +error: aborting due to 5 previous errors From c5447eb3c167025fcc1b842fabd7bb43a2eb1e9e Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 17:17:45 +0900 Subject: [PATCH 079/118] Make lint skip macros --- clippy_lints/src/unnecessary_wrap.rs | 3 ++- tests/ui/unnecessary_wrap.rs | 9 +++++++-- tests/ui/unnecessary_wrap.stderr | 6 +++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 365e9c9984e82..7ec523293c8e9 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -1,5 +1,5 @@ use crate::utils::{ - is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, visitors::find_all_ret_expressions, }; use if_chain::if_chain; @@ -84,6 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { let mut suggs = Vec::new(); let can_sugg = find_all_ret_expressions(cx, &body.value, |ret_expr| { if_chain! { + if !in_macro(ret_expr.span); if let ExprKind::Call(ref func, ref args) = ret_expr.kind; if let ExprKind::Path(ref qpath) = func.kind; if match_qpath(qpath, path); diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs index 0ced20b7a566d..618c452065b94 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wrap.rs @@ -76,16 +76,21 @@ fn func9(a: bool) -> Result { Err(()) } +// should not be linted +fn func10() -> Option<()> { + unimplemented!() +} + struct A; impl A { // should not be linted - pub fn func10() -> Option { + pub fn func11() -> Option { Some(1) } // should be linted - fn func11() -> Option { + fn func12() -> Option { Some(1) } } diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wrap.stderr index dbc5748c29ec4..5f21b74bc7600 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wrap.stderr @@ -86,16 +86,16 @@ LL | 1 | error: this function's return value is unnecessarily wrapped by `Option` - --> $DIR/unnecessary_wrap.rs:88:5 + --> $DIR/unnecessary_wrap.rs:93:5 | -LL | / fn func11() -> Option { +LL | / fn func12() -> Option { LL | | Some(1) LL | | } | |_____^ | help: remove `Option` from the return type... | -LL | fn func11() -> i32 { +LL | fn func12() -> i32 { | ^^^ help: ...and change the returning expressions | From c7692cf7493facefd520a98bf86aa1f4a031f435 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 17:27:08 +0900 Subject: [PATCH 080/118] Skip function with no exprs contained --- clippy_lints/src/unnecessary_wrap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 7ec523293c8e9..28cc20f000759 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { } }); - if can_sugg { + if can_sugg && !suggs.is_empty() { span_lint_and_then( cx, UNNECESSARY_WRAP, From 30632fb8e6e4d6b998f2af7da93931ddb9f5de03 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 17:55:25 +0900 Subject: [PATCH 081/118] Allow this lint on lint tests --- tests/ui/derive_ord_xor_partial_ord.rs | 1 + tests/ui/derive_ord_xor_partial_ord.stderr | 16 ++++----- tests/ui/doc_errors.rs | 1 + tests/ui/drop_ref.rs | 1 + tests/ui/forget_ref.rs | 1 + tests/ui/forget_ref.stderr | 36 +++++++++---------- tests/ui/let_underscore_must_use.rs | 1 + tests/ui/let_underscore_must_use.stderr | 24 ++++++------- tests/ui/map_flatten.fixed | 1 + tests/ui/map_flatten.rs | 1 + tests/ui/needless_lifetimes.rs | 2 +- tests/ui/option_map_unit_fn_fixable.fixed | 1 + tests/ui/option_map_unit_fn_fixable.rs | 1 + tests/ui/option_map_unit_fn_fixable.stderr | 36 +++++++++---------- tests/ui/option_option.rs | 1 + tests/ui/option_option.stderr | 20 +++++------ tests/ui/or_fun_call.fixed | 1 + tests/ui/or_fun_call.rs | 1 + tests/ui/or_fun_call.stderr | 20 +++++------ tests/ui/panic_in_result_fn.rs | 1 + tests/ui/panic_in_result_fn.stderr | 24 ++++++------- tests/ui/question_mark.fixed | 1 + tests/ui/question_mark.rs | 1 + tests/ui/question_mark.stderr | 22 ++++++------ tests/ui/redundant_pattern_matching.fixed | 1 + tests/ui/redundant_pattern_matching.rs | 1 + tests/ui/redundant_pattern_matching.stderr | 6 ++-- tests/ui/try_err.fixed | 1 + tests/ui/try_err.rs | 1 + tests/ui/try_err.stderr | 8 ++--- tests/ui/unit_arg.rs | 1 + tests/ui/unit_arg.stderr | 20 +++++------ tests/ui/unnecessary_clone.rs | 2 +- tests/ui/useless_conversion.fixed | 1 + tests/ui/useless_conversion.rs | 1 + tests/ui/useless_conversion.stderr | 22 ++++++------ tests/ui/wildcard_imports.fixed | 1 + tests/ui/wildcard_imports.rs | 1 + tests/ui/wildcard_imports.stderr | 40 +++++++++++----------- 39 files changed, 173 insertions(+), 149 deletions(-) diff --git a/tests/ui/derive_ord_xor_partial_ord.rs b/tests/ui/derive_ord_xor_partial_ord.rs index b82dc518a3ba6..78ec1727fc11f 100644 --- a/tests/ui/derive_ord_xor_partial_ord.rs +++ b/tests/ui/derive_ord_xor_partial_ord.rs @@ -1,4 +1,5 @@ #![warn(clippy::derive_ord_xor_partial_ord)] +#![allow(clippy::unnecessary_wrap)] use std::cmp::Ordering; diff --git a/tests/ui/derive_ord_xor_partial_ord.stderr b/tests/ui/derive_ord_xor_partial_ord.stderr index 66bc4d42ce8c3..97b46a4aa8982 100644 --- a/tests/ui/derive_ord_xor_partial_ord.stderr +++ b/tests/ui/derive_ord_xor_partial_ord.stderr @@ -1,12 +1,12 @@ error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> $DIR/derive_ord_xor_partial_ord.rs:20:10 + --> $DIR/derive_ord_xor_partial_ord.rs:21:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings` note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:23:1 + --> $DIR/derive_ord_xor_partial_ord.rs:24:1 | LL | / impl PartialOrd for DeriveOrd { LL | | fn partial_cmp(&self, other: &Self) -> Option { @@ -17,13 +17,13 @@ LL | | } = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> $DIR/derive_ord_xor_partial_ord.rs:29:10 + --> $DIR/derive_ord_xor_partial_ord.rs:30:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:32:1 + --> $DIR/derive_ord_xor_partial_ord.rs:33:1 | LL | / impl PartialOrd for DeriveOrdWithExplicitTypeVariable { LL | | fn partial_cmp(&self, other: &Self) -> Option { @@ -34,7 +34,7 @@ LL | | } = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> $DIR/derive_ord_xor_partial_ord.rs:41:1 + --> $DIR/derive_ord_xor_partial_ord.rs:42:1 | LL | / impl std::cmp::Ord for DerivePartialOrd { LL | | fn cmp(&self, other: &Self) -> Ordering { @@ -44,14 +44,14 @@ LL | | } | |_^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:38:10 + --> $DIR/derive_ord_xor_partial_ord.rs:39:10 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> $DIR/derive_ord_xor_partial_ord.rs:61:5 + --> $DIR/derive_ord_xor_partial_ord.rs:62:5 | LL | / impl Ord for DerivePartialOrdInUseOrd { LL | | fn cmp(&self, other: &Self) -> Ordering { @@ -61,7 +61,7 @@ LL | | } | |_____^ | note: `PartialOrd` implemented here - --> $DIR/derive_ord_xor_partial_ord.rs:58:14 + --> $DIR/derive_ord_xor_partial_ord.rs:59:14 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ diff --git a/tests/ui/doc_errors.rs b/tests/ui/doc_errors.rs index f47b81a450ea9..77df7f176f029 100644 --- a/tests/ui/doc_errors.rs +++ b/tests/ui/doc_errors.rs @@ -1,6 +1,7 @@ // edition:2018 #![warn(clippy::missing_errors_doc)] #![allow(clippy::result_unit_err)] +#![allow(clippy::unnecessary_wrap)] use std::io; diff --git a/tests/ui/drop_ref.rs b/tests/ui/drop_ref.rs index 6b5bcdaa78e27..ba12e76382152 100644 --- a/tests/ui/drop_ref.rs +++ b/tests/ui/drop_ref.rs @@ -1,6 +1,7 @@ #![warn(clippy::drop_ref)] #![allow(clippy::toplevel_ref_arg)] #![allow(clippy::map_err_ignore)] +#![allow(clippy::unnecessary_wrap)] use std::mem::drop; diff --git a/tests/ui/forget_ref.rs b/tests/ui/forget_ref.rs index 447fdbe1fac53..a9c2a92ce6be1 100644 --- a/tests/ui/forget_ref.rs +++ b/tests/ui/forget_ref.rs @@ -1,5 +1,6 @@ #![warn(clippy::forget_ref)] #![allow(clippy::toplevel_ref_arg)] +#![allow(clippy::unnecessary_wrap)] use std::mem::forget; diff --git a/tests/ui/forget_ref.stderr b/tests/ui/forget_ref.stderr index f90bcc2762cee..b2c7f2023bfbf 100644 --- a/tests/ui/forget_ref.stderr +++ b/tests/ui/forget_ref.stderr @@ -1,108 +1,108 @@ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:9:5 + --> $DIR/forget_ref.rs:10:5 | LL | forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::forget-ref` implied by `-D warnings` note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:9:12 + --> $DIR/forget_ref.rs:10:12 | LL | forget(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:12:5 + --> $DIR/forget_ref.rs:13:5 | LL | forget(&owned); | ^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:12:12 + --> $DIR/forget_ref.rs:13:12 | LL | forget(&owned); | ^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:13:5 + --> $DIR/forget_ref.rs:14:5 | LL | forget(&&owned); | ^^^^^^^^^^^^^^^ | note: argument has type `&&SomeStruct` - --> $DIR/forget_ref.rs:13:12 + --> $DIR/forget_ref.rs:14:12 | LL | forget(&&owned); | ^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:14:5 + --> $DIR/forget_ref.rs:15:5 | LL | forget(&mut owned); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:14:12 + --> $DIR/forget_ref.rs:15:12 | LL | forget(&mut owned); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:18:5 + --> $DIR/forget_ref.rs:19:5 | LL | forget(&*reference1); | ^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:18:12 + --> $DIR/forget_ref.rs:19:12 | LL | forget(&*reference1); | ^^^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:21:5 + --> $DIR/forget_ref.rs:22:5 | LL | forget(reference2); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:21:12 + --> $DIR/forget_ref.rs:22:12 | LL | forget(reference2); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:24:5 + --> $DIR/forget_ref.rs:25:5 | LL | forget(reference3); | ^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:24:12 + --> $DIR/forget_ref.rs:25:12 | LL | forget(reference3); | ^^^^^^^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:29:5 + --> $DIR/forget_ref.rs:30:5 | LL | forget(&val); | ^^^^^^^^^^^^ | note: argument has type `&T` - --> $DIR/forget_ref.rs:29:12 + --> $DIR/forget_ref.rs:30:12 | LL | forget(&val); | ^^^^ error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing. - --> $DIR/forget_ref.rs:37:5 + --> $DIR/forget_ref.rs:38:5 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:37:22 + --> $DIR/forget_ref.rs:38:22 | LL | std::mem::forget(&SomeStruct); | ^^^^^^^^^^^ diff --git a/tests/ui/let_underscore_must_use.rs b/tests/ui/let_underscore_must_use.rs index 27dda606067aa..e3800cda1b184 100644 --- a/tests/ui/let_underscore_must_use.rs +++ b/tests/ui/let_underscore_must_use.rs @@ -1,4 +1,5 @@ #![warn(clippy::let_underscore_must_use)] +#![allow(clippy::unnecessary_wrap)] // Debug implementations can fire this lint, // so we shouldn't lint external macros diff --git a/tests/ui/let_underscore_must_use.stderr b/tests/ui/let_underscore_must_use.stderr index 447f2419e3bdb..5b751ea56deff 100644 --- a/tests/ui/let_underscore_must_use.stderr +++ b/tests/ui/let_underscore_must_use.stderr @@ -1,5 +1,5 @@ error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:66:5 + --> $DIR/let_underscore_must_use.rs:67:5 | LL | let _ = f(); | ^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let _ = f(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:67:5 + --> $DIR/let_underscore_must_use.rs:68:5 | LL | let _ = g(); | ^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let _ = g(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:69:5 + --> $DIR/let_underscore_must_use.rs:70:5 | LL | let _ = l(0_u32); | ^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | let _ = l(0_u32); = help: consider explicitly using function result error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:73:5 + --> $DIR/let_underscore_must_use.rs:74:5 | LL | let _ = s.f(); | ^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | let _ = s.f(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:74:5 + --> $DIR/let_underscore_must_use.rs:75:5 | LL | let _ = s.g(); | ^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | let _ = s.g(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:77:5 + --> $DIR/let_underscore_must_use.rs:78:5 | LL | let _ = S::h(); | ^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _ = S::h(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:78:5 + --> $DIR/let_underscore_must_use.rs:79:5 | LL | let _ = S::p(); | ^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = S::p(); = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:80:5 + --> $DIR/let_underscore_must_use.rs:81:5 | LL | let _ = S::a(); | ^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | let _ = S::a(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:82:5 + --> $DIR/let_underscore_must_use.rs:83:5 | LL | let _ = if true { Ok(()) } else { Err(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | let _ = if true { Ok(()) } else { Err(()) }; = help: consider explicitly using expression value error: non-binding let on a result of a `#[must_use]` function - --> $DIR/let_underscore_must_use.rs:86:5 + --> $DIR/let_underscore_must_use.rs:87:5 | LL | let _ = a.is_ok(); | ^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL | let _ = a.is_ok(); = help: consider explicitly using function result error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:88:5 + --> $DIR/let_underscore_must_use.rs:89:5 | LL | let _ = a.map(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | let _ = a.map(|_| ()); = help: consider explicitly using expression value error: non-binding let on an expression with `#[must_use]` type - --> $DIR/let_underscore_must_use.rs:90:5 + --> $DIR/let_underscore_must_use.rs:91:5 | LL | let _ = a; | ^^^^^^^^^^ diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed index a7ab5a12cb765..b4a51837b2fbc 100644 --- a/tests/ui/map_flatten.fixed +++ b/tests/ui/map_flatten.fixed @@ -4,6 +4,7 @@ #![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] +#![allow(clippy::unnecessary_wrap)] fn main() { // mapping to Option on Iterator diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index e364a05f37605..e83cc46bda283 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -4,6 +4,7 @@ #![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] +#![allow(clippy::unnecessary_wrap)] fn main() { // mapping to Option on Iterator diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index 6001ef37eb781..e5973bbef8d4a 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value)] +#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wrap)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index 96d1c54946c0b..de2e915590608 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -2,6 +2,7 @@ #![warn(clippy::option_map_unit_fn)] #![allow(unused)] +#![allow(clippy::unnecessary_wrap)] fn do_nothing(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index 931ffc1866593..f0887c8a4bce0 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -2,6 +2,7 @@ #![warn(clippy::option_map_unit_fn)] #![allow(unused)] +#![allow(clippy::unnecessary_wrap)] fn do_nothing(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.stderr b/tests/ui/option_map_unit_fn_fixable.stderr index d7d45ef9b0b33..8abdbcafb6e93 100644 --- a/tests/ui/option_map_unit_fn_fixable.stderr +++ b/tests/ui/option_map_unit_fn_fixable.stderr @@ -1,5 +1,5 @@ error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:38:5 + --> $DIR/option_map_unit_fn_fixable.rs:39:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -9,7 +9,7 @@ LL | x.field.map(do_nothing); = note: `-D clippy::option-map-unit-fn` implied by `-D warnings` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:40:5 + --> $DIR/option_map_unit_fn_fixable.rs:41:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -17,7 +17,7 @@ LL | x.field.map(do_nothing); | help: try this: `if let Some(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:42:5 + --> $DIR/option_map_unit_fn_fixable.rs:43:5 | LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- @@ -25,7 +25,7 @@ LL | x.field.map(diverge); | help: try this: `if let Some(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:48:5 + --> $DIR/option_map_unit_fn_fixable.rs:49:5 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -33,7 +33,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:50:5 + --> $DIR/option_map_unit_fn_fixable.rs:51:5 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -41,7 +41,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:53:5 + --> $DIR/option_map_unit_fn_fixable.rs:54:5 | LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -49,7 +49,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:55:5 + --> $DIR/option_map_unit_fn_fixable.rs:56:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -57,7 +57,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:57:5 + --> $DIR/option_map_unit_fn_fixable.rs:58:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -65,7 +65,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:59:5 + --> $DIR/option_map_unit_fn_fixable.rs:60:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -73,7 +73,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | help: try this: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:62:5 + --> $DIR/option_map_unit_fn_fixable.rs:63:5 | LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -81,7 +81,7 @@ LL | x.field.map(|value| diverge(value + captured)); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:64:5 + --> $DIR/option_map_unit_fn_fixable.rs:65:5 | LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -89,7 +89,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | help: try this: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:66:5 + --> $DIR/option_map_unit_fn_fixable.rs:67:5 | LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -97,7 +97,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:68:5 + --> $DIR/option_map_unit_fn_fixable.rs:69:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -105,7 +105,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | help: try this: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:73:5 + --> $DIR/option_map_unit_fn_fixable.rs:74:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -113,7 +113,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:75:5 + --> $DIR/option_map_unit_fn_fixable.rs:76:5 | LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -121,7 +121,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:77:5 + --> $DIR/option_map_unit_fn_fixable.rs:78:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -129,7 +129,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | help: try this: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:80:5 + --> $DIR/option_map_unit_fn_fixable.rs:81:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -137,7 +137,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | help: try this: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> $DIR/option_map_unit_fn_fixable.rs:82:5 + --> $DIR/option_map_unit_fn_fixable.rs:83:5 | LL | option().map(do_nothing);} | ^^^^^^^^^^^^^^^^^^^^^^^^- diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index 2434483364151..557d29dff67ab 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -1,4 +1,5 @@ #![deny(clippy::option_option)] +#![allow(clippy::unnecessary_wrap)] fn input(_: Option>) {} diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 8ae1d23a8e33e..8ace8338fcf03 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -1,5 +1,5 @@ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:3:13 + --> $DIR/option_option.rs:4:13 | LL | fn input(_: Option>) {} | ^^^^^^^^^^^^^^^^^^ @@ -11,55 +11,55 @@ LL | #![deny(clippy::option_option)] | ^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:5:16 + --> $DIR/option_option.rs:6:16 | LL | fn output() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:9:27 + --> $DIR/option_option.rs:10:27 | LL | fn output_nested() -> Vec>> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:14:30 + --> $DIR/option_option.rs:15:30 | LL | fn output_nested_nested() -> Option>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:19:8 + --> $DIR/option_option.rs:20:8 | LL | x: Option>, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:23:23 + --> $DIR/option_option.rs:24:23 | LL | fn struct_fn() -> Option> { | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:29:22 + --> $DIR/option_option.rs:30:22 | LL | fn trait_fn() -> Option>; | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:33:11 + --> $DIR/option_option.rs:34:11 | LL | Tuple(Option>), | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:34:17 + --> $DIR/option_option.rs:35:17 | LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:75:14 + --> $DIR/option_option.rs:78:14 | LL | foo: Option>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index 20e5016bc17a0..e1735bc88f57b 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -2,6 +2,7 @@ #![warn(clippy::or_fun_call)] #![allow(dead_code)] +#![allow(clippy::unnecessary_wrap)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index e7192deeebb36..a6abd2e8b3498 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -2,6 +2,7 @@ #![warn(clippy::or_fun_call)] #![allow(dead_code)] +#![allow(clippy::unnecessary_wrap)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index d0c4df0e00817..8a7b5574c84e7 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -1,5 +1,5 @@ error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:32:19 + --> $DIR/or_fun_call.rs:33:19 | LL | with_const_fn.unwrap_or(Duration::from_secs(5)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Duration::from_secs(5))` @@ -7,55 +7,55 @@ LL | with_const_fn.unwrap_or(Duration::from_secs(5)); = note: `-D clippy::or-fun-call` implied by `-D warnings` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:35:22 + --> $DIR/or_fun_call.rs:36:22 | LL | with_constructor.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(make)` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:38:5 + --> $DIR/or_fun_call.rs:39:5 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_new.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:41:21 + --> $DIR/or_fun_call.rs:42:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:44:14 + --> $DIR/or_fun_call.rs:45:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| make())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:47:19 + --> $DIR/or_fun_call.rs:48:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:50:5 + --> $DIR/or_fun_call.rs:51:5 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_trait.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `default` - --> $DIR/or_fun_call.rs:53:5 + --> $DIR/or_fun_call.rs:54:5 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_default_type.unwrap_or_default()` error: use of `unwrap_or` followed by a call to `new` - --> $DIR/or_fun_call.rs:56:5 + --> $DIR/or_fun_call.rs:57:5 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `with_vec.unwrap_or_default()` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:59:21 + --> $DIR/or_fun_call.rs:60:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` diff --git a/tests/ui/panic_in_result_fn.rs b/tests/ui/panic_in_result_fn.rs index 287726f7a2d4e..be4e85d05a723 100644 --- a/tests/ui/panic_in_result_fn.rs +++ b/tests/ui/panic_in_result_fn.rs @@ -1,4 +1,5 @@ #![warn(clippy::panic_in_result_fn)] +#![allow(clippy::unnecessary_wrap)] struct A; diff --git a/tests/ui/panic_in_result_fn.stderr b/tests/ui/panic_in_result_fn.stderr index c6936fd86923c..ca73ac5a41114 100644 --- a/tests/ui/panic_in_result_fn.stderr +++ b/tests/ui/panic_in_result_fn.stderr @@ -1,5 +1,5 @@ error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:6:5 + --> $DIR/panic_in_result_fn.rs:7:5 | LL | / fn result_with_panic() -> Result // should emit lint LL | | { @@ -10,14 +10,14 @@ LL | | } = note: `-D clippy::panic-in-result-fn` implied by `-D warnings` = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:8:9 + --> $DIR/panic_in_result_fn.rs:9:9 | LL | panic!("error"); | ^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:11:5 + --> $DIR/panic_in_result_fn.rs:12:5 | LL | / fn result_with_unimplemented() -> Result // should emit lint LL | | { @@ -27,14 +27,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:13:9 + --> $DIR/panic_in_result_fn.rs:14:9 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:16:5 + --> $DIR/panic_in_result_fn.rs:17:5 | LL | / fn result_with_unreachable() -> Result // should emit lint LL | | { @@ -44,14 +44,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:18:9 + --> $DIR/panic_in_result_fn.rs:19:9 | LL | unreachable!(); | ^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:21:5 + --> $DIR/panic_in_result_fn.rs:22:5 | LL | / fn result_with_todo() -> Result // should emit lint LL | | { @@ -61,14 +61,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:23:9 + --> $DIR/panic_in_result_fn.rs:24:9 | LL | todo!("Finish this"); | ^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:52:1 + --> $DIR/panic_in_result_fn.rs:53:1 | LL | / fn function_result_with_panic() -> Result // should emit lint LL | | { @@ -78,14 +78,14 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:54:5 + --> $DIR/panic_in_result_fn.rs:55:5 | LL | panic!("error"); | ^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` in a function that returns `Result` - --> $DIR/panic_in_result_fn.rs:67:1 + --> $DIR/panic_in_result_fn.rs:68:1 | LL | / fn main() -> Result<(), String> { LL | | todo!("finish main method"); @@ -95,7 +95,7 @@ LL | | } | = help: `unimplemented!()`, `unreachable!()`, `todo!()` or `panic!()` should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> $DIR/panic_in_result_fn.rs:68:5 + --> $DIR/panic_in_result_fn.rs:69:5 | LL | todo!("finish main method"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index 11dff94a28865..df3c98a0aa57a 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,5 +1,6 @@ // run-rustfix #![allow(unreachable_code)] +#![allow(clippy::unnecessary_wrap)] fn some_func(a: Option) -> Option { a?; diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 1d0ee82b4f778..62b3e96b65a89 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,5 +1,6 @@ // run-rustfix #![allow(unreachable_code)] +#![allow(clippy::unnecessary_wrap)] fn some_func(a: Option) -> Option { if a.is_none() { diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index 502615fb175a1..6f330cfa385dd 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -1,5 +1,5 @@ error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:5:5 + --> $DIR/question_mark.rs:6:5 | LL | / if a.is_none() { LL | | return None; @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::question-mark` implied by `-D warnings` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:50:9 + --> $DIR/question_mark.rs:51:9 | LL | / if (self.opt).is_none() { LL | | return None; @@ -17,7 +17,7 @@ LL | | } | |_________^ help: replace it with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:54:9 + --> $DIR/question_mark.rs:55:9 | LL | / if self.opt.is_none() { LL | | return None @@ -25,7 +25,7 @@ LL | | } | |_________^ help: replace it with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:58:17 + --> $DIR/question_mark.rs:59:17 | LL | let _ = if self.opt.is_none() { | _________________^ @@ -36,7 +36,7 @@ LL | | }; | |_________^ help: replace it with: `Some(self.opt?)` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:64:17 + --> $DIR/question_mark.rs:65:17 | LL | let _ = if let Some(x) = self.opt { | _________________^ @@ -47,7 +47,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:81:9 + --> $DIR/question_mark.rs:82:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -55,7 +55,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:89:9 + --> $DIR/question_mark.rs:90:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -63,7 +63,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:97:9 + --> $DIR/question_mark.rs:98:9 | LL | / if self.opt.is_none() { LL | | return None; @@ -71,7 +71,7 @@ LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:104:26 + --> $DIR/question_mark.rs:105:26 | LL | let v: &Vec<_> = if let Some(ref v) = self.opt { | __________________________^ @@ -82,7 +82,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt.as_ref()?` error: this if-let-else may be rewritten with the `?` operator - --> $DIR/question_mark.rs:114:17 + --> $DIR/question_mark.rs:115:17 | LL | let v = if let Some(v) = self.opt { | _________________^ @@ -93,7 +93,7 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> $DIR/question_mark.rs:129:5 + --> $DIR/question_mark.rs:130:5 | LL | / if f().is_none() { LL | | return None; diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index fe8f62503b767..2e7ba8bc04d8d 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -7,6 +7,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::unnecessary_wrap, deprecated )] diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index 09426a6e59082..ea0e18f5970a8 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -7,6 +7,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, + clippy::unnecessary_wrap, deprecated )] diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 3473ceea00e22..5341e81836a4e 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -1,5 +1,5 @@ error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:15:12 + --> $DIR/redundant_pattern_matching.rs:16:12 | LL | if let Ok(_) = &result {} | -------^^^^^---------- help: try this: `if result.is_ok()` @@ -7,13 +7,13 @@ LL | if let Ok(_) = &result {} = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:17:12 + --> $DIR/redundant_pattern_matching.rs:18:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:19:12 + --> $DIR/redundant_pattern_matching.rs:20:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index aa43e69f79e8b..19458ddf68efc 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -2,6 +2,7 @@ // aux-build:macro_rules.rs #![deny(clippy::try_err)] +#![allow(clippy::unnecessary_wrap)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index df3a9dc5367f3..ab6a32dbe4d05 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -2,6 +2,7 @@ // aux-build:macro_rules.rs #![deny(clippy::try_err)] +#![allow(clippy::unnecessary_wrap)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index 3905ed2476b08..ababa64e6d843 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -1,5 +1,5 @@ error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:18:9 + --> $DIR/try_err.rs:19:9 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err)` @@ -11,19 +11,19 @@ LL | #![deny(clippy::try_err)] | ^^^^^^^^^^^^^^^ error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:28:9 + --> $DIR/try_err.rs:29:9 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:48:17 + --> $DIR/try_err.rs:49:17 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err)` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:67:17 + --> $DIR/try_err.rs:68:17 | LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index fec115ff29d66..6bf704c09e0ee 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -4,6 +4,7 @@ unused_must_use, unused_variables, clippy::unused_unit, + clippy::unnecessary_wrap, clippy::or_fun_call )] diff --git a/tests/ui/unit_arg.stderr b/tests/ui/unit_arg.stderr index 90fee3aab23b0..c3a839a9bf812 100644 --- a/tests/ui/unit_arg.stderr +++ b/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:29:5 + --> $DIR/unit_arg.rs:30:5 | LL | / foo({ LL | | 1; @@ -20,7 +20,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:32:5 + --> $DIR/unit_arg.rs:33:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:33:5 + --> $DIR/unit_arg.rs:34:5 | LL | / foo({ LL | | foo(1); @@ -54,7 +54,7 @@ LL | foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:38:5 + --> $DIR/unit_arg.rs:39:5 | LL | / b.bar({ LL | | 1; @@ -74,7 +74,7 @@ LL | b.bar(()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:41:5 + --> $DIR/unit_arg.rs:42:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:42:5 + --> $DIR/unit_arg.rs:43:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -110,7 +110,7 @@ LL | taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:46:5 + --> $DIR/unit_arg.rs:47:5 | LL | / taking_multiple_units( LL | | { @@ -140,7 +140,7 @@ LL | foo(2); ... error: passing a unit value to a function - --> $DIR/unit_arg.rs:57:13 + --> $DIR/unit_arg.rs:58:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:60:5 + --> $DIR/unit_arg.rs:61:5 | LL | foo(foo(())) | ^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL | foo(()) | error: passing a unit value to a function - --> $DIR/unit_arg.rs:93:5 + --> $DIR/unit_arg.rs:94:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index e785ac02feb32..3b1a6cf57c65b 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -1,7 +1,7 @@ // does not test any rustfixable lints #![warn(clippy::clone_on_ref_ptr)] -#![allow(unused, clippy::redundant_clone)] +#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wrap)] use std::cell::RefCell; use std::rc::{self, Rc}; diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 8a9b0cd3cf019..45ee367d649bb 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::useless_conversion)] +#![allow(clippy::unnecessary_wrap)] fn test_generic(val: T) -> T { let _ = val; diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index 4faa1572973bc..e5bdffed20d96 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,6 +1,7 @@ // run-rustfix #![deny(clippy::useless_conversion)] +#![allow(clippy::unnecessary_wrap)] fn test_generic(val: T) -> T { let _ = T::from(val); diff --git a/tests/ui/useless_conversion.stderr b/tests/ui/useless_conversion.stderr index 11c6efb25ccea..26a33595031bd 100644 --- a/tests/ui/useless_conversion.stderr +++ b/tests/ui/useless_conversion.stderr @@ -1,5 +1,5 @@ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion.rs:6:13 + --> $DIR/useless_conversion.rs:7:13 | LL | let _ = T::from(val); | ^^^^^^^^^^^^ help: consider removing `T::from()`: `val` @@ -11,61 +11,61 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> $DIR/useless_conversion.rs:7:5 + --> $DIR/useless_conversion.rs:8:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:19:22 + --> $DIR/useless_conversion.rs:20:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:60:21 + --> $DIR/useless_conversion.rs:61:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:61:21 + --> $DIR/useless_conversion.rs:62:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:62:13 + --> $DIR/useless_conversion.rs:63:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:63:13 + --> $DIR/useless_conversion.rs:64:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines` - --> $DIR/useless_conversion.rs:64:13 + --> $DIR/useless_conversion.rs:65:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> $DIR/useless_conversion.rs:65:13 + --> $DIR/useless_conversion.rs:66:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:66:21 + --> $DIR/useless_conversion.rs:67:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:71:13 + --> $DIR/useless_conversion.rs:72:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 287f8935327c5..14007e5f251da 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -4,6 +4,7 @@ #![warn(clippy::wildcard_imports)] //#![allow(clippy::redundant_pub_crate)] #![allow(unused)] +#![allow(clippy::unnecessary_wrap)] #![warn(unused_imports)] extern crate wildcard_imports_helper; diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 1f261159f4a94..0e8631ca7047e 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -4,6 +4,7 @@ #![warn(clippy::wildcard_imports)] //#![allow(clippy::redundant_pub_crate)] #![allow(unused)] +#![allow(clippy::unnecessary_wrap)] #![warn(unused_imports)] extern crate wildcard_imports_helper; diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr index 351988f31ead5..66267dd27b84f 100644 --- a/tests/ui/wildcard_imports.stderr +++ b/tests/ui/wildcard_imports.stderr @@ -1,5 +1,5 @@ error: usage of wildcard import - --> $DIR/wildcard_imports.rs:11:5 + --> $DIR/wildcard_imports.rs:12:5 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` @@ -7,85 +7,85 @@ LL | use crate::fn_mod::*; = note: `-D clippy::wildcard-imports` implied by `-D warnings` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:12:5 + --> $DIR/wildcard_imports.rs:13:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:13:5 + --> $DIR/wildcard_imports.rs:14:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:15:5 + --> $DIR/wildcard_imports.rs:16:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:19:5 + --> $DIR/wildcard_imports.rs:20:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:20:5 + --> $DIR/wildcard_imports.rs:21:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:91:13 + --> $DIR/wildcard_imports.rs:92:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:97:75 + --> $DIR/wildcard_imports.rs:98:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:98:13 + --> $DIR/wildcard_imports.rs:99:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:109:20 + --> $DIR/wildcard_imports.rs:110:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:109:30 + --> $DIR/wildcard_imports.rs:110:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:116:13 + --> $DIR/wildcard_imports.rs:117:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:145:9 + --> $DIR/wildcard_imports.rs:146:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:154:9 + --> $DIR/wildcard_imports.rs:155:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:155:9 + --> $DIR/wildcard_imports.rs:156:9 | LL | use crate:: fn_mod:: | _________^ @@ -93,31 +93,31 @@ LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:166:13 + --> $DIR/wildcard_imports.rs:167:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:201:17 + --> $DIR/wildcard_imports.rs:202:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:209:13 + --> $DIR/wildcard_imports.rs:210:13 | LL | use super_imports::*; | ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:218:17 + --> $DIR/wildcard_imports.rs:219:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> $DIR/wildcard_imports.rs:227:13 + --> $DIR/wildcard_imports.rs:228:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` From e998d61fe6a1407f73504a2fee16df2f9167a37c Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 18:36:37 +0900 Subject: [PATCH 082/118] Downgrade applicability to MaybeIncorrect --- clippy_lints/src/unnecessary_wrap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 28cc20f000759..6434b3033dd8e 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { fn_decl.output.span(), format!("remove `{}` from the return type...", return_type).as_str(), inner_ty, - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); }); diag.multipart_suggestion( From 9d96311d7354d99b6f3b3956405b7defac81461c Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 18:46:16 +0900 Subject: [PATCH 083/118] Remove wildcard use --- clippy_lints/src/unnecessary_wrap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 6434b3033dd8e..7a9cf627059f5 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -5,7 +5,7 @@ use crate::utils::{ use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::*; +use rustc_hir::{Body, ExprKind, FnDecl, HirId}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; From 532d205218c7aa28c1718f9e9088eeced6e2c5ac Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 19:24:11 +0900 Subject: [PATCH 084/118] Skip functions in PartialOrd --- clippy_lints/src/unnecessary_wrap.rs | 12 ++++++++++-- clippy_lints/src/utils/paths.rs | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index 7a9cf627059f5..ec6c823a4ec05 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -1,6 +1,6 @@ use crate::utils::{ - in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, - visitors::find_all_ret_expressions, + in_macro, is_type_diagnostic_item, match_path, match_qpath, paths, return_ty, snippet, span_lint_and_then, + trait_ref_of_method, visitors::find_all_ret_expressions, }; use if_chain::if_chain; use rustc_errors::Applicability; @@ -63,6 +63,14 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { span: Span, hir_id: HirId, ) { + if_chain! { + if let Some(trait_ref) = trait_ref_of_method(cx, hir_id); + if match_path(trait_ref.path, &paths::PARTIAL_ORD); + then { + return; + } + } + match fn_kind { FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => { if visibility.node.is_pub() { diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 2be5ff93f8695..97e01f445ffe1 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -81,6 +81,7 @@ pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"]; +pub const PARTIAL_ORD: [&str; 3] = ["std", "cmp", "PartialOrd"]; pub const PATH: [&str; 3] = ["std", "path", "Path"]; pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; From bf46f78ca7e15631f08253c14975896030ca24a8 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sun, 18 Oct 2020 19:35:59 +0900 Subject: [PATCH 085/118] Fix clippy error --- clippy_lints/src/redundant_clone.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs index b4a9804fb25a5..c4ca7fcdecc25 100644 --- a/clippy_lints/src/redundant_clone.rs +++ b/clippy_lints/src/redundant_clone.rs @@ -320,11 +320,11 @@ fn find_stmt_assigns_to<'tcx>( match (by_ref, &*rvalue) { (true, mir::Rvalue::Ref(_, _, place)) | (false, mir::Rvalue::Use(mir::Operand::Copy(place))) => { - base_local_and_movability(cx, mir, *place) + Some(base_local_and_movability(cx, mir, *place)) }, (false, mir::Rvalue::Ref(_, _, place)) => { if let [mir::ProjectionElem::Deref] = place.as_ref().projection { - base_local_and_movability(cx, mir, *place) + Some(base_local_and_movability(cx, mir, *place)) } else { None } @@ -341,7 +341,7 @@ fn base_local_and_movability<'tcx>( cx: &LateContext<'tcx>, mir: &mir::Body<'tcx>, place: mir::Place<'tcx>, -) -> Option<(mir::Local, CannotMoveOut)> { +) -> (mir::Local, CannotMoveOut) { use rustc_middle::mir::PlaceRef; // Dereference. You cannot move things out from a borrowed value. @@ -362,7 +362,7 @@ fn base_local_and_movability<'tcx>( && !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty); } - Some((local, deref || field || slice)) + (local, deref || field || slice) } struct LocalUseVisitor { From 86331a46e4030ddea41e1f9f9b8c313f58ce1eb1 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Mon, 2 Nov 2020 23:59:47 +0900 Subject: [PATCH 086/118] Update stderr files --- tests/ui/doc_errors.stderr | 14 ++++---- tests/ui/drop_ref.stderr | 36 ++++++++++---------- tests/ui/manual_unwrap_or.fixed | 2 +- tests/ui/manual_unwrap_or.rs | 2 +- tests/ui/map_err.rs | 1 + tests/ui/map_err.stderr | 2 +- tests/ui/or_fun_call.stderr | 6 ++-- tests/ui/redundant_pattern_matching.stderr | 38 +++++++++++----------- tests/ui/result_unit_error.rs | 1 + tests/ui/result_unit_error.stderr | 8 ++--- 10 files changed, 56 insertions(+), 54 deletions(-) diff --git a/tests/ui/doc_errors.stderr b/tests/ui/doc_errors.stderr index c7b616e289708..b5a81419daee3 100644 --- a/tests/ui/doc_errors.stderr +++ b/tests/ui/doc_errors.stderr @@ -1,5 +1,5 @@ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:7:1 + --> $DIR/doc_errors.rs:8:1 | LL | / pub fn pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -9,7 +9,7 @@ LL | | } = note: `-D clippy::missing-errors-doc` implied by `-D warnings` error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:11:1 + --> $DIR/doc_errors.rs:12:1 | LL | / pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -17,7 +17,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:16:1 + --> $DIR/doc_errors.rs:17:1 | LL | / pub fn pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -25,7 +25,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:21:1 + --> $DIR/doc_errors.rs:22:1 | LL | / pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { LL | | unimplemented!(); @@ -33,7 +33,7 @@ LL | | } | |_^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:51:5 + --> $DIR/doc_errors.rs:52:5 | LL | / pub fn pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -41,7 +41,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:56:5 + --> $DIR/doc_errors.rs:57:5 | LL | / pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { LL | | unimplemented!(); @@ -49,7 +49,7 @@ LL | | } | |_____^ error: docs for function returning `Result` missing `# Errors` section - --> $DIR/doc_errors.rs:85:5 + --> $DIR/doc_errors.rs:86:5 | LL | fn trait_method_missing_errors_header() -> Result<(), ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/drop_ref.stderr b/tests/ui/drop_ref.stderr index 7974bf56d44cf..10087cb4820a7 100644 --- a/tests/ui/drop_ref.stderr +++ b/tests/ui/drop_ref.stderr @@ -1,108 +1,108 @@ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:10:5 + --> $DIR/drop_ref.rs:11:5 | LL | drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^ | = note: `-D clippy::drop-ref` implied by `-D warnings` note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:10:10 + --> $DIR/drop_ref.rs:11:10 | LL | drop(&SomeStruct); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:13:5 + --> $DIR/drop_ref.rs:14:5 | LL | drop(&owned1); | ^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:13:10 + --> $DIR/drop_ref.rs:14:10 | LL | drop(&owned1); | ^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:14:5 + --> $DIR/drop_ref.rs:15:5 | LL | drop(&&owned1); | ^^^^^^^^^^^^^^ | note: argument has type `&&SomeStruct` - --> $DIR/drop_ref.rs:14:10 + --> $DIR/drop_ref.rs:15:10 | LL | drop(&&owned1); | ^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:15:5 + --> $DIR/drop_ref.rs:16:5 | LL | drop(&mut owned1); | ^^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:15:10 + --> $DIR/drop_ref.rs:16:10 | LL | drop(&mut owned1); | ^^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:19:5 + --> $DIR/drop_ref.rs:20:5 | LL | drop(reference1); | ^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:19:10 + --> $DIR/drop_ref.rs:20:10 | LL | drop(reference1); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:22:5 + --> $DIR/drop_ref.rs:23:5 | LL | drop(reference2); | ^^^^^^^^^^^^^^^^ | note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:22:10 + --> $DIR/drop_ref.rs:23:10 | LL | drop(reference2); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:25:5 + --> $DIR/drop_ref.rs:26:5 | LL | drop(reference3); | ^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:25:10 + --> $DIR/drop_ref.rs:26:10 | LL | drop(reference3); | ^^^^^^^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:30:5 + --> $DIR/drop_ref.rs:31:5 | LL | drop(&val); | ^^^^^^^^^^ | note: argument has type `&T` - --> $DIR/drop_ref.rs:30:10 + --> $DIR/drop_ref.rs:31:10 | LL | drop(&val); | ^^^^ error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing. - --> $DIR/drop_ref.rs:38:5 + --> $DIR/drop_ref.rs:39:5 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:38:20 + --> $DIR/drop_ref.rs:39:20 | LL | std::mem::drop(&SomeStruct); | ^^^^^^^^^^^ diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 5aa5a43cb92cf..740b2f6672882 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code)] -#![allow(unused_variables)] +#![allow(unused_variables, clippy::unnecessary_wrap)] fn option_unwrap_or() { // int case diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index df534031f54c3..6750662c58c07 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code)] -#![allow(unused_variables)] +#![allow(unused_variables, clippy::unnecessary_wrap)] fn option_unwrap_or() { // int case diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs index 617b642287264..231562507a85f 100644 --- a/tests/ui/map_err.rs +++ b/tests/ui/map_err.rs @@ -1,4 +1,5 @@ #![warn(clippy::map_err_ignore)] +#![allow(clippy::unnecessary_wrap)] use std::convert::TryFrom; use std::error::Error; use std::fmt; diff --git a/tests/ui/map_err.stderr b/tests/ui/map_err.stderr index 7273f46038078..390d7ce2e4e7b 100644 --- a/tests/ui/map_err.stderr +++ b/tests/ui/map_err.stderr @@ -1,5 +1,5 @@ error: `map_err(|_|...` ignores the original error - --> $DIR/map_err.rs:22:32 + --> $DIR/map_err.rs:23:32 | LL | println!("{:?}", x.map_err(|_| Errors::Ignored)); | ^^^ diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index 8a7b5574c84e7..a29e8fb58f5ed 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -61,19 +61,19 @@ LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(Foo::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:62:19 + --> $DIR/or_fun_call.rs:63:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `or_insert` followed by a function call - --> $DIR/or_fun_call.rs:65:21 + --> $DIR/or_fun_call.rs:66:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_insert_with(String::new)` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:68:21 + --> $DIR/or_fun_call.rs:69:21 | LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching.stderr index 5341e81836a4e..aeb309f5ba12a 100644 --- a/tests/ui/redundant_pattern_matching.stderr +++ b/tests/ui/redundant_pattern_matching.stderr @@ -19,19 +19,19 @@ LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:21:15 + --> $DIR/redundant_pattern_matching.rs:22:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:23:15 + --> $DIR/redundant_pattern_matching.rs:24:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:33:5 + --> $DIR/redundant_pattern_matching.rs:34:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -40,7 +40,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:38:5 + --> $DIR/redundant_pattern_matching.rs:39:5 | LL | / match Ok::(42) { LL | | Ok(_) => false, @@ -49,7 +49,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:43:5 + --> $DIR/redundant_pattern_matching.rs:44:5 | LL | / match Err::(42) { LL | | Ok(_) => false, @@ -58,7 +58,7 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:48:5 + --> $DIR/redundant_pattern_matching.rs:49:5 | LL | / match Err::(42) { LL | | Ok(_) => true, @@ -67,73 +67,73 @@ LL | | }; | |_____^ help: try this: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:53:20 + --> $DIR/redundant_pattern_matching.rs:54:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:59:20 + --> $DIR/redundant_pattern_matching.rs:60:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:61:19 + --> $DIR/redundant_pattern_matching.rs:62:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:84:19 + --> $DIR/redundant_pattern_matching.rs:85:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:85:16 + --> $DIR/redundant_pattern_matching.rs:86:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:91:12 + --> $DIR/redundant_pattern_matching.rs:92:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching.rs:92:15 + --> $DIR/redundant_pattern_matching.rs:93:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:110:12 + --> $DIR/redundant_pattern_matching.rs:111:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try this: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:112:12 + --> $DIR/redundant_pattern_matching.rs:113:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try this: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:114:15 + --> $DIR/redundant_pattern_matching.rs:115:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:116:15 + --> $DIR/redundant_pattern_matching.rs:117:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching.rs:118:5 + --> $DIR/redundant_pattern_matching.rs:119:5 | LL | / match Ok::(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching.rs:123:5 + --> $DIR/redundant_pattern_matching.rs:124:5 | LL | / match Err::(42) { LL | | Ok(_) => false, diff --git a/tests/ui/result_unit_error.rs b/tests/ui/result_unit_error.rs index a66f581b2159f..1b4a702377eae 100644 --- a/tests/ui/result_unit_error.rs +++ b/tests/ui/result_unit_error.rs @@ -1,3 +1,4 @@ +#![allow(clippy::unnecessary_wrap)] #[warn(clippy::result_unit_err)] #[allow(unused)] diff --git a/tests/ui/result_unit_error.stderr b/tests/ui/result_unit_error.stderr index b8230032491b6..12901b354f916 100644 --- a/tests/ui/result_unit_error.stderr +++ b/tests/ui/result_unit_error.stderr @@ -1,5 +1,5 @@ error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:4:1 + --> $DIR/result_unit_error.rs:5:1 | LL | pub fn returns_unit_error() -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | pub fn returns_unit_error() -> Result { = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:13:5 + --> $DIR/result_unit_error.rs:14:5 | LL | fn get_that_error(&self) -> Result; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | fn get_that_error(&self) -> Result; = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:15:5 + --> $DIR/result_unit_error.rs:16:5 | LL | fn get_this_one_too(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | fn get_this_one_too(&self) -> Result { = help: use a custom Error type instead error: this returns a `Result<_, ()> - --> $DIR/result_unit_error.rs:33:5 + --> $DIR/result_unit_error.rs:34:5 | LL | pub fn unit_error(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 4c8d248190819f09753d4f6a9f89e3804e232ae7 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sat, 14 Nov 2020 18:54:16 +0900 Subject: [PATCH 087/118] Update stderr files --- tests/ui/map_flatten.stderr | 12 ++++++------ tests/ui/option_option.stderr | 2 +- tests/ui/or_fun_call.stderr | 8 ++++---- tests/ui/try_err.stderr | 12 ++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr index d4e27f9aa0750..756e6e818ad44 100644 --- a/tests/ui/map_flatten.stderr +++ b/tests/ui/map_flatten.stderr @@ -1,5 +1,5 @@ error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:15:46 + --> $DIR/map_flatten.rs:16:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id)` @@ -7,31 +7,31 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = note: `-D clippy::map-flatten` implied by `-D warnings` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:16:46 + --> $DIR/map_flatten.rs:17:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_ref)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:17:46 + --> $DIR/map_flatten.rs:18:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(option_id_closure)` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:18:46 + --> $DIR/map_flatten.rs:19:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `filter_map` instead: `.filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on an `Iterator` - --> $DIR/map_flatten.rs:21:46 + --> $DIR/map_flatten.rs:22:46 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `.flat_map(|x| 0..x)` error: called `map(..).flatten()` on an `Option` - --> $DIR/map_flatten.rs:24:39 + --> $DIR/map_flatten.rs:25:39 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `.and_then(|x| x)` diff --git a/tests/ui/option_option.stderr b/tests/ui/option_option.stderr index 8ace8338fcf03..ad7f081c71392 100644 --- a/tests/ui/option_option.stderr +++ b/tests/ui/option_option.stderr @@ -59,7 +59,7 @@ LL | Struct { x: Option> }, | ^^^^^^^^^^^^^^^^^^ error: consider using `Option` instead of `Option>` or a custom enum if you need to distinguish all 3 cases - --> $DIR/option_option.rs:78:14 + --> $DIR/option_option.rs:76:14 | LL | foo: Option>>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/or_fun_call.stderr b/tests/ui/or_fun_call.stderr index a29e8fb58f5ed..fb8bf339828f4 100644 --- a/tests/ui/or_fun_call.stderr +++ b/tests/ui/or_fun_call.stderr @@ -79,25 +79,25 @@ LL | let _ = stringy.unwrap_or("".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| "".to_owned())` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:76:21 + --> $DIR/or_fun_call.rs:77:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `unwrap_or` followed by a function call - --> $DIR/or_fun_call.rs:78:21 + --> $DIR/or_fun_call.rs:79:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| map[&1])` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:102:35 + --> $DIR/or_fun_call.rs:103:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some("b".to_string()))` error: use of `or` followed by a function call - --> $DIR/or_fun_call.rs:106:10 + --> $DIR/or_fun_call.rs:107:10 | LL | .or(Some(Bar(b, Duration::from_secs(2)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `or_else(|| Some(Bar(b, Duration::from_secs(2))))` diff --git a/tests/ui/try_err.stderr b/tests/ui/try_err.stderr index ababa64e6d843..2c01d37192e8e 100644 --- a/tests/ui/try_err.stderr +++ b/tests/ui/try_err.stderr @@ -29,7 +29,7 @@ LL | Err(err)?; | ^^^^^^^^^ help: try this: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:86:23 + --> $DIR/try_err.rs:87:23 | LL | Err(_) => Err(1)?, | ^^^^^^^ help: try this: `return Err(1)` @@ -40,7 +40,7 @@ LL | try_validation!(Ok::<_, i32>(5)); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:101:23 + --> $DIR/try_err.rs:102:23 | LL | Err(_) => Err(ret_one!())?, | ^^^^^^^^^^^^^^^^ help: try this: `return Err(ret_one!())` @@ -51,25 +51,25 @@ LL | try_validation_in_macro!(Ok::<_, i32>(5)); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:140:9 + --> $DIR/try_err.rs:141:9 | LL | Err(foo!())?; | ^^^^^^^^^^^^ help: try this: `return Err(foo!())` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:147:9 + --> $DIR/try_err.rs:148:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:149:9 + --> $DIR/try_err.rs:150:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> $DIR/try_err.rs:157:9 + --> $DIR/try_err.rs:158:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` From 4e5c02e8980d16feeee953f112f940c598180ddc Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sat, 14 Nov 2020 19:25:54 +0900 Subject: [PATCH 088/118] Ignore trait implementations --- clippy_lints/src/unnecessary_wrap.rs | 20 +++++++++----------- clippy_lints/src/utils/paths.rs | 1 - tests/ui/unnecessary_wrap.rs | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wrap.rs index ec6c823a4ec05..2960ffc5352e7 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wrap.rs @@ -1,11 +1,11 @@ use crate::utils::{ - in_macro, is_type_diagnostic_item, match_path, match_qpath, paths, return_ty, snippet, span_lint_and_then, - trait_ref_of_method, visitors::find_all_ret_expressions, + in_macro, is_type_diagnostic_item, match_qpath, paths, return_ty, snippet, span_lint_and_then, + visitors::find_all_ret_expressions, }; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, ExprKind, FnDecl, HirId}; +use rustc_hir::{Body, ExprKind, FnDecl, HirId, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::subst::GenericArgKind; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -63,14 +63,6 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { span: Span, hir_id: HirId, ) { - if_chain! { - if let Some(trait_ref) = trait_ref_of_method(cx, hir_id); - if match_path(trait_ref.path, &paths::PARTIAL_ORD); - then { - return; - } - } - match fn_kind { FnKind::ItemFn(.., visibility, _) | FnKind::Method(.., Some(visibility), _) => { if visibility.node.is_pub() { @@ -81,6 +73,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { _ => (), } + if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) { + if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), ..} | ItemKind::Trait(..)) { + return; + } + } + let (return_type, path) = if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(option_type)) { ("Option", &paths::OPTION_SOME) } else if is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym!(result_type)) { diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 97e01f445ffe1..2be5ff93f8695 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -81,7 +81,6 @@ pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"]; -pub const PARTIAL_ORD: [&str; 3] = ["std", "cmp", "PartialOrd"]; pub const PATH: [&str; 3] = ["std", "path", "Path"]; pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"]; pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"]; diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs index 618c452065b94..1120869042825 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wrap.rs @@ -95,6 +95,20 @@ impl A { } } +trait B { + // trait impls are not linted + fn func13() -> Option { + Some(1) + } +} + +impl A for B { + // trait impls are not linted + fn func13() -> Option { + Some(0) + } +} + fn main() { // method calls are not linted func1(true, true); From 1f577c030049d974b7982f46e90d2bf96e665ea1 Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Sat, 14 Nov 2020 19:39:41 +0900 Subject: [PATCH 089/118] Fix embarrassing grammatical error --- tests/ui/unnecessary_wrap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wrap.rs index 1120869042825..58178e2e04b94 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wrap.rs @@ -102,7 +102,7 @@ trait B { } } -impl A for B { +impl B for A { // trait impls are not linted fn func13() -> Option { Some(0) From c7445d7f2c3eece2b9056d05ea92fb1d1112b3ca Mon Sep 17 00:00:00 2001 From: Hirochika Matsumoto Date: Wed, 18 Nov 2020 01:01:22 +0900 Subject: [PATCH 090/118] Pluralize lint name --- CHANGELOG.md | 2 +- clippy_lints/src/lib.rs | 10 +++++----- .../{unnecessary_wrap.rs => unnecessary_wraps.rs} | 8 ++++---- src/lintlist/mod.rs | 4 ++-- tests/ui/derive_ord_xor_partial_ord.rs | 2 +- tests/ui/doc_errors.rs | 2 +- tests/ui/drop_ref.rs | 2 +- tests/ui/forget_ref.rs | 2 +- tests/ui/let_underscore_must_use.rs | 2 +- tests/ui/manual_unwrap_or.fixed | 2 +- tests/ui/manual_unwrap_or.rs | 2 +- tests/ui/map_err.rs | 2 +- tests/ui/map_flatten.fixed | 2 +- tests/ui/map_flatten.rs | 2 +- tests/ui/needless_lifetimes.rs | 2 +- tests/ui/option_map_unit_fn_fixable.fixed | 2 +- tests/ui/option_map_unit_fn_fixable.rs | 2 +- tests/ui/option_option.rs | 2 +- tests/ui/or_fun_call.fixed | 2 +- tests/ui/or_fun_call.rs | 2 +- tests/ui/panic_in_result_fn.rs | 2 +- tests/ui/question_mark.fixed | 2 +- tests/ui/question_mark.rs | 2 +- tests/ui/redundant_pattern_matching.fixed | 2 +- tests/ui/redundant_pattern_matching.rs | 2 +- tests/ui/result_unit_error.rs | 2 +- tests/ui/try_err.fixed | 2 +- tests/ui/try_err.rs | 2 +- tests/ui/unit_arg.rs | 2 +- tests/ui/unnecessary_clone.rs | 2 +- .../ui/{unnecessary_wrap.rs => unnecessary_wraps.rs} | 2 +- ...ecessary_wrap.stderr => unnecessary_wraps.stderr} | 12 ++++++------ tests/ui/useless_conversion.fixed | 2 +- tests/ui/useless_conversion.rs | 2 +- tests/ui/wildcard_imports.fixed | 2 +- tests/ui/wildcard_imports.rs | 2 +- 36 files changed, 49 insertions(+), 49 deletions(-) rename clippy_lints/src/{unnecessary_wrap.rs => unnecessary_wraps.rs} (96%) rename tests/ui/{unnecessary_wrap.rs => unnecessary_wraps.rs} (97%) rename tests/ui/{unnecessary_wrap.stderr => unnecessary_wraps.stderr} (89%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02b862d319659..64f67680b6c3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2008,7 +2008,7 @@ Released 2018-09-13 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation [`unnecessary_sort_by`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by [`unnecessary_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap -[`unnecessary_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wrap +[`unnecessary_wraps`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_wraps [`unneeded_field_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_field_pattern [`unneeded_wildcard_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#unneeded_wildcard_pattern [`unnested_or_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnested_or_patterns diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 2d1f75391bb56..f0c1cb8d6e5ee 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -323,7 +323,7 @@ mod unicode; mod unit_return_expecting_ord; mod unnamed_address; mod unnecessary_sort_by; -mod unnecessary_wrap; +mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; mod unused_io_amount; @@ -893,7 +893,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &unnamed_address::FN_ADDRESS_COMPARISONS, &unnamed_address::VTABLE_ADDRESS_COMPARISONS, &unnecessary_sort_by::UNNECESSARY_SORT_BY, - &unnecessary_wrap::UNNECESSARY_WRAP, + &unnecessary_wraps::UNNECESSARY_WRAPS, &unnested_or_patterns::UNNESTED_OR_PATTERNS, &unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, &unused_io_amount::UNUSED_IO_AMOUNT, @@ -1066,7 +1066,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| box redundant_clone::RedundantClone); store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy); - store.register_late_pass(|| box unnecessary_wrap::UnnecessaryWrap); + store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps); store.register_late_pass(|| box types::RefToMut); store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); store.register_late_pass(|| box missing_const_for_fn::MissingConstForFn); @@ -1574,7 +1574,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&unnamed_address::FN_ADDRESS_COMPARISONS), LintId::of(&unnamed_address::VTABLE_ADDRESS_COMPARISONS), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), - LintId::of(&unnecessary_wrap::UNNECESSARY_WRAP), + LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME), LintId::of(&unused_io_amount::UNUSED_IO_AMOUNT), LintId::of(&unused_unit::UNUSED_UNIT), @@ -1779,7 +1779,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&types::UNNECESSARY_CAST), LintId::of(&types::VEC_BOX), LintId::of(&unnecessary_sort_by::UNNECESSARY_SORT_BY), - LintId::of(&unnecessary_wrap::UNNECESSARY_WRAP), + LintId::of(&unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(&unwrap::UNNECESSARY_UNWRAP), LintId::of(&useless_conversion::USELESS_CONVERSION), LintId::of(&zero_div_zero::ZERO_DIVIDED_BY_ZERO), diff --git a/clippy_lints/src/unnecessary_wrap.rs b/clippy_lints/src/unnecessary_wraps.rs similarity index 96% rename from clippy_lints/src/unnecessary_wrap.rs rename to clippy_lints/src/unnecessary_wraps.rs index 2960ffc5352e7..25ecc7a82f18b 100644 --- a/clippy_lints/src/unnecessary_wrap.rs +++ b/clippy_lints/src/unnecessary_wraps.rs @@ -46,14 +46,14 @@ declare_clippy_lint! { /// } /// } /// ``` - pub UNNECESSARY_WRAP, + pub UNNECESSARY_WRAPS, complexity, "functions that only return `Ok` or `Some`" } -declare_lint_pass!(UnnecessaryWrap => [UNNECESSARY_WRAP]); +declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]); -impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { +impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { fn check_fn( &mut self, cx: &LateContext<'tcx>, @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWrap { if can_sugg && !suggs.is_empty() { span_lint_and_then( cx, - UNNECESSARY_WRAP, + UNNECESSARY_WRAPS, span, format!( "this function's return value is unnecessarily wrapped by `{}`", diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 4a0cdc5d82f9b..a2edd6cd0bd4f 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2609,11 +2609,11 @@ vec![ module: "unwrap", }, Lint { - name: "unnecessary_wrap", + name: "unnecessary_wraps", group: "complexity", desc: "functions that only return `Ok` or `Some`", deprecation: None, - module: "unnecessary_wrap", + module: "unnecessary_wraps", }, Lint { name: "unneeded_field_pattern", diff --git a/tests/ui/derive_ord_xor_partial_ord.rs b/tests/ui/derive_ord_xor_partial_ord.rs index 78ec1727fc11f..6f12d36d777dc 100644 --- a/tests/ui/derive_ord_xor_partial_ord.rs +++ b/tests/ui/derive_ord_xor_partial_ord.rs @@ -1,5 +1,5 @@ #![warn(clippy::derive_ord_xor_partial_ord)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] use std::cmp::Ordering; diff --git a/tests/ui/doc_errors.rs b/tests/ui/doc_errors.rs index 77df7f176f029..c77a74a58f22c 100644 --- a/tests/ui/doc_errors.rs +++ b/tests/ui/doc_errors.rs @@ -1,7 +1,7 @@ // edition:2018 #![warn(clippy::missing_errors_doc)] #![allow(clippy::result_unit_err)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] use std::io; diff --git a/tests/ui/drop_ref.rs b/tests/ui/drop_ref.rs index ba12e76382152..e1a15c609fd23 100644 --- a/tests/ui/drop_ref.rs +++ b/tests/ui/drop_ref.rs @@ -1,7 +1,7 @@ #![warn(clippy::drop_ref)] #![allow(clippy::toplevel_ref_arg)] #![allow(clippy::map_err_ignore)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] use std::mem::drop; diff --git a/tests/ui/forget_ref.rs b/tests/ui/forget_ref.rs index a9c2a92ce6be1..c49e6756a6c5b 100644 --- a/tests/ui/forget_ref.rs +++ b/tests/ui/forget_ref.rs @@ -1,6 +1,6 @@ #![warn(clippy::forget_ref)] #![allow(clippy::toplevel_ref_arg)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] use std::mem::forget; diff --git a/tests/ui/let_underscore_must_use.rs b/tests/ui/let_underscore_must_use.rs index e3800cda1b184..a842e872a37b1 100644 --- a/tests/ui/let_underscore_must_use.rs +++ b/tests/ui/let_underscore_must_use.rs @@ -1,5 +1,5 @@ #![warn(clippy::let_underscore_must_use)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] // Debug implementations can fire this lint, // so we shouldn't lint external macros diff --git a/tests/ui/manual_unwrap_or.fixed b/tests/ui/manual_unwrap_or.fixed index 740b2f6672882..81d903c15d32a 100644 --- a/tests/ui/manual_unwrap_or.fixed +++ b/tests/ui/manual_unwrap_or.fixed @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code)] -#![allow(unused_variables, clippy::unnecessary_wrap)] +#![allow(unused_variables, clippy::unnecessary_wraps)] fn option_unwrap_or() { // int case diff --git a/tests/ui/manual_unwrap_or.rs b/tests/ui/manual_unwrap_or.rs index 6750662c58c07..16105d379c305 100644 --- a/tests/ui/manual_unwrap_or.rs +++ b/tests/ui/manual_unwrap_or.rs @@ -1,6 +1,6 @@ // run-rustfix #![allow(dead_code)] -#![allow(unused_variables, clippy::unnecessary_wrap)] +#![allow(unused_variables, clippy::unnecessary_wraps)] fn option_unwrap_or() { // int case diff --git a/tests/ui/map_err.rs b/tests/ui/map_err.rs index 231562507a85f..05b9949f10217 100644 --- a/tests/ui/map_err.rs +++ b/tests/ui/map_err.rs @@ -1,5 +1,5 @@ #![warn(clippy::map_err_ignore)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] use std::convert::TryFrom; use std::error::Error; use std::fmt; diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed index b4a51837b2fbc..773b5914439d3 100644 --- a/tests/ui/map_flatten.fixed +++ b/tests/ui/map_flatten.fixed @@ -4,7 +4,7 @@ #![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn main() { // mapping to Option on Iterator diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs index e83cc46bda283..578bd87726795 100644 --- a/tests/ui/map_flatten.rs +++ b/tests/ui/map_flatten.rs @@ -4,7 +4,7 @@ #![allow(clippy::let_underscore_drop)] #![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::map_identity)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn main() { // mapping to Option on Iterator diff --git a/tests/ui/needless_lifetimes.rs b/tests/ui/needless_lifetimes.rs index e5973bbef8d4a..44972c8c63964 100644 --- a/tests/ui/needless_lifetimes.rs +++ b/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ #![warn(clippy::needless_lifetimes)] -#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wrap)] +#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps)] fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} diff --git a/tests/ui/option_map_unit_fn_fixable.fixed b/tests/ui/option_map_unit_fn_fixable.fixed index de2e915590608..7d29445e66c8b 100644 --- a/tests/ui/option_map_unit_fn_fixable.fixed +++ b/tests/ui/option_map_unit_fn_fixable.fixed @@ -2,7 +2,7 @@ #![warn(clippy::option_map_unit_fn)] #![allow(unused)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn do_nothing(_: T) {} diff --git a/tests/ui/option_map_unit_fn_fixable.rs b/tests/ui/option_map_unit_fn_fixable.rs index f0887c8a4bce0..b6f834f686f9f 100644 --- a/tests/ui/option_map_unit_fn_fixable.rs +++ b/tests/ui/option_map_unit_fn_fixable.rs @@ -2,7 +2,7 @@ #![warn(clippy::option_map_unit_fn)] #![allow(unused)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn do_nothing(_: T) {} diff --git a/tests/ui/option_option.rs b/tests/ui/option_option.rs index 557d29dff67ab..6859ba8e5bb8f 100644 --- a/tests/ui/option_option.rs +++ b/tests/ui/option_option.rs @@ -1,5 +1,5 @@ #![deny(clippy::option_option)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn input(_: Option>) {} diff --git a/tests/ui/or_fun_call.fixed b/tests/ui/or_fun_call.fixed index e1735bc88f57b..2a63318c8c7a8 100644 --- a/tests/ui/or_fun_call.fixed +++ b/tests/ui/or_fun_call.fixed @@ -2,7 +2,7 @@ #![warn(clippy::or_fun_call)] #![allow(dead_code)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/or_fun_call.rs b/tests/ui/or_fun_call.rs index a6abd2e8b3498..026ef437caa1a 100644 --- a/tests/ui/or_fun_call.rs +++ b/tests/ui/or_fun_call.rs @@ -2,7 +2,7 @@ #![warn(clippy::or_fun_call)] #![allow(dead_code)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/tests/ui/panic_in_result_fn.rs b/tests/ui/panic_in_result_fn.rs index be4e85d05a723..3d3c19a1be519 100644 --- a/tests/ui/panic_in_result_fn.rs +++ b/tests/ui/panic_in_result_fn.rs @@ -1,5 +1,5 @@ #![warn(clippy::panic_in_result_fn)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] struct A; diff --git a/tests/ui/question_mark.fixed b/tests/ui/question_mark.fixed index df3c98a0aa57a..0b5746cb52270 100644 --- a/tests/ui/question_mark.fixed +++ b/tests/ui/question_mark.fixed @@ -1,6 +1,6 @@ // run-rustfix #![allow(unreachable_code)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn some_func(a: Option) -> Option { a?; diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index 62b3e96b65a89..0f0825c933467 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -1,6 +1,6 @@ // run-rustfix #![allow(unreachable_code)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn some_func(a: Option) -> Option { if a.is_none() { diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching.fixed index 2e7ba8bc04d8d..aa20512296aa1 100644 --- a/tests/ui/redundant_pattern_matching.fixed +++ b/tests/ui/redundant_pattern_matching.fixed @@ -7,7 +7,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, - clippy::unnecessary_wrap, + clippy::unnecessary_wraps, deprecated )] diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching.rs index ea0e18f5970a8..d76f9c288ffdb 100644 --- a/tests/ui/redundant_pattern_matching.rs +++ b/tests/ui/redundant_pattern_matching.rs @@ -7,7 +7,7 @@ unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro, - clippy::unnecessary_wrap, + clippy::unnecessary_wraps, deprecated )] diff --git a/tests/ui/result_unit_error.rs b/tests/ui/result_unit_error.rs index 1b4a702377eae..5e57c752b5a03 100644 --- a/tests/ui/result_unit_error.rs +++ b/tests/ui/result_unit_error.rs @@ -1,4 +1,4 @@ -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] #[warn(clippy::result_unit_err)] #[allow(unused)] diff --git a/tests/ui/try_err.fixed b/tests/ui/try_err.fixed index 19458ddf68efc..652b611208b73 100644 --- a/tests/ui/try_err.fixed +++ b/tests/ui/try_err.fixed @@ -2,7 +2,7 @@ // aux-build:macro_rules.rs #![deny(clippy::try_err)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/try_err.rs b/tests/ui/try_err.rs index ab6a32dbe4d05..6bd479657b70b 100644 --- a/tests/ui/try_err.rs +++ b/tests/ui/try_err.rs @@ -2,7 +2,7 @@ // aux-build:macro_rules.rs #![deny(clippy::try_err)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] #[macro_use] extern crate macro_rules; diff --git a/tests/ui/unit_arg.rs b/tests/ui/unit_arg.rs index 6bf704c09e0ee..9ad16d365094e 100644 --- a/tests/ui/unit_arg.rs +++ b/tests/ui/unit_arg.rs @@ -4,7 +4,7 @@ unused_must_use, unused_variables, clippy::unused_unit, - clippy::unnecessary_wrap, + clippy::unnecessary_wraps, clippy::or_fun_call )] diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs index 3b1a6cf57c65b..6770a7fac90fd 100644 --- a/tests/ui/unnecessary_clone.rs +++ b/tests/ui/unnecessary_clone.rs @@ -1,7 +1,7 @@ // does not test any rustfixable lints #![warn(clippy::clone_on_ref_ptr)] -#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wrap)] +#![allow(unused, clippy::redundant_clone, clippy::unnecessary_wraps)] use std::cell::RefCell; use std::rc::{self, Rc}; diff --git a/tests/ui/unnecessary_wrap.rs b/tests/ui/unnecessary_wraps.rs similarity index 97% rename from tests/ui/unnecessary_wrap.rs rename to tests/ui/unnecessary_wraps.rs index 58178e2e04b94..a53dec8f91ac5 100644 --- a/tests/ui/unnecessary_wrap.rs +++ b/tests/ui/unnecessary_wraps.rs @@ -1,4 +1,4 @@ -#![warn(clippy::unnecessary_wrap)] +#![warn(clippy::unnecessary_wraps)] #![allow(clippy::no_effect)] #![allow(clippy::needless_return)] #![allow(clippy::if_same_then_else)] diff --git a/tests/ui/unnecessary_wrap.stderr b/tests/ui/unnecessary_wraps.stderr similarity index 89% rename from tests/ui/unnecessary_wrap.stderr rename to tests/ui/unnecessary_wraps.stderr index 5f21b74bc7600..410f054b8efca 100644 --- a/tests/ui/unnecessary_wrap.stderr +++ b/tests/ui/unnecessary_wraps.stderr @@ -1,5 +1,5 @@ error: this function's return value is unnecessarily wrapped by `Option` - --> $DIR/unnecessary_wrap.rs:8:1 + --> $DIR/unnecessary_wraps.rs:8:1 | LL | / fn func1(a: bool, b: bool) -> Option { LL | | if a && b { @@ -10,7 +10,7 @@ LL | | } LL | | } | |_^ | - = note: `-D clippy::unnecessary-wrap` implied by `-D warnings` + = note: `-D clippy::unnecessary-wraps` implied by `-D warnings` help: remove `Option` from the return type... | LL | fn func1(a: bool, b: bool) -> i32 { @@ -26,7 +26,7 @@ LL | } else { ... error: this function's return value is unnecessarily wrapped by `Option` - --> $DIR/unnecessary_wrap.rs:21:1 + --> $DIR/unnecessary_wraps.rs:21:1 | LL | / fn func2(a: bool, b: bool) -> Option { LL | | if a && b { @@ -52,7 +52,7 @@ LL | 30 | error: this function's return value is unnecessarily wrapped by `Option` - --> $DIR/unnecessary_wrap.rs:51:1 + --> $DIR/unnecessary_wraps.rs:51:1 | LL | / fn func5() -> Option { LL | | Some(1) @@ -69,7 +69,7 @@ LL | 1 | error: this function's return value is unnecessarily wrapped by `Result` - --> $DIR/unnecessary_wrap.rs:61:1 + --> $DIR/unnecessary_wraps.rs:61:1 | LL | / fn func7() -> Result { LL | | Ok(1) @@ -86,7 +86,7 @@ LL | 1 | error: this function's return value is unnecessarily wrapped by `Option` - --> $DIR/unnecessary_wrap.rs:93:5 + --> $DIR/unnecessary_wraps.rs:93:5 | LL | / fn func12() -> Option { LL | | Some(1) diff --git a/tests/ui/useless_conversion.fixed b/tests/ui/useless_conversion.fixed index 45ee367d649bb..03977de9455eb 100644 --- a/tests/ui/useless_conversion.fixed +++ b/tests/ui/useless_conversion.fixed @@ -1,7 +1,7 @@ // run-rustfix #![deny(clippy::useless_conversion)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn test_generic(val: T) -> T { let _ = val; diff --git a/tests/ui/useless_conversion.rs b/tests/ui/useless_conversion.rs index e5bdffed20d96..f6e094c16616c 100644 --- a/tests/ui/useless_conversion.rs +++ b/tests/ui/useless_conversion.rs @@ -1,7 +1,7 @@ // run-rustfix #![deny(clippy::useless_conversion)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] fn test_generic(val: T) -> T { let _ = T::from(val); diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed index 14007e5f251da..ee9c9045fff55 100644 --- a/tests/ui/wildcard_imports.fixed +++ b/tests/ui/wildcard_imports.fixed @@ -4,7 +4,7 @@ #![warn(clippy::wildcard_imports)] //#![allow(clippy::redundant_pub_crate)] #![allow(unused)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] extern crate wildcard_imports_helper; diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs index 0e8631ca7047e..efaa8f9ef6641 100644 --- a/tests/ui/wildcard_imports.rs +++ b/tests/ui/wildcard_imports.rs @@ -4,7 +4,7 @@ #![warn(clippy::wildcard_imports)] //#![allow(clippy::redundant_pub_crate)] #![allow(unused)] -#![allow(clippy::unnecessary_wrap)] +#![allow(clippy::unnecessary_wraps)] #![warn(unused_imports)] extern crate wildcard_imports_helper; From bf2d31d0533ee03a2c1e91f74780ea779e8b330c Mon Sep 17 00:00:00 2001 From: flip1995 Date: Tue, 17 Nov 2020 18:08:12 +0100 Subject: [PATCH 091/118] Run cargo dev fmt --- clippy_lints/src/mut_key.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/clippy_lints/src/mut_key.rs b/clippy_lints/src/mut_key.rs index 9cceecc785a28..11044e0c2fb48 100644 --- a/clippy_lints/src/mut_key.rs +++ b/clippy_lints/src/mut_key.rs @@ -89,11 +89,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir:: for (hir_ty, ty) in decl.inputs.iter().zip(fn_sig.inputs().skip_binder().iter()) { check_ty(cx, hir_ty.span, ty); } - check_ty( - cx, - decl.output.span(), - cx.tcx.erase_late_bound_regions(fn_sig.output()), - ); + check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output())); } // We want to lint 1. sets or maps with 2. not immutable key types and 3. no unerased From 4e4c4fb8aa5010313c8bcc8a6f1edd9912702269 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 17 Nov 2020 12:16:15 -0800 Subject: [PATCH 092/118] Fix handling of panic calls This should make Clippy more resilient and will unblock #78343. This PR is made against rust-lang/rust to avoid the need for a subtree sync at @flip1995's suggestion in rust-lang/rust-clippy#6310. --- clippy_lints/src/assertions_on_constants.rs | 5 +-- clippy_lints/src/attrs.rs | 4 +- clippy_lints/src/fallible_impl_from.rs | 9 ++-- clippy_lints/src/implicit_return.rs | 9 +--- clippy_lints/src/panic_unimplemented.rs | 44 +++++++++--------- clippy_lints/src/utils/mod.rs | 20 ++++++++- clippy_lints/src/utils/paths.rs | 8 +++- tests/ui/panicking_macros.rs | 11 +++++ tests/ui/panicking_macros.stderr | 50 +++++++++++++++------ 9 files changed, 106 insertions(+), 54 deletions(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 982d5ecf8d02f..a2ccb0369c4a4 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,6 +1,5 @@ use crate::consts::{constant, Constant}; -use crate::utils::paths; -use crate::utils::{is_direct_expn_of, is_expn_of, match_function_call, snippet_opt, span_lint_and_help}; +use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, snippet_opt, span_lint_and_help}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind, PatKind, UnOp}; @@ -133,7 +132,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) if let ExprKind::Block(ref inner_block, _) = block_expr.kind; if let Some(begin_panic_call) = &inner_block.expr; // function call - if let Some(args) = match_function_call(cx, begin_panic_call, &paths::BEGIN_PANIC); + if let Some(args) = match_panic_call(cx, begin_panic_call); if args.len() == 1; // bind the second argument of the `assert!` macro if it exists if let panic_message = snippet_opt(cx, args[0].span); diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 55904a0ec0a84..57702dafa6a0c 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -1,7 +1,7 @@ //! checks for attributes use crate::utils::{ - first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_help, + first_line_of_span, is_present_in_source, match_panic_def_id, snippet_opt, span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then, without_block_comments, }; use if_chain::if_chain; @@ -513,7 +513,7 @@ fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_> typeck_results .qpath_res(qpath, path_expr.hir_id) .opt_def_id() - .map_or(true, |fun_id| !match_def_path(cx, fun_id, &paths::BEGIN_PANIC)) + .map_or(true, |fun_id| !match_panic_def_id(cx, fun_id)) } else { true } diff --git a/clippy_lints/src/fallible_impl_from.rs b/clippy_lints/src/fallible_impl_from.rs index fe817fe94f2e4..509a4a4e15f62 100644 --- a/clippy_lints/src/fallible_impl_from.rs +++ b/clippy_lints/src/fallible_impl_from.rs @@ -1,5 +1,7 @@ -use crate::utils::paths::{BEGIN_PANIC, BEGIN_PANIC_FMT, FROM_TRAIT}; -use crate::utils::{is_expn_of, is_type_diagnostic_item, match_def_path, method_chain_args, span_lint_and_then}; +use crate::utils::paths::FROM_TRAIT; +use crate::utils::{ + is_expn_of, is_type_diagnostic_item, match_def_path, match_panic_def_id, method_chain_args, span_lint_and_then, +}; use if_chain::if_chain; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -84,8 +86,7 @@ fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[h if let ExprKind::Call(ref func_expr, _) = expr.kind; if let ExprKind::Path(QPath::Resolved(_, ref path)) = func_expr.kind; if let Some(path_def_id) = path.res.opt_def_id(); - if match_def_path(self.lcx, path_def_id, &BEGIN_PANIC) || - match_def_path(self.lcx, path_def_id, &BEGIN_PANIC_FMT); + if match_panic_def_id(self.lcx, path_def_id); if is_expn_of(expr.span, "unreachable").is_none(); then { self.result.push(expr.span); diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 22c4fef32a32b..ed7f3b9293dbf 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -1,8 +1,4 @@ -use crate::utils::{ - fn_has_unsatisfiable_preds, match_def_path, - paths::{BEGIN_PANIC, BEGIN_PANIC_FMT}, - snippet_opt, span_lint_and_then, -}; +use crate::utils::{fn_has_unsatisfiable_preds, match_panic_def_id, snippet_opt, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -109,8 +105,7 @@ fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Path(qpath) = &expr.kind; if let Some(path_def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id(); - if match_def_path(cx, path_def_id, &BEGIN_PANIC) || - match_def_path(cx, path_def_id, &BEGIN_PANIC_FMT); + if match_panic_def_id(cx, path_def_id); then { } else { lint(cx, expr.span, expr.span, LINT_RETURN) diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 6379dffd22e37..3d888fe732573 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,4 +1,4 @@ -use crate::utils::{is_direct_expn_of, is_expn_of, match_function_call, paths, span_lint}; +use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, span_lint}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; @@ -93,27 +93,27 @@ declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED, UNREACHAB impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if_chain! { - if let ExprKind::Block(ref block, _) = expr.kind; - if let Some(ref ex) = block.expr; - if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC) - .or_else(|| match_function_call(cx, ex, &paths::BEGIN_PANIC_FMT)); - then { - let span = get_outer_span(expr); - if is_expn_of(expr.span, "unimplemented").is_some() { - span_lint(cx, UNIMPLEMENTED, span, - "`unimplemented` should not be present in production code"); - } else if is_expn_of(expr.span, "todo").is_some() { - span_lint(cx, TODO, span, - "`todo` should not be present in production code"); - } else if is_expn_of(expr.span, "unreachable").is_some() { - span_lint(cx, UNREACHABLE, span, - "`unreachable` should not be present in production code"); - } else if is_expn_of(expr.span, "panic").is_some() { - span_lint(cx, PANIC, span, - "`panic` should not be present in production code"); - match_panic(params, expr, cx); - } + if let Some(params) = match_panic_call(cx, expr) { + let span = get_outer_span(expr); + if is_expn_of(expr.span, "unimplemented").is_some() { + span_lint( + cx, + UNIMPLEMENTED, + span, + "`unimplemented` should not be present in production code", + ); + } else if is_expn_of(expr.span, "todo").is_some() { + span_lint(cx, TODO, span, "`todo` should not be present in production code"); + } else if is_expn_of(expr.span, "unreachable").is_some() { + span_lint( + cx, + UNREACHABLE, + span, + "`unreachable` should not be present in production code", + ); + } else if is_expn_of(expr.span, "panic").is_some() { + span_lint(cx, PANIC, span, "`panic` should not be present in production code"); + match_panic(params, expr, cx); } } } diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 0d43fd0392eb2..a68262d56c64d 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1196,7 +1196,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option< /// Usage: /// /// ```rust,ignore -/// if let Some(args) = match_function_call(cx, begin_panic_call, &paths::BEGIN_PANIC); +/// if let Some(args) = match_function_call(cx, cmp_max_call, &paths::CMP_MAX); /// ``` pub fn match_function_call<'tcx>( cx: &LateContext<'tcx>, @@ -1231,6 +1231,24 @@ pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) - cx.match_def_path(did, &syms) } +pub fn match_panic_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx [Expr<'tcx>]> { + match_function_call(cx, expr, &paths::BEGIN_PANIC) + .or_else(|| match_function_call(cx, expr, &paths::BEGIN_PANIC_FMT)) + .or_else(|| match_function_call(cx, expr, &paths::PANIC_ANY)) + .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC)) + .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_FMT)) + .or_else(|| match_function_call(cx, expr, &paths::PANICKING_PANIC_STR)) +} + +pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool { + match_def_path(cx, did, &paths::BEGIN_PANIC) + || match_def_path(cx, did, &paths::BEGIN_PANIC_FMT) + || match_def_path(cx, did, &paths::PANIC_ANY) + || match_def_path(cx, did, &paths::PANICKING_PANIC) + || match_def_path(cx, did, &paths::PANICKING_PANIC_FMT) + || match_def_path(cx, did, &paths::PANICKING_PANIC_STR) +} + /// Returns the list of condition expressions and the list of blocks in a /// sequence of `if/else`. /// E.g., this returns `([a, b], [c, d, e])` for the expression diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs index 1ad8c6029860b..8f5fbfd9f846a 100644 --- a/clippy_lints/src/utils/paths.rs +++ b/clippy_lints/src/utils/paths.rs @@ -8,8 +8,8 @@ pub const ANY_TRAIT: [&str; 3] = ["std", "any", "Any"]; pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"]; pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"]; pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"]; -pub const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; -pub const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"]; +pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"]; +pub(super) const BEGIN_PANIC_FMT: [&str; 3] = ["std", "panicking", "begin_panic_fmt"]; pub const BINARY_HEAP: [&str; 4] = ["alloc", "collections", "binary_heap", "BinaryHeap"]; pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"]; pub const BOX: [&str; 3] = ["alloc", "boxed", "Box"]; @@ -78,6 +78,10 @@ pub const ORD: [&str; 3] = ["core", "cmp", "Ord"]; pub const OS_STRING: [&str; 4] = ["std", "ffi", "os_str", "OsString"]; pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"]; pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"]; +pub(super) const PANICKING_PANIC: [&str; 3] = ["core", "panicking", "panic"]; +pub(super) const PANICKING_PANIC_FMT: [&str; 3] = ["core", "panicking", "panic_fmt"]; +pub(super) const PANICKING_PANIC_STR: [&str; 3] = ["core", "panicking", "panic_str"]; +pub(super) const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"]; pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"]; pub const PARKING_LOT_RWLOCK_READ_GUARD: [&str; 2] = ["parking_lot", "RwLockReadGuard"]; pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 2] = ["parking_lot", "RwLockWriteGuard"]; diff --git a/tests/ui/panicking_macros.rs b/tests/ui/panicking_macros.rs index f91ccfaed743d..77fcb8dfd02fd 100644 --- a/tests/ui/panicking_macros.rs +++ b/tests/ui/panicking_macros.rs @@ -1,6 +1,8 @@ #![warn(clippy::unimplemented, clippy::unreachable, clippy::todo, clippy::panic)] #![allow(clippy::assertions_on_constants)] +extern crate core; + fn panic() { let a = 2; panic!(); @@ -33,9 +35,18 @@ fn unreachable() { let b = a + 2; } +fn core_versions() { + use core::{panic, todo, unimplemented, unreachable}; + panic!(); + todo!(); + unimplemented!(); + unreachable!(); +} + fn main() { panic(); todo(); unimplemented(); unreachable(); + core_versions(); } diff --git a/tests/ui/panicking_macros.stderr b/tests/ui/panicking_macros.stderr index 37c11d72a574a..83234c0ed92cc 100644 --- a/tests/ui/panicking_macros.stderr +++ b/tests/ui/panicking_macros.stderr @@ -1,5 +1,5 @@ error: `panic` should not be present in production code - --> $DIR/panicking_macros.rs:6:5 + --> $DIR/panicking_macros.rs:8:5 | LL | panic!(); | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | panic!(); = note: `-D clippy::panic` implied by `-D warnings` error: `panic` should not be present in production code - --> $DIR/panicking_macros.rs:7:5 + --> $DIR/panicking_macros.rs:9:5 | LL | panic!("message"); | ^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | panic!("message"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `panic` should not be present in production code - --> $DIR/panicking_macros.rs:8:5 + --> $DIR/panicking_macros.rs:10:5 | LL | panic!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | panic!("{} {}", "panic with", "multiple arguments"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `todo` should not be present in production code - --> $DIR/panicking_macros.rs:14:5 + --> $DIR/panicking_macros.rs:16:5 | LL | todo!(); | ^^^^^^^^ @@ -31,19 +31,19 @@ LL | todo!(); = note: `-D clippy::todo` implied by `-D warnings` error: `todo` should not be present in production code - --> $DIR/panicking_macros.rs:15:5 + --> $DIR/panicking_macros.rs:17:5 | LL | todo!("message"); | ^^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> $DIR/panicking_macros.rs:16:5 + --> $DIR/panicking_macros.rs:18:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> $DIR/panicking_macros.rs:22:5 + --> $DIR/panicking_macros.rs:24:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^^ @@ -51,19 +51,19 @@ LL | unimplemented!(); = note: `-D clippy::unimplemented` implied by `-D warnings` error: `unimplemented` should not be present in production code - --> $DIR/panicking_macros.rs:23:5 + --> $DIR/panicking_macros.rs:25:5 | LL | unimplemented!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> $DIR/panicking_macros.rs:24:5 + --> $DIR/panicking_macros.rs:26:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unreachable` should not be present in production code - --> $DIR/panicking_macros.rs:30:5 + --> $DIR/panicking_macros.rs:32:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | unreachable!(); = note: `-D clippy::unreachable` implied by `-D warnings` error: `unreachable` should not be present in production code - --> $DIR/panicking_macros.rs:31:5 + --> $DIR/panicking_macros.rs:33:5 | LL | unreachable!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,10 +79,34 @@ LL | unreachable!("message"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `unreachable` should not be present in production code - --> $DIR/panicking_macros.rs:32:5 + --> $DIR/panicking_macros.rs:34:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: `panic` should not be present in production code + --> $DIR/panicking_macros.rs:40:5 + | +LL | panic!(); + | ^^^^^^^^^ + +error: `todo` should not be present in production code + --> $DIR/panicking_macros.rs:41:5 + | +LL | todo!(); + | ^^^^^^^^ + +error: `unimplemented` should not be present in production code + --> $DIR/panicking_macros.rs:42:5 + | +LL | unimplemented!(); + | ^^^^^^^^^^^^^^^^^ + +error: `unreachable` should not be present in production code + --> $DIR/panicking_macros.rs:43:5 + | +LL | unreachable!(); + | ^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors From 0502ac2a87458620ae83e5260fd13149a558e090 Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Wed, 18 Nov 2020 08:33:25 +0900 Subject: [PATCH 093/118] Improve doc about `map_clone` --- clippy_lints/src/map_clone.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs index 3f34dd5112eff..220240acb7aa9 100644 --- a/clippy_lints/src/map_clone.rs +++ b/clippy_lints/src/map_clone.rs @@ -14,8 +14,9 @@ use rustc_span::symbol::Ident; use rustc_span::{sym, Span}; declare_clippy_lint! { - /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests - /// `iterator.cloned()` instead + /// **What it does:** Checks for usage of `map(|x| x.clone())` or + /// dereferencing closures for `Copy` types, on `Iterator` or `Option`, + /// and suggests `cloned()` or `copied()` instead /// /// **Why is this bad?** Readability, this can be written more concisely /// From 6494bd0bac72b621fc4db64d68c94c8199e97afe Mon Sep 17 00:00:00 2001 From: Takayuki Nakata Date: Wed, 18 Nov 2020 12:36:47 +0900 Subject: [PATCH 094/118] Revert "Add `rustfmt::skip` as a work around" This reverts commit 0e803417f997ba35c0045704dd347e64c2a1786c. Fixed by https://github.com/rust-lang/rustfmt/issues/4528. --- tests/ui/cast_ref_to_mut.rs | 4 ---- tests/ui/cast_ref_to_mut.stderr | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/ui/cast_ref_to_mut.rs b/tests/ui/cast_ref_to_mut.rs index 0ede958d17069..089e5cfabe4b9 100644 --- a/tests/ui/cast_ref_to_mut.rs +++ b/tests/ui/cast_ref_to_mut.rs @@ -2,10 +2,6 @@ #![allow(clippy::no_effect)] extern "C" { - #[rustfmt::skip] - // TODO: This `rustfmt::skip` is a work around of #6336 because - // the following comments are checked by rustfmt for some reason. - // // N.B., mutability can be easily incorrect in FFI calls -- as // in C, the default is mutable pointers. fn ffi(c: *mut u8); diff --git a/tests/ui/cast_ref_to_mut.stderr b/tests/ui/cast_ref_to_mut.stderr index d36aa0e00eecc..aacd99437d9fc 100644 --- a/tests/ui/cast_ref_to_mut.stderr +++ b/tests/ui/cast_ref_to_mut.stderr @@ -1,5 +1,5 @@ error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell` - --> $DIR/cast_ref_to_mut.rs:22:9 + --> $DIR/cast_ref_to_mut.rs:18:9 | LL | (*(a as *const _ as *mut String)).push_str(" world"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | (*(a as *const _ as *mut String)).push_str(" world"); = note: `-D clippy::cast-ref-to-mut` implied by `-D warnings` error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell` - --> $DIR/cast_ref_to_mut.rs:23:9 + --> $DIR/cast_ref_to_mut.rs:19:9 | LL | *(a as *const _ as *mut _) = String::from("Replaced"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `&T` to `&mut T` may cause undefined behavior, consider instead using an `UnsafeCell` - --> $DIR/cast_ref_to_mut.rs:24:9 + --> $DIR/cast_ref_to_mut.rs:20:9 | LL | *(a as *const _ as *mut String) += " world"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 4bf58bd55d1681332f7b35fbc8680e0741353c4f Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 19 Nov 2020 11:22:59 +0100 Subject: [PATCH 095/118] Add CHANGELOG for 1.48 --- CHANGELOG.md | 112 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 816d25bcd93eb..a00554f33b53e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,11 +6,117 @@ document. ## Unreleased / In Rust Nightly -[e636b88...master](https://github.com/rust-lang/rust-clippy/compare/e636b88...master) +[b20d4c1...master](https://github.com/rust-lang/rust-clippy/compare/b20d4c1...master) + +## Rust 1.49 + +Current beta, release 2020-12-31 + +[e636b88...b20d4c1](https://github.com/rust-lang/rust-clippy/compare/e636b88...b20d4c1) + +### New Lints + +* [`field_reassign_with_default`] [#5911](https://github.com/rust-lang/rust-clippy/pull/5911) +* [`await_holding_refcell_ref`] [#6029](https://github.com/rust-lang/rust-clippy/pull/6029) +* [`disallowed_method`] [#6081](https://github.com/rust-lang/rust-clippy/pull/6081) +* [`inline_asm_x86_att_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092) +* [`inline_asm_x86_intel_syntax`] [#6092](https://github.com/rust-lang/rust-clippy/pull/6092) +* [`from_iter_instead_of_collect`] [#6101](https://github.com/rust-lang/rust-clippy/pull/6101) +* [`mut_mutex_lock`] [#6103](https://github.com/rust-lang/rust-clippy/pull/6103) +* [`single_element_loop`] [#6109](https://github.com/rust-lang/rust-clippy/pull/6109) +* [`manual_unwrap_or`] [#6123](https://github.com/rust-lang/rust-clippy/pull/6123) +* [`large_types_passed_by_value`] [#6135](https://github.com/rust-lang/rust-clippy/pull/6135) +* [`result_unit_err`] [#6157](https://github.com/rust-lang/rust-clippy/pull/6157) +* [`ref_option_ref`] [#6165](https://github.com/rust-lang/rust-clippy/pull/6165) +* [`manual_range_contains`] [#6177](https://github.com/rust-lang/rust-clippy/pull/6177) +* [`unusual_byte_groupings`] [#6183](https://github.com/rust-lang/rust-clippy/pull/6183) +* [`comparison_to_empty`] [#6226](https://github.com/rust-lang/rust-clippy/pull/6226) +* [`map_collect_result_unit`] [#6227](https://github.com/rust-lang/rust-clippy/pull/6227) +* [`manual_ok_or`] [#6233](https://github.com/rust-lang/rust-clippy/pull/6233) + +### Moves and Deprecations + +* Rename `single_char_push_str` to [`single_char_add_str`] + [#6037](https://github.com/rust-lang/rust-clippy/pull/6037) +* Rename `zero_width_space` to [`invisible_characters`] + [#6105](https://github.com/rust-lang/rust-clippy/pull/6105) +* Deprecate [`drop_bounds`] (uplifted) + [#6111](https://github.com/rust-lang/rust-clippy/pull/6111) +* Move [`string_lit_as_bytes`] to `nursery` + [#6117](https://github.com/rust-lang/rust-clippy/pull/6117) +* Move [`rc_buffer`] to `restriction` + [#6128](https://github.com/rust-lang/rust-clippy/pull/6128) + +### Enhancements + +* [`manual_memcpy`]: Also lint when there are loop counters (and produce a + reliable suggestion) + [#5727](https://github.com/rust-lang/rust-clippy/pull/5727) +* [`single_char_add_str`]: Also lint on `String::insert_str` + [#6037](https://github.com/rust-lang/rust-clippy/pull/6037) +* [`invisible_characters`]: Also lint the characters `\u{AD}` and `\u{2060}` + [#6105](https://github.com/rust-lang/rust-clippy/pull/6105) +* [`eq_op`]: Also lint on the `assert_*!` macro family + [#6167](https://github.com/rust-lang/rust-clippy/pull/6167) +* [`items_after_statements`]: Also lint in local macro expansions + [#6176](https://github.com/rust-lang/rust-clippy/pull/6176) +* [`unnecessary_cast`]: Also lint casts on integer and float literals + [#6187](https://github.com/rust-lang/rust-clippy/pull/6187) +* [`manual_unwrap_or`]: Also lint `Result::unwrap_or` + [#6190](https://github.com/rust-lang/rust-clippy/pull/6190) +* [`match_like_matches_macro`]: Also lint when `match` has more than two arms + [#6216](https://github.com/rust-lang/rust-clippy/pull/6216) +* [`integer_arithmetic`]: Better handle `/` an `%` operators + [#6229](https://github.com/rust-lang/rust-clippy/pull/6229) + +### False Positive Fixes + +* [`needless_lifetimes`]: Bail out if the function has a `where` clause with the + lifetime [#5978](https://github.com/rust-lang/rust-clippy/pull/5978) +* [`explicit_counter_loop`]: No longer lints, when loop counter is used after it + is incremented [#6076](https://github.com/rust-lang/rust-clippy/pull/6076) +* [`or_fun_call`]: Revert changes addressing the handling of `const fn` + [#6077](https://github.com/rust-lang/rust-clippy/pull/6077) +* [`needless_range_loop`]: No longer lints, when the iterable is used in the + range [#6102](https://github.com/rust-lang/rust-clippy/pull/6102) +* [`inconsistent_digit_grouping`]: Fix bug when using floating point exponent + [#6104](https://github.com/rust-lang/rust-clippy/pull/6104) +* [`mistyped_literal_suffixes`]: No longer lints on the fractional part of a + float (e.g. `713.32_64`) + [#6114](https://github.com/rust-lang/rust-clippy/pull/6114) +* [`invalid_regex`]: No longer lint on unicode characters within `bytes::Regex` + [#6132](https://github.com/rust-lang/rust-clippy/pull/6132) +* [`boxed_local`]: No longer lints on `extern fn` arguments + [#6133](https://github.com/rust-lang/rust-clippy/pull/6133) +* [`needless_lifetimes`]: Fix regression, where lifetime is used in `where` + clause [#6198](https://github.com/rust-lang/rust-clippy/pull/6198) + +### Suggestion Fixes/Improvements + +* [`unnecessary_sort_by`]: Avoid dereferencing the suggested closure parameter + [#6078](https://github.com/rust-lang/rust-clippy/pull/6078) +* [`needless_arbitrary_self_type`]: Correctly handle expanded code + [#6093](https://github.com/rust-lang/rust-clippy/pull/6093) +* [`useless_format`]: Preserve raw strings in suggestion + [#6151](https://github.com/rust-lang/rust-clippy/pull/6151) +* [`empty_loop`]: Suggest alternatives + [#6162](https://github.com/rust-lang/rust-clippy/pull/6162) +* [`borrowed_box`]: Correctly add parentheses in suggestion + [#6200](https://github.com/rust-lang/rust-clippy/pull/6200) +* [`unused_unit`]: Improve suggestion formatting + [#6247](https://github.com/rust-lang/rust-clippy/pull/6247) + +### Documentation Improvements + +* Some doc improvements: + * [`rc_buffer`] [#6090](https://github.com/rust-lang/rust-clippy/pull/6090) + * [`empty_loop`] [#6162](https://github.com/rust-lang/rust-clippy/pull/6162) +* [`doc_markdown`]: Document problematic link text style + [#6107](https://github.com/rust-lang/rust-clippy/pull/6107) ## Rust 1.48 -Current beta, release 2020-11-19 +Current stable, released 2020-11-19 [09bd400...e636b88](https://github.com/rust-lang/rust-clippy/compare/09bd400...e636b88) @@ -128,7 +234,7 @@ Current beta, release 2020-11-19 ## Rust 1.47 -Current stable, released 2020-10-08 +Released 2020-10-08 [c2c07fa...09bd400](https://github.com/rust-lang/rust-clippy/compare/c2c07fa...09bd400) From a98acdba3e1e1697bdde26584972893edcdc49d1 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 19 Nov 2020 11:23:28 +0100 Subject: [PATCH 096/118] Fix trailing whitespaces in CHANGELOG file --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a00554f33b53e..033d633438ed6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -162,7 +162,7 @@ Current stable, released 2020-11-19 * [`useless_attribute`]: permit allowing [`wildcard_imports`] and [`enum_glob_use`] [#5994](https://github.com/rust-lang/rust-clippy/pull/5994) -* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts +* [`transmute_ptr_to_ptr`]: avoid suggesting dereferencing raw pointers in const contexts [#5999](https://github.com/rust-lang/rust-clippy/pull/5999) * [`redundant_closure_call`]: take into account usages of the closure in nested functions and closures [#5920](https://github.com/rust-lang/rust-clippy/pull/5920) @@ -170,7 +170,7 @@ Current stable, released 2020-11-19 [#5949](https://github.com/rust-lang/rust-clippy/pull/5949) * [`doc_markdown`]: allow using "GraphQL" without backticks [#5996](https://github.com/rust-lang/rust-clippy/pull/5996) -* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` +* [`to_string_in_display`]: avoid linting when calling `to_string()` on anything that is not `self` [#5971](https://github.com/rust-lang/rust-clippy/pull/5971) * [`indexing_slicing`] and [`out_of_bounds_indexing`] treat references to arrays as arrays [#6034](https://github.com/rust-lang/rust-clippy/pull/6034) @@ -191,19 +191,19 @@ Current stable, released 2020-11-19 [#5946](https://github.com/rust-lang/rust-clippy/pull/5946) * [`useless_conversion`]: show the type in the error message [#6035](https://github.com/rust-lang/rust-clippy/pull/6035) -* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message +* [`unnecessary_mut_passed`]: discriminate between functions and methods in the error message [#5892](https://github.com/rust-lang/rust-clippy/pull/5892) * [`float_cmp`] and [`float_cmp_const`]: change wording to make margin of error less ambiguous [#6043](https://github.com/rust-lang/rust-clippy/pull/6043) * [`default_trait_access`]: do not use unnecessary type parameters in the suggestion [#5993](https://github.com/rust-lang/rust-clippy/pull/5993) -* [`collapsible_if`]: don't use expanded code in the suggestion +* [`collapsible_if`]: don't use expanded code in the suggestion [#5992](https://github.com/rust-lang/rust-clippy/pull/5992) * Do not suggest empty format strings in [`print_with_newline`] and [`write_with_newline`] [#6042](https://github.com/rust-lang/rust-clippy/pull/6042) * [`unit_arg`]: improve the readability of the suggestion [#5931](https://github.com/rust-lang/rust-clippy/pull/5931) -* [`stable_sort_primitive`]: print the type that is being sorted in the lint message +* [`stable_sort_primitive`]: print the type that is being sorted in the lint message [#5935](https://github.com/rust-lang/rust-clippy/pull/5935) * Show line count and max lines in [`too_many_lines`] lint message [#6009](https://github.com/rust-lang/rust-clippy/pull/6009) @@ -211,7 +211,7 @@ Current stable, released 2020-11-19 [#5900](https://github.com/rust-lang/rust-clippy/pull/5900) * [`option_map_unit_fn`] and [`result_map_unit_fn`]: print the unit type `()` explicitly [#6024](https://github.com/rust-lang/rust-clippy/pull/6024) -* [`redundant_allocation`]: suggest replacing `Rc>` with `Rc` +* [`redundant_allocation`]: suggest replacing `Rc>` with `Rc` [#5899](https://github.com/rust-lang/rust-clippy/pull/5899) * Make lint messages adhere to rustc dev guide conventions [#5893](https://github.com/rust-lang/rust-clippy/pull/5893) From e9afdf074090d24f18ecc9d7bb3b20861615794a Mon Sep 17 00:00:00 2001 From: flip1995 Date: Thu, 19 Nov 2020 11:23:59 +0100 Subject: [PATCH 097/118] Improve changlog update documentation --- doc/changelog_update.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/doc/changelog_update.md b/doc/changelog_update.md index 4972646495730..115848c48044c 100644 --- a/doc/changelog_update.md +++ b/doc/changelog_update.md @@ -29,8 +29,11 @@ bullet points might be helpful: * When writing the release notes for the **upcoming beta release**, you need to check out the Clippy commit of the current Rust `master`. [Link][rust_master_tools] * When writing the (forgotten) release notes for a **past stable release**, you - need to select the Rust release tag from the dropdown and then check the - commit of the Clippy directory: + need to check out the Rust release tag of the stable release. + [Link][rust_stable_tools] + +Usually you want to wirte the changelog of the **upcoming stable release**. Make +sure though, that `beta` was already branched in the Rust repository. To find the commit hash, issue the following command when in a `rust-lang/rust` checkout: ``` @@ -71,6 +74,19 @@ The order should roughly be: 7. Documentation improvements 8. Others +As section headers, we use: + +``` +### New Lints +### Moves and Deprecations +### Enhancements +### False Positive Fixes +### Suggestion Fixes/Improvements +### ICE Fixes +### Documentation Improvements +### Others +``` + Please also be sure to update the Beta/Unreleased sections at the top with the relevant commit ranges. @@ -78,3 +94,4 @@ relevant commit ranges. [forge]: https://forge.rust-lang.org/ [rust_master_tools]: https://github.com/rust-lang/rust/tree/master/src/tools/clippy [rust_beta_tools]: https://github.com/rust-lang/rust/tree/beta/src/tools/clippy +[rust_stable_tools]: https://github.com/rust-lang/rust/releases From 78faaef8de0ac1dcd11353ad0cad1c0f0a6d2a58 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 19 Nov 2020 18:13:32 +0100 Subject: [PATCH 098/118] Remove the clippy::panic-params lint. Rustc itself now warns for all cases that triggered this lint. --- clippy_lints/src/lib.rs | 3 -- clippy_lints/src/panic_unimplemented.rs | 46 ++----------------- tests/ui/panic.rs | 61 ------------------------- tests/ui/panic.stderr | 28 ------------ 4 files changed, 4 insertions(+), 134 deletions(-) delete mode 100644 tests/ui/panic.rs delete mode 100644 tests/ui/panic.stderr diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 126852df502eb..19bf67d80c428 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -788,7 +788,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL, &panic_in_result_fn::PANIC_IN_RESULT_FN, &panic_unimplemented::PANIC, - &panic_unimplemented::PANIC_PARAMS, &panic_unimplemented::TODO, &panic_unimplemented::UNIMPLEMENTED, &panic_unimplemented::UNREACHABLE, @@ -1499,7 +1498,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS), LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(&overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), - LintId::of(&panic_unimplemented::PANIC_PARAMS), LintId::of(&partialeq_ne_impl::PARTIALEQ_NE_IMPL), LintId::of(&precedence::PRECEDENCE), LintId::of(&ptr::CMP_NULL), @@ -1666,7 +1664,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&non_copy_const::DECLARE_INTERIOR_MUTABLE_CONST), LintId::of(&non_expressive_names::JUST_UNDERSCORES_AND_DIGITS), LintId::of(&non_expressive_names::MANY_SINGLE_CHAR_NAMES), - LintId::of(&panic_unimplemented::PANIC_PARAMS), LintId::of(&ptr::CMP_NULL), LintId::of(&ptr::PTR_ARG), LintId::of(&ptr_eq::PTR_EQ), diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 3d888fe732573..8b10d07164712 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -1,30 +1,10 @@ -use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, span_lint}; +use crate::utils::{is_expn_of, match_panic_call, span_lint}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::Expr; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; -declare_clippy_lint! { - /// **What it does:** Checks for missing parameters in `panic!`. - /// - /// **Why is this bad?** Contrary to the `format!` family of macros, there are - /// two forms of `panic!`: if there are no parameters given, the first argument - /// is not a format string and used literally. So while `format!("{}")` will - /// fail to compile, `panic!("{}")` will not. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```no_run - /// panic!("This `panic!` is probably missing a parameter there: {}"); - /// ``` - pub PANIC_PARAMS, - style, - "missing parameters in `panic!` calls" -} - declare_clippy_lint! { /// **What it does:** Checks for usage of `panic!`. /// @@ -89,11 +69,11 @@ declare_clippy_lint! { "`unreachable!` should not be present in production code" } -declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); +declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]); impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(params) = match_panic_call(cx, expr) { + if let Some(_) = match_panic_call(cx, expr) { let span = get_outer_span(expr); if is_expn_of(expr.span, "unimplemented").is_some() { span_lint( @@ -113,7 +93,6 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { ); } else if is_expn_of(expr.span, "panic").is_some() { span_lint(cx, PANIC, span, "`panic` should not be present in production code"); - match_panic(params, expr, cx); } } } @@ -132,20 +111,3 @@ fn get_outer_span(expr: &Expr<'_>) -> Span { } } } - -fn match_panic(params: &[Expr<'_>], expr: &Expr<'_>, cx: &LateContext<'_>) { - if_chain! { - if let ExprKind::Lit(ref lit) = params[0].kind; - if is_direct_expn_of(expr.span, "panic").is_some(); - if let LitKind::Str(ref string, _) = lit.node; - let string = string.as_str().replace("{{", "").replace("}}", ""); - if let Some(par) = string.find('{'); - if string[par..].contains('}'); - if params[0].span.source_callee().is_none(); - if params[0].span.lo() != params[0].span.hi(); - then { - span_lint(cx, PANIC_PARAMS, params[0].span, - "you probably are missing some parameter in your format string"); - } - } -} diff --git a/tests/ui/panic.rs b/tests/ui/panic.rs deleted file mode 100644 index 6e004aa9a924f..0000000000000 --- a/tests/ui/panic.rs +++ /dev/null @@ -1,61 +0,0 @@ -#![warn(clippy::panic_params)] -#![allow(clippy::assertions_on_constants)] -fn missing() { - if true { - panic!("{}"); - } else if false { - panic!("{:?}"); - } else { - assert!(true, "here be missing values: {}"); - } - - panic!("{{{this}}}"); -} - -fn ok_single() { - panic!("foo bar"); -} - -fn ok_inner() { - // Test for #768 - assert!("foo bar".contains(&format!("foo {}", "bar"))); -} - -fn ok_multiple() { - panic!("{}", "This is {ok}"); -} - -fn ok_bracket() { - match 42 { - 1337 => panic!("{so is this"), - 666 => panic!("so is this}"), - _ => panic!("}so is that{"), - } -} - -const ONE: u32 = 1; - -fn ok_nomsg() { - assert!({ 1 == ONE }); - assert!(if 1 == ONE { ONE == 1 } else { false }); -} - -fn ok_escaped() { - panic!("{{ why should this not be ok? }}"); - panic!(" or {{ that ?"); - panic!(" or }} this ?"); - panic!(" {or {{ that ?"); - panic!(" }or }} this ?"); - panic!("{{ test }"); - panic!("{case }}"); -} - -fn main() { - missing(); - ok_single(); - ok_multiple(); - ok_bracket(); - ok_inner(); - ok_nomsg(); - ok_escaped(); -} diff --git a/tests/ui/panic.stderr b/tests/ui/panic.stderr deleted file mode 100644 index 1f8ff8ccf5575..0000000000000 --- a/tests/ui/panic.stderr +++ /dev/null @@ -1,28 +0,0 @@ -error: you probably are missing some parameter in your format string - --> $DIR/panic.rs:5:16 - | -LL | panic!("{}"); - | ^^^^ - | - = note: `-D clippy::panic-params` implied by `-D warnings` - -error: you probably are missing some parameter in your format string - --> $DIR/panic.rs:7:16 - | -LL | panic!("{:?}"); - | ^^^^^^ - -error: you probably are missing some parameter in your format string - --> $DIR/panic.rs:9:23 - | -LL | assert!(true, "here be missing values: {}"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: you probably are missing some parameter in your format string - --> $DIR/panic.rs:12:12 - | -LL | panic!("{{{this}}}"); - | ^^^^^^^^^^^^ - -error: aborting due to 4 previous errors - From 113c1476c923492ea1427b061458a6ab8faf8df8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 19 Nov 2020 19:47:25 +0100 Subject: [PATCH 099/118] Clippy: Match on assert!() expansions without an inner block. --- clippy_lints/src/assertions_on_constants.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index a2ccb0369c4a4..a52f0997d439d 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -129,8 +129,11 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) if let ExprKind::Block(ref block, _) = arms[0].body.kind; if block.stmts.is_empty(); if let Some(block_expr) = &block.expr; - if let ExprKind::Block(ref inner_block, _) = block_expr.kind; - if let Some(begin_panic_call) = &inner_block.expr; + // inner block is optional. unwarp it if it exists, or use the expression as is otherwise. + if let Some(begin_panic_call) = match block_expr.kind { + ExprKind::Block(ref inner_block, _) => &inner_block.expr, + _ => &block.expr, + }; // function call if let Some(args) = match_panic_call(cx, begin_panic_call); if args.len() == 1; From dd4e471b3fb701312c2a3fabfba0011f239d4760 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 20 Nov 2020 09:37:47 +0100 Subject: [PATCH 100/118] Properly deprecate panic_params lint --- clippy_lints/src/deprecated_lints.rs | 5 +++++ clippy_lints/src/lib.rs | 4 ++++ src/lintlist/mod.rs | 7 ------- tests/ui/deprecated.rs | 1 + tests/ui/deprecated.stderr | 8 +++++++- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs index 461c6e31d3eb4..1c3285ed701db 100644 --- a/clippy_lints/src/deprecated_lints.rs +++ b/clippy_lints/src/deprecated_lints.rs @@ -181,3 +181,8 @@ declare_deprecated_lint! { pub TEMPORARY_CSTRING_AS_PTR, "this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`" } + +declare_deprecated_lint! { + pub PANIC_PARAMS, + "this lint has been uplifted to rustc and is now called `panic_fmt`" +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 19bf67d80c428..ff5d484699556 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -495,6 +495,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::temporary_cstring_as_ptr", "this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr`", ); + store.register_removed( + "clippy::panic_params", + "this lint has been uplifted to rustc and is now called `panic_fmt`", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 702f9d86de62d..213e5758659c6 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -1831,13 +1831,6 @@ vec![ deprecation: None, module: "panic_in_result_fn", }, - Lint { - name: "panic_params", - group: "style", - desc: "missing parameters in `panic!` calls", - deprecation: None, - module: "panic_unimplemented", - }, Lint { name: "panicking_unwrap", group: "correctness", diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs index 56755596c97fc..4cbc5630d759d 100644 --- a/tests/ui/deprecated.rs +++ b/tests/ui/deprecated.rs @@ -10,5 +10,6 @@ #[warn(clippy::regex_macro)] #[warn(clippy::drop_bounds)] #[warn(clippy::temporary_cstring_as_ptr)] +#[warn(clippy::panic_params)] fn main() {} diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr index 37b726fc00f1c..a348d01d734fe 100644 --- a/tests/ui/deprecated.stderr +++ b/tests/ui/deprecated.stderr @@ -72,11 +72,17 @@ error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has LL | #[warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error: lint `clippy::panic_params` has been removed: `this lint has been uplifted to rustc and is now called `panic_fmt`` + --> $DIR/deprecated.rs:13:8 + | +LL | #[warn(clippy::panic_params)] + | ^^^^^^^^^^^^^^^^^^^^ + error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon` --> $DIR/deprecated.rs:1:8 | LL | #[warn(clippy::str_to_string)] | ^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: aborting due to 14 previous errors From 5ee0a400fc5104a0fb9be5c85c48d79cf1af8dce Mon Sep 17 00:00:00 2001 From: flip1995 Date: Fri, 20 Nov 2020 10:06:26 +0100 Subject: [PATCH 101/118] Fix dogfood errors --- clippy_lints/src/panic_unimplemented.rs | 2 +- clippy_lints/src/utils/ast_utils.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/panic_unimplemented.rs b/clippy_lints/src/panic_unimplemented.rs index 8b10d07164712..31b03ecd101c0 100644 --- a/clippy_lints/src/panic_unimplemented.rs +++ b/clippy_lints/src/panic_unimplemented.rs @@ -73,7 +73,7 @@ declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANI impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some(_) = match_panic_call(cx, expr) { + if match_panic_call(cx, expr).is_some() { let span = get_outer_span(expr); if is_expn_of(expr.span, "unimplemented").is_some() { span_lint( diff --git a/clippy_lints/src/utils/ast_utils.rs b/clippy_lints/src/utils/ast_utils.rs index 9050b9b2d9ab8..fcf7a4b1367e3 100644 --- a/clippy_lints/src/utils/ast_utils.rs +++ b/clippy_lints/src/utils/ast_utils.rs @@ -110,8 +110,7 @@ pub fn eq_expr_opt(l: &Option>, r: &Option>) -> bool { pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool { match (l, r) { (StructRest::Base(lb), StructRest::Base(rb)) => eq_expr(lb, rb), - (StructRest::Rest(_), StructRest::Rest(_)) => true, - (StructRest::None, StructRest::None) => true, + (StructRest::Rest(_), StructRest::Rest(_)) | (StructRest::None, StructRest::None) => true, _ => false, } } From 8b21241fd57376ab35e8ae75b3f57b7c601cdcdb Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 20 Nov 2020 11:35:15 -0500 Subject: [PATCH 102/118] Revert "Convert the await holding lints to correctness" This reverts commit d8c6bce4407b1c99ed961f75a093ffe767818069. --- clippy_lints/src/await_holding_invalid.rs | 4 ++-- clippy_lints/src/lib.rs | 6 ++---- src/lintlist/mod.rs | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/clippy_lints/src/await_holding_invalid.rs b/clippy_lints/src/await_holding_invalid.rs index ca819663fded8..58892024ce243 100644 --- a/clippy_lints/src/await_holding_invalid.rs +++ b/clippy_lints/src/await_holding_invalid.rs @@ -45,7 +45,7 @@ declare_clippy_lint! { /// } /// ``` pub AWAIT_HOLDING_LOCK, - correctness, + pedantic, "Inside an async function, holding a MutexGuard while calling await" } @@ -84,7 +84,7 @@ declare_clippy_lint! { /// } /// ``` pub AWAIT_HOLDING_REFCELL_REF, - correctness, + pedantic, "Inside an async function, holding a RefCell ref while calling await" } diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 36016988b6b0d..7e8cbd00c22a1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -1224,6 +1224,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(&attrs::INLINE_ALWAYS), + LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), + LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::VERBOSE_BIT_MASK), LintId::of(&checked_conversions::CHECKED_CONVERSIONS), LintId::of(&copies::SAME_FUNCTIONS_IN_IF_CONDITION), @@ -1327,8 +1329,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&attrs::MISMATCHED_TARGET_OS), LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS), LintId::of(&attrs::USELESS_ATTRIBUTE), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(&blacklisted_name::BLACKLISTED_NAME), @@ -1793,8 +1793,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(&attrs::DEPRECATED_SEMVER), LintId::of(&attrs::MISMATCHED_TARGET_OS), LintId::of(&attrs::USELESS_ATTRIBUTE), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_LOCK), - LintId::of(&await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), LintId::of(&bit_mask::BAD_BIT_MASK), LintId::of(&bit_mask::INEFFECTIVE_BIT_MASK), LintId::of(&booleans::LOGIC_BUG), diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index c5a31fac254d4..79b24b83680e2 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -62,14 +62,14 @@ vec![ }, Lint { name: "await_holding_lock", - group: "correctness", + group: "pedantic", desc: "Inside an async function, holding a MutexGuard while calling await", deprecation: None, module: "await_holding_invalid", }, Lint { name: "await_holding_refcell_ref", - group: "correctness", + group: "pedantic", desc: "Inside an async function, holding a RefCell ref while calling await", deprecation: None, module: "await_holding_invalid", From 9b910e19ce9bcd27c6dad220aba38121dc85138e Mon Sep 17 00:00:00 2001 From: oliver <16816606+o752d@users.noreply.github.com> Date: Sun, 22 Nov 2020 04:44:47 +0000 Subject: [PATCH 103/118] a typo typo --- clippy_lints/src/assertions_on_constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index a52f0997d439d..62c73dbac48b4 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -129,7 +129,7 @@ fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) if let ExprKind::Block(ref block, _) = arms[0].body.kind; if block.stmts.is_empty(); if let Some(block_expr) = &block.expr; - // inner block is optional. unwarp it if it exists, or use the expression as is otherwise. + // inner block is optional. unwrap it if it exists, or use the expression as is otherwise. if let Some(begin_panic_call) = match block_expr.kind { ExprKind::Block(ref inner_block, _) => &inner_block.expr, _ => &block.expr, From e30bb7661d5cb547c59deb7ff700d53ddc219a11 Mon Sep 17 00:00:00 2001 From: oliver Date: Sun, 22 Nov 2020 00:50:09 -0400 Subject: [PATCH 104/118] update --- tests/ui/manual_ok_or.fixed | 2 +- tests/ui/manual_ok_or.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/manual_ok_or.fixed b/tests/ui/manual_ok_or.fixed index b42e94bd727de..887a97d7a0173 100644 --- a/tests/ui/manual_ok_or.fixed +++ b/tests/ui/manual_ok_or.fixed @@ -28,7 +28,7 @@ fn main() { // not applicable, or side isn't `Result::Err` foo.map_or(Ok::(1), |v| Ok(v)); - // not applicatble, expr is not a `Result` value + // not applicable, expr is not a `Result` value foo.map_or(42, |v| v); // TODO patterns not covered yet diff --git a/tests/ui/manual_ok_or.rs b/tests/ui/manual_ok_or.rs index e5a6056fbf5cc..3c99872f5022a 100644 --- a/tests/ui/manual_ok_or.rs +++ b/tests/ui/manual_ok_or.rs @@ -32,7 +32,7 @@ fn main() { // not applicable, or side isn't `Result::Err` foo.map_or(Ok::(1), |v| Ok(v)); - // not applicatble, expr is not a `Result` value + // not applicable, expr is not a `Result` value foo.map_or(42, |v| v); // TODO patterns not covered yet From 6667c6637d6d91e76e4b2879c412e63c6eceb4b3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 22 Nov 2020 14:20:16 +0300 Subject: [PATCH 105/118] Add test for an unmotivated "cannot determine resolution" error --- src/test/ui/resolve/macro-determinacy-non-module.rs | 5 +++++ .../ui/resolve/macro-determinacy-non-module.stderr | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/test/ui/resolve/macro-determinacy-non-module.rs create mode 100644 src/test/ui/resolve/macro-determinacy-non-module.stderr diff --git a/src/test/ui/resolve/macro-determinacy-non-module.rs b/src/test/ui/resolve/macro-determinacy-non-module.rs new file mode 100644 index 0000000000000..7bc4c6643040b --- /dev/null +++ b/src/test/ui/resolve/macro-determinacy-non-module.rs @@ -0,0 +1,5 @@ +use std as line; + +const C: u32 = line!(); //~ ERROR cannot determine resolution for the macro `line` + +fn main() {} diff --git a/src/test/ui/resolve/macro-determinacy-non-module.stderr b/src/test/ui/resolve/macro-determinacy-non-module.stderr new file mode 100644 index 0000000000000..bc19de8d04c1f --- /dev/null +++ b/src/test/ui/resolve/macro-determinacy-non-module.stderr @@ -0,0 +1,10 @@ +error: cannot determine resolution for the macro `line` + --> $DIR/macro-determinacy-non-module.rs:3:16 + | +LL | const C: u32 = line!(); + | ^^^^ + | + = note: import resolution is stuck, try simplifying macro imports + +error: aborting due to previous error + From 27af650a0df2975fba5a8ae3e1a42eada0ff7bd4 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 21 Nov 2020 18:02:37 +0300 Subject: [PATCH 106/118] resolve: Do not put macros into `module.unexpanded_invocations` unless necessary --- .../rustc_resolve/src/build_reduced_graph.rs | 29 ++-- .../cfg-generic-params.stderr | 24 ++-- .../feature-gate-custom_attribute2.stderr | 128 +++++++++--------- src/test/ui/issues/issue-40845.stderr | 12 +- .../ui/parser/default-unmatched-assoc.stderr | 4 +- ...sue-65122-mac-invoc-in-mut-patterns.stderr | 8 +- .../resolve/macro-determinacy-non-module.rs | 4 +- .../macro-determinacy-non-module.stderr | 10 -- 8 files changed, 111 insertions(+), 108 deletions(-) delete mode 100644 src/test/ui/resolve/macro-determinacy-non-module.stderr diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 493b9f15271ef..6d7e4ebc253bd 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1155,14 +1155,18 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { false } - fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> { + fn visit_invoc(&mut self, id: NodeId) -> ExpnId { let invoc_id = id.placeholder_to_expn_id(); - - self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); - let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope); assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation"); + invoc_id + } + /// Visit invocation in context in which it can emit a named item (possibly `macro_rules`) + /// directly into its parent scope's module. + fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> { + let invoc_id = self.visit_invoc(id); + self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id); self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id)) } @@ -1291,7 +1295,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { return; } ItemKind::MacCall(..) => { - self.parent_scope.macro_rules = self.visit_invoc(item.id); + self.parent_scope.macro_rules = self.visit_invoc_in_module(item.id); return; } ItemKind::Mod(..) => self.contains_macro_use(&item.attrs), @@ -1309,7 +1313,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_stmt(&mut self, stmt: &'b ast::Stmt) { if let ast::StmtKind::MacCall(..) = stmt.kind { - self.parent_scope.macro_rules = self.visit_invoc(stmt.id); + self.parent_scope.macro_rules = self.visit_invoc_in_module(stmt.id); } else { visit::walk_stmt(self, stmt); } @@ -1317,7 +1321,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_foreign_item(&mut self, foreign_item: &'b ForeignItem) { if let ForeignItemKind::MacCall(_) = foreign_item.kind { - self.visit_invoc(foreign_item.id); + self.visit_invoc_in_module(foreign_item.id); return; } @@ -1336,7 +1340,14 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { fn visit_assoc_item(&mut self, item: &'b AssocItem, ctxt: AssocCtxt) { if let AssocItemKind::MacCall(_) = item.kind { - self.visit_invoc(item.id); + match ctxt { + AssocCtxt::Trait => { + self.visit_invoc_in_module(item.id); + } + AssocCtxt::Impl => { + self.visit_invoc(item.id); + } + } return; } @@ -1460,7 +1471,7 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { // type and value namespaces. fn visit_variant(&mut self, variant: &'b ast::Variant) { if variant.is_placeholder { - self.visit_invoc(variant.id); + self.visit_invoc_in_module(variant.id); return; } diff --git a/src/test/ui/conditional-compilation/cfg-generic-params.stderr b/src/test/ui/conditional-compilation/cfg-generic-params.stderr index d9e29c8262c63..4d6560e96e513 100644 --- a/src/test/ui/conditional-compilation/cfg-generic-params.stderr +++ b/src/test/ui/conditional-compilation/cfg-generic-params.stderr @@ -17,16 +17,16 @@ LL | struct WhereBad where for<#[cfg(no)] 'a, #[cfg(yes)] T> u8: Copy; | ^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:34:43 + --> $DIR/cfg-generic-params.rs:19:29 | -LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; - | ^^^^^^^ +LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} + | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:30:40 + --> $DIR/cfg-generic-params.rs:22:29 | -LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; - | ^^^^^^^ +LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} + | ^^^^^^^ error: cannot find attribute `unknown` in this scope --> $DIR/cfg-generic-params.rs:26:34 @@ -35,16 +35,16 @@ LL | type FnYes = for<#[cfg_attr(yes, unknown)] 'a> fn(); | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:22:29 + --> $DIR/cfg-generic-params.rs:30:40 | -LL | fn f_ty_yes<#[cfg_attr(yes, unknown)] T>() {} - | ^^^^^^^ +LL | type PolyYes = dyn for<#[cfg_attr(yes, unknown)] 'a> Copy; + | ^^^^^^^ error: cannot find attribute `unknown` in this scope - --> $DIR/cfg-generic-params.rs:19:29 + --> $DIR/cfg-generic-params.rs:34:43 | -LL | fn f_lt_yes<#[cfg_attr(yes, unknown)] 'a>() {} - | ^^^^^^^ +LL | struct WhereYes where for<#[cfg_attr(yes, unknown)] 'a> u8: Copy; + | ^^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr index b33710ce04958..f2287111719bc 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_attribute2.stderr @@ -1,50 +1,50 @@ -error: cannot find attribute `lt_hof` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:51:21 +error: cannot find attribute `lt_struct` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:4:15 | -LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 - | ^^^^^^ +LL | struct StLt<#[lt_struct] 'a>(&'a u32); + | ^^^^^^^^^ -error: cannot find attribute `ty_meth` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:46:15 +error: cannot find attribute `ty_struct` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:6:15 | -LL | fn m_ty<#[ty_meth] P>(_: P) { } - | ^^^^^^^ +LL | struct StTy<#[ty_struct] I>(I); + | ^^^^^^^^^ -error: cannot find attribute `lt_meth` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:44:15 +error: cannot find attribute `lt_enum` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:9:13 | -LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } - | ^^^^^^^ +LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } + | ^^^^^^^ -error: cannot find attribute `ty_fn` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:40:11 +error: cannot find attribute `ty_enum` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:11:13 | -LL | fn f_ty<#[ty_fn] O>(_: O) { } - | ^^^^^ +LL | enum EnTy<#[ty_enum] J> { A(J), B } + | ^^^^^^^ -error: cannot find attribute `lt_fn` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:38:11 +error: cannot find attribute `lt_trait` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:14:14 | -LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } - | ^^^^^ +LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } + | ^^^^^^^^ -error: cannot find attribute `ty_impl_for` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:33:8 +error: cannot find attribute `ty_trait` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:16:14 | -LL | impl<#[ty_impl_for] N> TrTy for StTy { - | ^^^^^^^^^^^ +LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } + | ^^^^^^^^ -error: cannot find attribute `lt_impl_for` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:29:8 +error: cannot find attribute `lt_type` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:19:13 | -LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { - | ^^^^^^^^^^^ +LL | type TyLt<#[lt_type] 'd> = &'d u32; + | ^^^^^^^ -error: cannot find attribute `ty_inherent` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:26:8 +error: cannot find attribute `ty_type` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:21:13 | -LL | impl<#[ty_inherent] M> StTy { } - | ^^^^^^^^^^^ +LL | type TyTy<#[ty_type] L> = (L, ); + | ^^^^^^^ error: cannot find attribute `lt_inherent` in this scope --> $DIR/feature-gate-custom_attribute2.rs:24:8 @@ -52,53 +52,53 @@ error: cannot find attribute `lt_inherent` in this scope LL | impl<#[lt_inherent] 'e> StLt<'e> { } | ^^^^^^^^^^^ -error: cannot find attribute `ty_type` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:21:13 +error: cannot find attribute `ty_inherent` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:26:8 | -LL | type TyTy<#[ty_type] L> = (L, ); - | ^^^^^^^ +LL | impl<#[ty_inherent] M> StTy { } + | ^^^^^^^^^^^ -error: cannot find attribute `lt_type` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:19:13 +error: cannot find attribute `lt_impl_for` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:29:8 | -LL | type TyLt<#[lt_type] 'd> = &'d u32; - | ^^^^^^^ +LL | impl<#[lt_impl_for] 'f> TrLt<'f> for StLt<'f> { + | ^^^^^^^^^^^ -error: cannot find attribute `ty_trait` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:16:14 +error: cannot find attribute `ty_impl_for` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:33:8 | -LL | trait TrTy<#[ty_trait] K> { fn foo(&self, _: K); } - | ^^^^^^^^ +LL | impl<#[ty_impl_for] N> TrTy for StTy { + | ^^^^^^^^^^^ -error: cannot find attribute `lt_trait` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:14:14 +error: cannot find attribute `lt_fn` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:38:11 | -LL | trait TrLt<#[lt_trait] 'c> { fn foo(&self, _: &'c [u32]) -> &'c u32; } - | ^^^^^^^^ +LL | fn f_lt<#[lt_fn] 'g>(_: &'g [u32]) -> &'g u32 { loop { } } + | ^^^^^ -error: cannot find attribute `ty_enum` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:11:13 +error: cannot find attribute `ty_fn` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:40:11 | -LL | enum EnTy<#[ty_enum] J> { A(J), B } - | ^^^^^^^ +LL | fn f_ty<#[ty_fn] O>(_: O) { } + | ^^^^^ -error: cannot find attribute `lt_enum` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:9:13 +error: cannot find attribute `lt_meth` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:44:15 | -LL | enum EnLt<#[lt_enum] 'b> { A(&'b u32), B } - | ^^^^^^^ +LL | fn m_lt<#[lt_meth] 'h>(_: &'h [u32]) -> &'h u32 { loop { } } + | ^^^^^^^ -error: cannot find attribute `ty_struct` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:6:15 +error: cannot find attribute `ty_meth` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:46:15 | -LL | struct StTy<#[ty_struct] I>(I); - | ^^^^^^^^^ +LL | fn m_ty<#[ty_meth] P>(_: P) { } + | ^^^^^^^ -error: cannot find attribute `lt_struct` in this scope - --> $DIR/feature-gate-custom_attribute2.rs:4:15 +error: cannot find attribute `lt_hof` in this scope + --> $DIR/feature-gate-custom_attribute2.rs:51:21 | -LL | struct StLt<#[lt_struct] 'a>(&'a u32); - | ^^^^^^^^^ +LL | where Q: for <#[lt_hof] 'i> Fn(&'i [u32]) -> &'i u32 + | ^^^^^^ error: aborting due to 17 previous errors diff --git a/src/test/ui/issues/issue-40845.stderr b/src/test/ui/issues/issue-40845.stderr index 2744330a4e58e..66bf053204c08 100644 --- a/src/test/ui/issues/issue-40845.stderr +++ b/src/test/ui/issues/issue-40845.stderr @@ -1,14 +1,14 @@ -error: cannot find macro `m` in this scope - --> $DIR/issue-40845.rs:4:10 - | -LL | impl S { m!(); } - | ^ - error: cannot find macro `m` in this scope --> $DIR/issue-40845.rs:1:11 | LL | trait T { m!(); } | ^ +error: cannot find macro `m` in this scope + --> $DIR/issue-40845.rs:4:10 + | +LL | impl S { m!(); } + | ^ + error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/default-unmatched-assoc.stderr b/src/test/ui/parser/default-unmatched-assoc.stderr index c8d1769cb5a2a..ee35fded99ec9 100644 --- a/src/test/ui/parser/default-unmatched-assoc.stderr +++ b/src/test/ui/parser/default-unmatched-assoc.stderr @@ -39,13 +39,13 @@ LL | } | - item list ends here error: cannot find macro `default` in this scope - --> $DIR/default-unmatched-assoc.rs:12:5 + --> $DIR/default-unmatched-assoc.rs:4:5 | LL | default!(); | ^^^^^^^ error: cannot find macro `default` in this scope - --> $DIR/default-unmatched-assoc.rs:4:5 + --> $DIR/default-unmatched-assoc.rs:12:5 | LL | default!(); | ^^^^^^^ diff --git a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr index 40599d228b27a..16a08b9b85607 100644 --- a/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr +++ b/src/test/ui/parser/issue-65122-mac-invoc-in-mut-patterns.stderr @@ -34,15 +34,15 @@ LL | mac2! { does_not_exist!() } = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find macro `does_not_exist` in this scope - --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13 + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 | -LL | mac1! { does_not_exist!() } +LL | mac2! { does_not_exist!() } | ^^^^^^^^^^^^^^ error: cannot find macro `does_not_exist` in this scope - --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:22:13 + --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:20:13 | -LL | mac2! { does_not_exist!() } +LL | mac1! { does_not_exist!() } | ^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/resolve/macro-determinacy-non-module.rs b/src/test/ui/resolve/macro-determinacy-non-module.rs index 7bc4c6643040b..3215e0cd34605 100644 --- a/src/test/ui/resolve/macro-determinacy-non-module.rs +++ b/src/test/ui/resolve/macro-determinacy-non-module.rs @@ -1,5 +1,7 @@ +// check-pass + use std as line; -const C: u32 = line!(); //~ ERROR cannot determine resolution for the macro `line` +const C: u32 = line!(); fn main() {} diff --git a/src/test/ui/resolve/macro-determinacy-non-module.stderr b/src/test/ui/resolve/macro-determinacy-non-module.stderr deleted file mode 100644 index bc19de8d04c1f..0000000000000 --- a/src/test/ui/resolve/macro-determinacy-non-module.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: cannot determine resolution for the macro `line` - --> $DIR/macro-determinacy-non-module.rs:3:16 - | -LL | const C: u32 = line!(); - | ^^^^ - | - = note: import resolution is stuck, try simplifying macro imports - -error: aborting due to previous error - From 034244f1081ee65ce9a258e99cf39baa5d692bca Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" Date: Sat, 21 Nov 2020 15:00:03 -0500 Subject: [PATCH 107/118] Small grammar, punctuation, and code style improvements to docs --- clippy_lints/src/len_zero.rs | 2 +- clippy_lints/src/methods/mod.rs | 2 +- clippy_lints/src/regex.rs | 4 ++-- clippy_lints/src/unit_return_expecting_ord.rs | 2 +- clippy_lints/src/useless_conversion.rs | 6 +++--- src/lintlist/mod.rs | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs index 8e2f03d6e4e91..8842901d90b83 100644 --- a/clippy_lints/src/len_zero.rs +++ b/clippy_lints/src/len_zero.rs @@ -69,7 +69,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for comparing to an empty slice such as "" or [],` + /// **What it does:** Checks for comparing to an empty slice such as `""` or `[]`, /// and suggests using `.is_empty()` where applicable. /// /// **Why is this bad?** Some structures can answer `.is_empty()` much faster diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index ff0a35324652a..fa1744043657a 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -1351,7 +1351,7 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Checks for usage of `_.map(_).collect::()`. + /// **What it does:** Checks for usage of `_.map(_).collect::()`. /// /// **Why is this bad?** Using `try_for_each` instead is more readable and idiomatic. /// diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs index 95594e38c9ec1..d06ab14348237 100644 --- a/clippy_lints/src/regex.rs +++ b/clippy_lints/src/regex.rs @@ -11,7 +11,7 @@ use std::convert::TryFrom; declare_clippy_lint! { /// **What it does:** Checks [regex](https://crates.io/crates/regex) creation - /// (with `Regex::new`,`RegexBuilder::new` or `RegexSet::new`) for correct + /// (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`) for correct /// regex syntax. /// /// **Why is this bad?** This will lead to a runtime panic. @@ -29,7 +29,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// **What it does:** Checks for trivial [regex](https://crates.io/crates/regex) - /// creation (with `Regex::new`, `RegexBuilder::new` or `RegexSet::new`). + /// creation (with `Regex::new`, `RegexBuilder::new`, or `RegexSet::new`). /// /// **Why is this bad?** Matching the regex can likely be replaced by `==` or /// `str::starts_with`, `str::ends_with` or `std::contains` or other `str` diff --git a/clippy_lints/src/unit_return_expecting_ord.rs b/clippy_lints/src/unit_return_expecting_ord.rs index ade5fff5ffc06..2501635e7ef66 100644 --- a/clippy_lints/src/unit_return_expecting_ord.rs +++ b/clippy_lints/src/unit_return_expecting_ord.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// **Example:** /// /// ```rust - /// let mut twins = vec!((1,1), (2,2)); + /// let mut twins = vec!((1, 1), (2, 2)); /// twins.sort_by_key(|x| { x.1; }); /// ``` pub UNIT_RETURN_EXPECTING_ORD, diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index c6194b0c6de3e..99c38e8f1761d 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -12,8 +12,8 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; declare_clippy_lint! { - /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`,`IntoIter` calls - /// that useless converts to the same type as caller. + /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls + /// that uselessly convert to the same type. /// /// **Why is this bad?** Redundant code. /// @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` pub USELESS_CONVERSION, complexity, - "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type" + "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` that perform useless conversions to the same type" } #[derive(Default)] diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs index 79b24b83680e2..1d906d20ad475 100644 --- a/src/lintlist/mod.rs +++ b/src/lintlist/mod.rs @@ -2751,7 +2751,7 @@ vec![ Lint { name: "useless_conversion", group: "complexity", - desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, `IntoIter` that performs useless conversions to the same type", + desc: "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type", deprecation: None, module: "useless_conversion", }, From 445466e567c192bb81ccc366743793ffb079da5d Mon Sep 17 00:00:00 2001 From: "Carol (Nichols || Goulding)" <193874+carols10cents@users.noreply.github.com> Date: Sun, 22 Nov 2020 10:12:41 -0500 Subject: [PATCH 108/118] Apply suggestions from code review to change "that" to "which" Co-authored-by: oliver <16816606+o752d@users.noreply.github.com> --- clippy_lints/src/useless_conversion.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs index 99c38e8f1761d..efa9c3fab4ab8 100644 --- a/clippy_lints/src/useless_conversion.rs +++ b/clippy_lints/src/useless_conversion.rs @@ -13,7 +13,7 @@ use rustc_span::sym; declare_clippy_lint! { /// **What it does:** Checks for `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` calls - /// that uselessly convert to the same type. + /// which uselessly convert to the same type. /// /// **Why is this bad?** Redundant code. /// @@ -31,7 +31,7 @@ declare_clippy_lint! { /// ``` pub USELESS_CONVERSION, complexity, - "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` that perform useless conversions to the same type" + "calls to `Into`, `TryInto`, `From`, `TryFrom`, or `IntoIter` which perform useless conversions to the same type" } #[derive(Default)] From ab1e6342956620901723106761eacb0113e1583b Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 22 Nov 2020 12:57:55 -0500 Subject: [PATCH 109/118] Make `fold_item_recur` non-nullable This gets rid of a bunch of `unwrap()`s and makes it a little more clear what's going on. Originally I wanted to make `fold_item` non-nullable too, which would have been a lot nicer to work with, but unfortunately `stripper` does actually return `None` in some places. I might make a follow-up moving stripper to be special and not a pass so that passes can be non-nullable. --- src/librustdoc/fold.rs | 13 ++-- src/librustdoc/formats/cache.rs | 77 +++++++++---------- src/librustdoc/html/sources.rs | 2 +- .../passes/calculate_doc_coverage.rs | 2 +- .../passes/check_code_block_syntax.rs | 2 +- src/librustdoc/passes/collapse_docs.rs | 2 +- .../passes/collect_intra_doc_links.rs | 6 +- src/librustdoc/passes/collect_trait_impls.rs | 4 +- src/librustdoc/passes/doc_test_lints.rs | 2 +- src/librustdoc/passes/html_tags.rs | 4 +- src/librustdoc/passes/non_autolinks.rs | 4 +- src/librustdoc/passes/propagate_doc_cfg.rs | 2 +- src/librustdoc/passes/strip_hidden.rs | 4 +- src/librustdoc/passes/stripper.rs | 16 ++-- src/librustdoc/passes/unindent_comments.rs | 2 +- 15 files changed, 67 insertions(+), 75 deletions(-) diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index a72860ef0a8fd..285fabdc37230 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -16,7 +16,7 @@ impl StripItem { crate trait DocFolder: Sized { fn fold_item(&mut self, item: Item) -> Option { - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } /// don't override! @@ -71,15 +71,12 @@ crate trait DocFolder: Sized { } /// don't override! - fn fold_item_recur(&mut self, item: Item) -> Option { - let Item { attrs, name, source, visibility, def_id, kind, stability, deprecation } = item; - - let kind = match kind { + fn fold_item_recur(&mut self, mut item: Item) -> Item { + item.kind = match item.kind { StrippedItem(box i) => StrippedItem(box self.fold_inner_recur(i)), - _ => self.fold_inner_recur(kind), + _ => self.fold_inner_recur(item.kind), }; - - Some(Item { attrs, name, source, kind, visibility, stability, deprecation, def_id }) + item } fn fold_mod(&mut self, m: Module) -> Module { diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 917c1a95fdbf5..39b750279ac5b 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -421,55 +421,52 @@ impl DocFolder for Cache { // Once we've recursively found all the generics, hoard off all the // implementations elsewhere. - let ret = self.fold_item_recur(item).and_then(|item| { - if let clean::Item { kind: clean::ImplItem(_), .. } = item { - // Figure out the id of this impl. This may map to a - // primitive rather than always to a struct/enum. - // Note: matching twice to restrict the lifetime of the `i` borrow. - let mut dids = FxHashSet::default(); - if let clean::Item { kind: clean::ImplItem(ref i), .. } = item { - match i.for_ { - clean::ResolvedPath { did, .. } - | clean::BorrowedRef { - type_: box clean::ResolvedPath { did, .. }, .. - } => { - dids.insert(did); - } - ref t => { - let did = t - .primitive_type() - .and_then(|t| self.primitive_locations.get(&t).cloned()); + let item = self.fold_item_recur(item); + let ret = if let clean::Item { kind: clean::ImplItem(_), .. } = item { + // Figure out the id of this impl. This may map to a + // primitive rather than always to a struct/enum. + // Note: matching twice to restrict the lifetime of the `i` borrow. + let mut dids = FxHashSet::default(); + if let clean::Item { kind: clean::ImplItem(ref i), .. } = item { + match i.for_ { + clean::ResolvedPath { did, .. } + | clean::BorrowedRef { type_: box clean::ResolvedPath { did, .. }, .. } => { + dids.insert(did); + } + ref t => { + let did = t + .primitive_type() + .and_then(|t| self.primitive_locations.get(&t).cloned()); - if let Some(did) = did { - dids.insert(did); - } + if let Some(did) = did { + dids.insert(did); } } + } - if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { - for bound in generics { - if let Some(did) = bound.def_id() { - dids.insert(did); - } + if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { + for bound in generics { + if let Some(did) = bound.def_id() { + dids.insert(did); } } - } else { - unreachable!() - }; - let impl_item = Impl { impl_item: item }; - if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { - for did in dids { - self.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); - } - } else { - let trait_did = impl_item.trait_did().expect("no trait did"); - self.orphan_trait_impls.push((trait_did, dids, impl_item)); } - None } else { - Some(item) + unreachable!() + }; + let impl_item = Impl { impl_item: item }; + if impl_item.trait_did().map_or(true, |d| self.traits.contains_key(&d)) { + for did in dids { + self.impls.entry(did).or_insert(vec![]).push(impl_item.clone()); + } + } else { + let trait_did = impl_item.trait_did().expect("no trait did"); + self.orphan_trait_impls.push((trait_did, dids, impl_item)); } - }); + None + } else { + Some(item) + }; if pushed { self.stack.pop().expect("stack already empty"); diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 0f82649409f36..e7b5a90d84df0 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -60,7 +60,7 @@ impl<'a> DocFolder for SourceCollector<'a> { } }; } - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index aca218e538165..3f9978c8fca84 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -268,6 +268,6 @@ impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { } } - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index a48fa738e3b72..0c76dc571beee 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -105,7 +105,7 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { } } - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index 1f9f5c58e5a93..e1ba75baa0fa4 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -23,7 +23,7 @@ struct Collapser; impl fold::DocFolder for Collapser { fn fold_item(&mut self, mut i: Item) -> Option { i.attrs.collapse_doc_comments(); - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fd09ba04b3db9..b0639e43ae65e 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -858,7 +858,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { // we don't display docs on `extern crate` items anyway, so don't process them. clean::ExternCrateItem(..) => { debug!("ignoring extern crate item {:?}", item.def_id); - return self.fold_item_recur(item); + return Some(self.fold_item_recur(item)); } clean::ImportItem(Import { kind: clean::ImportKind::Simple(ref name, ..), .. }) => { Some(name.clone()) @@ -958,7 +958,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } } - if item.is_mod() { + Some(if item.is_mod() { if !item.attrs.inner_docs { self.mod_ids.push(item.def_id); } @@ -968,7 +968,7 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { ret } else { self.fold_item_recur(item) - } + }) } } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 2946db1f46206..4c3defabc3294 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> DocFolder for SyntheticImplCollector<'a, 'tcx> { } } - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } @@ -152,7 +152,7 @@ impl DocFolder for ItemCollector { fn fold_item(&mut self, i: Item) -> Option { self.items.insert(i.def_id); - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 60fe8080f56b4..299a73c8a0112 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -41,7 +41,7 @@ impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> { look_for_tests(&cx, &dox, &item); - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index 70748633117fb..a7a1ba1118d1f 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -178,7 +178,7 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - return self.fold_item_recur(item); + return Some(self.fold_item_recur(item)); } }; let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); @@ -223,6 +223,6 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { } } - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/non_autolinks.rs b/src/librustdoc/passes/non_autolinks.rs index c9c49968b93e1..1f411b997f802 100644 --- a/src/librustdoc/passes/non_autolinks.rs +++ b/src/librustdoc/passes/non_autolinks.rs @@ -68,7 +68,7 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> { Some(hir_id) => hir_id, None => { // If non-local, no need to check anything. - return self.fold_item_recur(item); + return Some(self.fold_item_recur(item)); } }; let dox = item.attrs.collapsed_doc_value().unwrap_or_default(); @@ -133,6 +133,6 @@ impl<'a, 'tcx> DocFolder for NonAutolinksLinter<'a, 'tcx> { } } - self.fold_item_recur(item) + Some(self.fold_item_recur(item)) } } diff --git a/src/librustdoc/passes/propagate_doc_cfg.rs b/src/librustdoc/passes/propagate_doc_cfg.rs index fbfc693c5347d..6722d7c2fc9fe 100644 --- a/src/librustdoc/passes/propagate_doc_cfg.rs +++ b/src/librustdoc/passes/propagate_doc_cfg.rs @@ -39,6 +39,6 @@ impl DocFolder for CfgPropagator { let result = self.fold_item_recur(item); self.parent_cfg = old_parent_cfg; - result + Some(result) } } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 6da753ea6e695..6b59eb8cf288a 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -47,7 +47,7 @@ impl<'a> DocFolder for Stripper<'a> { // strip things like impl methods but when doing so // we must not add any items to the `retained` set. let old = mem::replace(&mut self.update_retained, false); - let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); + let ret = StripItem(self.fold_item_recur(i)).strip(); self.update_retained = old; return ret; } @@ -58,6 +58,6 @@ impl<'a> DocFolder for Stripper<'a> { self.retained.insert(i.def_id); } } - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index eb5a61a9d202a..444fd593ec9c9 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -22,7 +22,7 @@ impl<'a> DocFolder for Stripper<'a> { let old = mem::replace(&mut self.update_retained, false); let ret = self.fold_item_recur(i); self.update_retained = old; - return ret; + return Some(ret); } // These items can all get re-exported clean::OpaqueTyItem(..) @@ -59,7 +59,7 @@ impl<'a> DocFolder for Stripper<'a> { if i.def_id.is_local() && !i.visibility.is_public() { debug!("Stripper: stripping module {:?}", i.name); let old = mem::replace(&mut self.update_retained, false); - let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); + let ret = StripItem(self.fold_item_recur(i)).strip(); self.update_retained = old; return ret; } @@ -107,12 +107,10 @@ impl<'a> DocFolder for Stripper<'a> { self.fold_item_recur(i) }; - if let Some(ref i) = i { - if self.update_retained { - self.retained.insert(i.def_id); - } + if self.update_retained { + self.retained.insert(i.def_id); } - i + Some(i) } } @@ -153,7 +151,7 @@ impl<'a> DocFolder for ImplStripper<'a> { } } } - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } @@ -164,7 +162,7 @@ impl DocFolder for ImportStripper { fn fold_item(&mut self, i: Item) -> Option { match i.kind { clean::ExternCrateItem(..) | clean::ImportItem(..) if !i.visibility.is_public() => None, - _ => self.fold_item_recur(i), + _ => Some(self.fold_item_recur(i)), } } } diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs index eb2f066bbdebb..d0345d1e48cb5 100644 --- a/src/librustdoc/passes/unindent_comments.rs +++ b/src/librustdoc/passes/unindent_comments.rs @@ -23,7 +23,7 @@ struct CommentCleaner; impl fold::DocFolder for CommentCleaner { fn fold_item(&mut self, mut i: Item) -> Option { i.attrs.unindent_doc_comments(); - self.fold_item_recur(i) + Some(self.fold_item_recur(i)) } } From 0043fc9ce6e5482bda8e4a1b8c4c195332a877b9 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 22 Nov 2020 13:34:06 -0500 Subject: [PATCH 110/118] Get rid of `doctree::Impl` --- src/librustdoc/clean/mod.rs | 102 +++++++++---------- src/librustdoc/core.rs | 16 --- src/librustdoc/doctree.rs | 18 ---- src/librustdoc/visit_ast.rs | 30 +----- src/test/rustdoc-ui/intra-link-errors.stderr | 18 ++-- 5 files changed, 60 insertions(+), 124 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d58a88957df22..e76ca1022a943 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -234,9 +234,8 @@ impl Clean for doctree::Module<'_> { items.extend(self.fns.iter().map(|x| x.clean(cx))); items.extend(self.foreigns.iter().map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); - items.extend(self.items.iter().map(|x| x.clean(cx))); + items.extend(self.items.iter().map(|x| x.clean(cx)).flatten()); items.extend(self.traits.iter().map(|x| x.clean(cx))); - items.extend(self.impls.iter().flat_map(|x| x.clean(cx))); items.extend(self.macros.iter().map(|x| x.clean(cx))); items.extend(self.proc_macros.iter().map(|x| x.clean(cx))); @@ -1922,8 +1921,8 @@ impl Clean for hir::BareFnTy<'_> { } } -impl Clean for (&hir::Item<'_>, Option) { - fn clean(&self, cx: &DocContext<'_>) -> Item { +impl Clean> for (&hir::Item<'_>, Option) { + fn clean(&self, cx: &DocContext<'_>) -> Vec { use hir::ItemKind; let (item, renamed) = self; @@ -1977,10 +1976,11 @@ impl Clean for (&hir::Item<'_>, Option) { fields: variant_data.fields().clean(cx), fields_stripped: false, }), + ItemKind::Impl { .. } => return clean_impl(item, cx), _ => unreachable!("not yet converted"), }; - Item::from_def_id_and_parts(def_id, Some(name), kind, cx) + vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)] } } @@ -2005,57 +2005,53 @@ impl Clean for ty::ImplPolarity { } } -impl Clean> for doctree::Impl<'_> { - fn clean(&self, cx: &DocContext<'_>) -> Vec { - let mut ret = Vec::new(); - let trait_ = self.trait_.clean(cx); - let items = self.items.iter().map(|ii| ii.clean(cx)).collect::>(); - let def_id = cx.tcx.hir().local_def_id(self.id); - - // If this impl block is an implementation of the Deref trait, then we - // need to try inlining the target's inherent impl blocks as well. - if trait_.def_id() == cx.tcx.lang_items().deref_trait() { - build_deref_target_impls(cx, &items, &mut ret); +fn clean_impl(impl_: &hir::Item<'_>, cx: &DocContext<'_>) -> Vec { + let mut ret = Vec::new(); + let (trait_, items, for_, unsafety, generics) = match &impl_.kind { + hir::ItemKind::Impl { of_trait, items, self_ty, unsafety, generics, .. } => { + (of_trait, items, self_ty, *unsafety, generics) } - - let provided: FxHashSet = trait_ - .def_id() - .map(|did| { - cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect() - }) - .unwrap_or_default(); - - let for_ = self.for_.clean(cx); - let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) { - DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)), - _ => None, + _ => unreachable!(), + }; + let trait_ = trait_.clean(cx); + let items = items.iter().map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx)).collect::>(); + let def_id = cx.tcx.hir().local_def_id(impl_.hir_id); + + // If this impl block is an implementation of the Deref trait, then we + // need to try inlining the target's inherent impl blocks as well. + if trait_.def_id() == cx.tcx.lang_items().deref_trait() { + build_deref_target_impls(cx, &items, &mut ret); + } + + let provided: FxHashSet = trait_ + .def_id() + .map(|did| cx.tcx.provided_trait_methods(did).map(|meth| meth.ident.to_string()).collect()) + .unwrap_or_default(); + + let for_ = for_.clean(cx); + let type_alias = for_.def_id().and_then(|did| match cx.tcx.def_kind(did) { + DefKind::TyAlias => Some(cx.tcx.type_of(did).clean(cx)), + _ => None, + }); + let make_item = |trait_: Option, for_: Type, items: Vec| { + let kind = ImplItem(Impl { + unsafety, + generics: generics.clean(cx), + provided_trait_methods: provided.clone(), + trait_, + for_, + items, + polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)), + synthetic: false, + blanket_impl: None, }); - let make_item = |trait_: Option, for_: Type, items: Vec| Item { - name: None, - attrs: self.attrs.clean(cx), - source: self.span.clean(cx), - def_id: def_id.to_def_id(), - visibility: self.vis.clean(cx), - stability: cx.stability(self.id), - deprecation: cx.deprecation(self.id).clean(cx), - kind: ImplItem(Impl { - unsafety: self.unsafety, - generics: self.generics.clean(cx), - provided_trait_methods: provided.clone(), - trait_, - for_, - items, - polarity: Some(cx.tcx.impl_polarity(def_id).clean(cx)), - synthetic: false, - blanket_impl: None, - }), - }; - if let Some(type_alias) = type_alias { - ret.push(make_item(trait_.clone(), type_alias, items.clone())); - } - ret.push(make_item(trait_, for_, items)); - ret + Item::from_hir_id_and_parts(impl_.hir_id, None, kind, cx) + }; + if let Some(type_alias) = type_alias { + ret.push(make_item(trait_.clone(), type_alias, items.clone())); } + ret.push(make_item(trait_, for_, items)); + ret } impl Clean> for doctree::ExternCrate<'_> { diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 413f5bdf5214b..b7cc0f1945911 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,4 +1,3 @@ -use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{self, Lrc}; use rustc_driver::abort_on_err; @@ -156,21 +155,6 @@ impl<'tcx> DocContext<'tcx> { def_id.as_local().map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)) } } - - crate fn stability(&self, id: HirId) -> Option { - self.tcx - .hir() - .opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_stability(def_id.to_def_id())) - .cloned() - } - - crate fn deprecation(&self, id: HirId) -> Option { - self.tcx - .hir() - .opt_local_def_id(id) - .and_then(|def_id| self.tcx.lookup_deprecation(def_id.to_def_id())) - } } /// Creates a new diagnostic `Handler` that can be used to emit warnings and errors. diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index d56328cc2aa08..4d2fe04123bc2 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -23,7 +23,6 @@ crate struct Module<'hir> { // (item, renamed) crate items: Vec<(&'hir hir::Item<'hir>, Option)>, crate traits: Vec>, - crate impls: Vec>, crate foreigns: Vec>, crate macros: Vec, crate proc_macros: Vec, @@ -44,7 +43,6 @@ impl Module<'hir> { mods: Vec::new(), items: Vec::new(), traits: Vec::new(), - impls: Vec::new(), foreigns: Vec::new(), macros: Vec::new(), proc_macros: Vec::new(), @@ -89,22 +87,6 @@ crate struct Trait<'hir> { crate id: hir::HirId, } -#[derive(Debug)] -crate struct Impl<'hir> { - crate unsafety: hir::Unsafety, - crate polarity: hir::ImplPolarity, - crate defaultness: hir::Defaultness, - crate constness: hir::Constness, - crate generics: &'hir hir::Generics<'hir>, - crate trait_: &'hir Option>, - crate for_: &'hir hir::Ty<'hir>, - crate items: Vec<&'hir hir::ImplItem<'hir>>, - crate attrs: &'hir [ast::Attribute], - crate span: Span, - crate vis: &'hir hir::Visibility<'hir>, - crate id: hir::HirId, -} - crate struct ForeignItem<'hir> { crate id: hir::HirId, crate name: Symbol, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index c55e5f7690c14..37050a57ca017 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -401,37 +401,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; om.traits.push(t); } - hir::ItemKind::Impl { - unsafety, - polarity, - defaultness, - constness, - defaultness_span: _, - ref generics, - ref of_trait, - self_ty, - ref items, - } => { + hir::ItemKind::Impl { ref of_trait, .. } => { // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick // them up regardless of where they're located. if !self.inlining && of_trait.is_none() { - let items = - items.iter().map(|item| self.cx.tcx.hir().impl_item(item.id)).collect(); - let i = Impl { - unsafety, - polarity, - defaultness, - constness, - generics, - trait_: of_trait, - for_: self_ty, - items, - attrs: &item.attrs, - id: item.hir_id, - span: item.span, - vis: &item.vis, - }; - om.impls.push(i); + om.items.push((item, None)); } } } diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr index 31e7fc48afde5..be98cac94ece7 100644 --- a/src/test/rustdoc-ui/intra-link-errors.stderr +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -106,6 +106,15 @@ LL | /// [S!] | this link resolves to the struct `S`, which is not in the macro namespace | help: to link to the struct, prefix with `struct@`: `struct@S` +error: unresolved link to `S::h` + --> $DIR/intra-link-errors.rs:78:6 + | +LL | /// [type@S::h] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `h`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `S::h()` + error: unresolved link to `T::g` --> $DIR/intra-link-errors.rs:86:6 | @@ -121,15 +130,6 @@ error: unresolved link to `T::h` LL | /// [T::h!] | ^^^^^ the trait `T` has no macro named `h` -error: unresolved link to `S::h` - --> $DIR/intra-link-errors.rs:78:6 - | -LL | /// [type@S::h] - | ^^^^^^^^^ - | | - | this link resolves to the associated function `h`, which is not in the type namespace - | help: to link to the associated function, add parentheses: `S::h()` - error: unresolved link to `m` --> $DIR/intra-link-errors.rs:98:6 | From 0b6537a9ea50b294ae0b371ac4b6757303bb19f8 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sun, 22 Nov 2020 14:25:50 -0800 Subject: [PATCH 111/118] Accept '!' in intra-doc links This will allow linking to things like `Result`. --- src/librustdoc/passes/collect_intra_doc_links.rs | 2 +- src/test/rustdoc/intra-doc-link-generic-params.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index fd09ba04b3db9..e1b82e58b85b3 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1022,7 +1022,7 @@ impl LinkCollector<'_, '_> { (link.trim(), None) }; - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) { + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, !".contains(ch))) { return None; } diff --git a/src/test/rustdoc/intra-doc-link-generic-params.rs b/src/test/rustdoc/intra-doc-link-generic-params.rs index 7d7289437ff8a..1de6410f10c43 100644 --- a/src/test/rustdoc/intra-doc-link-generic-params.rs +++ b/src/test/rustdoc/intra-doc-link-generic-params.rs @@ -15,8 +15,11 @@ // @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option' //! We should also try linking to [`Result`]; it has *two* generics! +//! And [`Result`] and [`Result`]. //! // @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result' //! Now let's test a trickier case: [`Vec::::new`], or you could write it //! [with parentheses as `Vec::::new()`][Vec::::new()]. From fafe3cd68290b7440e1ea66fca8438363a431274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Mon, 23 Nov 2020 00:00:00 +0000 Subject: [PATCH 112/118] Allow using `-Z fewer-names=no` to retain value names Change `-Z fewer-names` into an optional boolean flag and allow using it to either discard value names when true or retain them when false, regardless of other settings. --- compiler/rustc_interface/src/tests.rs | 2 +- compiler/rustc_session/src/options.rs | 2 +- compiler/rustc_session/src/session.rs | 15 +++++++++------ src/test/codegen/fewer-names.rs | 20 ++++++++++++++++++++ 4 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 src/test/codegen/fewer-names.rs diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 1fc2d281e7935..01d5ed2f34abf 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -547,7 +547,7 @@ fn test_debugging_options_tracking_hash() { tracked!(debug_macros, true); tracked!(dep_info_omit_d_target, true); tracked!(dual_proc_macros, true); - tracked!(fewer_names, true); + tracked!(fewer_names, Some(true)); tracked!(force_overflow_checks, Some(true)); tracked!(force_unstable_if_unmarked, true); tracked!(fuel, Some(("abc".to_string(), 99))); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1cd3d11e32153..ba083140f5140 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -900,7 +900,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "emits a future-incompatibility report for lints (RFC 2834)"), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), - fewer_names: bool = (false, parse_bool, [TRACKED], + fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), force_overflow_checks: Option = (None, parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 419d1447764ec..5dddf0eb72ea6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -734,12 +734,15 @@ impl Session { self.opts.cg.panic.unwrap_or(self.target.panic_strategy) } pub fn fewer_names(&self) -> bool { - let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) - || self.opts.output_types.contains_key(&OutputType::Bitcode) - // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. - || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); - - self.opts.debugging_opts.fewer_names || !more_names + if let Some(fewer_names) = self.opts.debugging_opts.fewer_names { + fewer_names + } else { + let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) + || self.opts.output_types.contains_key(&OutputType::Bitcode) + // AddressSanitizer and MemorySanitizer use alloca name when reporting an issue. + || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY); + !more_names + } } pub fn unstable_options(&self) -> bool { diff --git a/src/test/codegen/fewer-names.rs b/src/test/codegen/fewer-names.rs new file mode 100644 index 0000000000000..53a926d49efe7 --- /dev/null +++ b/src/test/codegen/fewer-names.rs @@ -0,0 +1,20 @@ +// no-system-llvm +// compile-flags: -Coverflow-checks=no -O +// revisions: YES NO +// [YES]compile-flags: -Zfewer-names=yes +// [NO] compile-flags: -Zfewer-names=no +#![crate_type = "lib"] + +#[no_mangle] +pub fn sum(x: u32, y: u32) -> u32 { +// YES-LABEL: define i32 @sum(i32 %0, i32 %1) +// YES-NEXT: %3 = add i32 %1, %0 +// YES-NEXT: ret i32 %3 + +// NO-LABEL: define i32 @sum(i32 %x, i32 %y) +// NO-NEXT: start: +// NO-NEXT: %z = add i32 %y, %x +// NO-NEXT: ret i32 %z + let z = x + y; + z +} From 99b9459a77d71abe0e0bb8466beb5c2548d592d5 Mon Sep 17 00:00:00 2001 From: flip1995 Date: Mon, 23 Nov 2020 13:52:27 +0100 Subject: [PATCH 113/118] Fix ICE in utils::implements_trait This only happend when debug_assertions were enabled in rustc --- src/tools/clippy/clippy_lints/src/utils/mod.rs | 3 +++ src/tools/clippy/tests/ui/crashes/implements-trait.rs | 5 +++++ 2 files changed, 8 insertions(+) create mode 100644 src/tools/clippy/tests/ui/crashes/implements-trait.rs diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 5bd64dcb541f4..e9c71e23a670b 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -365,6 +365,9 @@ pub fn implements_trait<'tcx>( return false; } let ty = cx.tcx.erase_regions(ty); + if ty.has_escaping_bound_vars() { + return false; + } let ty_params = cx.tcx.mk_substs(ty_params.iter()); cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env)) } diff --git a/src/tools/clippy/tests/ui/crashes/implements-trait.rs b/src/tools/clippy/tests/ui/crashes/implements-trait.rs new file mode 100644 index 0000000000000..4502b0147a83e --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/implements-trait.rs @@ -0,0 +1,5 @@ +#[allow(clippy::needless_borrowed_reference)] +fn main() { + let mut v = Vec::::new(); + let _ = v.iter_mut().filter(|&ref a| a.is_empty()); +} From c5c3d7bdf43078b5323b21bf15711831b2c8a229 Mon Sep 17 00:00:00 2001 From: takashiidobe Date: Mon, 23 Nov 2020 10:48:19 -0500 Subject: [PATCH 114/118] Fix typo in keyword docs for traits --- library/std/src/keyword_docs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index b990b78570393..80b74a9ba9b09 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1739,7 +1739,7 @@ mod super_keyword {} /// /// # Differences between the 2015 and 2018 editions /// -/// In the 2015 edition parameters pattern where not needed for traits: +/// In the 2015 edition the parameters pattern was not needed for traits: /// /// ```rust,edition2015 /// trait Tr { From 8526c313c115bb997a10d6c012864f6c4a5c6853 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 23 Nov 2020 16:40:48 +0100 Subject: [PATCH 115/118] BTreeMap: cut out the ceremony around BoxedNode --- library/alloc/src/collections/btree/node.rs | 50 +++++---------------- src/etc/gdb_providers.py | 12 ++--- 2 files changed, 18 insertions(+), 44 deletions(-) diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index e3e555a72de02..6a8be441513a0 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -112,20 +112,8 @@ impl InternalNode { /// /// However, `BoxedNode` contains no information as to which of the two types /// of nodes it actually contains, and, partially due to this lack of information, -/// has no destructor. -struct BoxedNode { - ptr: NonNull>, -} - -impl BoxedNode { - fn from_owned(ptr: NonNull>) -> Self { - BoxedNode { ptr } - } - - fn as_ptr(&self) -> NonNull> { - self.ptr - } -} +/// is not a separate type and has no destructor. +type BoxedNode = NonNull>; /// An owned tree. /// @@ -168,11 +156,6 @@ impl NodeRef { pub fn borrow_valmut(&mut self) -> NodeRef, K, V, Type> { NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - - /// Packs the reference, aware of type and height, into a type-agnostic pointer. - fn into_boxed_node(self) -> BoxedNode { - BoxedNode::from_owned(self.node) - } } impl NodeRef { @@ -181,7 +164,7 @@ impl NodeRef { /// and is the opposite of `pop_internal_level`. pub fn push_internal_level(&mut self) -> NodeRef, K, V, marker::Internal> { let mut new_node = Box::new(unsafe { InternalNode::new() }); - new_node.edges[0].write(BoxedNode::from_owned(self.node)); + new_node.edges[0].write(self.node); let mut new_root = NodeRef::from_new_internal(new_node, self.height + 1); new_root.borrow_mut().first_edge().correct_parent_link(); *self = new_root.forget_type(); @@ -288,13 +271,6 @@ unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef Send for NodeRef, K, V, Type> {} unsafe impl Send for NodeRef {} -impl NodeRef { - /// Unpack a node reference that was packed by `Root::into_boxed_node`. - fn from_boxed_node(boxed_node: BoxedNode, height: usize) -> Self { - NodeRef { height, node: boxed_node.as_ptr(), _marker: PhantomData } - } -} - impl NodeRef { /// Unpack a node reference that was packed as `NodeRef::parent`. fn from_internal(node: NonNull>, height: usize) -> Self { @@ -695,7 +671,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { unsafe { self.reborrow_mut().into_key_area_mut_at(idx).write(key); self.reborrow_mut().into_val_area_mut_at(idx).write(val); - self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.into_boxed_node()); + self.reborrow_mut().into_edge_area_mut_at(idx + 1).write(edge.node); Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); } } @@ -710,7 +686,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { *self.reborrow_mut().into_len_mut() += 1; slice_insert(self.reborrow_mut().into_key_area_slice(), 0, key); slice_insert(self.reborrow_mut().into_val_area_slice(), 0, val); - slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.into_boxed_node()); + slice_insert(self.reborrow_mut().into_edge_area_slice(), 0, edge.node); } self.correct_all_childrens_parent_links(); @@ -732,8 +708,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(internal) => { - let boxed_node = ptr::read(internal.reborrow().edge_at(idx + 1)); - let mut edge = Root::from_boxed_node(boxed_node, internal.height - 1); + let node = ptr::read(internal.reborrow().edge_at(idx + 1)); + let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; // In practice, clearing the parent is a waste of time, because we will // insert the node elsewhere and set its parent link again. edge.borrow_mut().clear_parent_link(); @@ -760,9 +736,8 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let boxed_node = - slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0); - let mut edge = Root::from_boxed_node(boxed_node, internal.height - 1); + let node = slice_remove(internal.reborrow_mut().into_edge_area_slice(), 0); + let mut edge = Root { node, height: internal.height - 1, _marker: PhantomData }; // In practice, clearing the parent is a waste of time, because we will // insert the node elsewhere and set its parent link again. edge.borrow_mut().clear_parent_link(); @@ -1041,12 +1016,11 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, debug_assert!(self.node.len() < CAPACITY); debug_assert!(edge.height == self.node.height - 1); - let boxed_node = edge.into_boxed_node(); unsafe { *self.node.reborrow_mut().into_len_mut() += 1; slice_insert(self.node.reborrow_mut().into_key_area_slice(), self.idx, key); slice_insert(self.node.reborrow_mut().into_val_area_slice(), self.idx, val); - slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, boxed_node); + slice_insert(self.node.reborrow_mut().into_edge_area_slice(), self.idx + 1, edge.node); self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len()); } @@ -1135,8 +1109,8 @@ impl Handle, marke // reference (Rust issue #73987) and invalidate any other references // to or inside the array, should any be around. let parent_ptr = NodeRef::as_internal_ptr(&self.node); - let boxed_node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() }; - NodeRef::from_boxed_node(boxed_node, self.node.height - 1) + let node = unsafe { (*parent_ptr).edges.get_unchecked(self.idx).assume_init_read() }; + NodeRef { node, height: self.node.height - 1, _marker: PhantomData } } } diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index b5ade324bba10..b74d47a80027a 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -216,6 +216,10 @@ def cast_to_internal(node): internal_type = lookup_type(internal_type_name) return node.cast(internal_type.pointer()) + if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"): + # BACKCOMPAT: rust 1.49 + node_ptr = node_ptr["ptr"] + node_ptr = unwrap_unique_or_non_null(node_ptr) leaf = node_ptr.dereference() keys = leaf["keys"] vals = leaf["vals"] @@ -224,9 +228,8 @@ def cast_to_internal(node): for i in xrange(0, length + 1): if height > 0: - boxed_child_node = edges[i]["value"]["value"] - child_node = unwrap_unique_or_non_null(boxed_child_node["ptr"]) - for child in children_of_node(child_node, height - 1): + child_ptr = edges[i]["value"]["value"] + for child in children_of_node(child_ptr, height - 1): yield child if i < length: # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays. @@ -239,9 +242,6 @@ def cast_to_internal(node): if root.type.name.startswith("core::option::Option<"): root = root.cast(gdb.lookup_type(root.type.name[21:-1])) node_ptr = root["node"] - if node_ptr.type.name.startswith("alloc::collections::btree::node::BoxedNode<"): - node_ptr = node_ptr["ptr"] - node_ptr = unwrap_unique_or_non_null(node_ptr) height = root["height"] for child in children_of_node(node_ptr, height): yield child From 9c8db454af551ca4e9a6d0eb9599ef71e5c579a2 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Mon, 23 Nov 2020 19:09:23 +0100 Subject: [PATCH 116/118] BTreeMap/BTreeSet: make public doc more consistent --- library/alloc/src/collections/btree/map.rs | 4 ++-- library/alloc/src/collections/btree/set.rs | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 383f4487aff3d..1625af4543dac 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -458,7 +458,7 @@ impl fmt::Debug for RangeMut<'_, K, V> { } impl BTreeMap { - /// Makes a new empty BTreeMap. + /// Makes a new, empty `BTreeMap`. /// /// Does not allocate anything on its own. /// @@ -1924,7 +1924,7 @@ impl Hash for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeMap { - /// Creates an empty `BTreeMap`. + /// Creates an empty `BTreeMap`. fn default() -> BTreeMap { BTreeMap::new() } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 1a807100653bc..f4046e87b99a8 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -220,7 +220,9 @@ impl fmt::Debug for Union<'_, T> { const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16; impl BTreeSet { - /// Makes a new `BTreeSet` with a reasonable choice of B. + /// Makes a new, empty `BTreeSet`. + /// + /// Does not allocate anything on its own. /// /// # Examples /// @@ -1121,7 +1123,7 @@ impl<'a, T: 'a + Ord + Copy> Extend<&'a T> for BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] impl Default for BTreeSet { - /// Makes an empty `BTreeSet` with a reasonable choice of B. + /// Creates an empty `BTreeSet`. fn default() -> BTreeSet { BTreeSet::new() } From fcbe6381a75fa2502a5c46cf4463b6eae46ba38f Mon Sep 17 00:00:00 2001 From: Christiaan Dirkx Date: Sun, 22 Nov 2020 09:08:04 +0100 Subject: [PATCH 117/118] Make ui test that are run-pass and do not test the compiler itself library tests --- library/alloc/tests/str.rs | 96 +++++++- library/core/tests/ascii.rs | 53 ++++ library/core/tests/atomic.rs | 79 ++++++ library/core/tests/bool.rs | 84 +++++++ library/core/tests/cmp.rs | 71 ++++++ library/core/tests/iter.rs | 12 + library/core/tests/lib.rs | 3 + library/core/tests/macros.rs | 14 ++ library/core/tests/num/wrapping.rs | 233 ++++++++++++++++++ library/core/tests/ops.rs | 33 +++ library/core/tests/option.rs | 10 + library/core/tests/ptr.rs | 13 + library/core/tests/result.rs | 38 +++ library/core/tests/unicode.rs | 5 + library/std/tests/env.rs | 61 +++++ .../sleep.rs => library/std/tests/thread.rs | 15 +- src/test/ui/assert-eq-trailing-comma.rs | 5 - src/test/ui/assert-escape.rs | 5 - src/test/ui/assert-ne-trailing-comma.rs | 5 - src/test/ui/atomic-access-bool.rs | 24 -- src/test/ui/atomic-alignment.rs | 38 --- src/test/ui/atomic-compare_exchange.rs | 31 --- src/test/ui/bool-not.rs | 6 - src/test/ui/bool.rs | 72 ------ src/test/ui/char_unicode.rs | 10 - src/test/ui/cmp-default.rs | 73 ------ src/test/ui/consts/ascii_ctype.rs | 53 ---- src/test/ui/consts/const-str-ptr.rs | 17 -- src/test/ui/deref-mut-on-ref.rs | 15 -- src/test/ui/deref-on-ref.rs | 19 -- src/test/ui/env-home-dir.rs | 50 ---- src/test/ui/extend-for-unit.rs | 12 - src/test/ui/offset_from.rs | 13 - src/test/ui/option-ext.rs | 10 - src/test/ui/result-opt-conversions.rs | 47 ---- src/test/ui/utf8.rs | 50 ---- src/test/ui/utf8_chars.rs | 31 --- src/test/ui/wrapping-int-api.rs | 228 ----------------- 38 files changed, 811 insertions(+), 823 deletions(-) create mode 100644 library/core/tests/macros.rs create mode 100644 library/core/tests/unicode.rs rename src/test/ui/sleep.rs => library/std/tests/thread.rs (61%) delete mode 100644 src/test/ui/assert-eq-trailing-comma.rs delete mode 100644 src/test/ui/assert-escape.rs delete mode 100644 src/test/ui/assert-ne-trailing-comma.rs delete mode 100644 src/test/ui/atomic-access-bool.rs delete mode 100644 src/test/ui/atomic-alignment.rs delete mode 100644 src/test/ui/atomic-compare_exchange.rs delete mode 100644 src/test/ui/bool-not.rs delete mode 100644 src/test/ui/bool.rs delete mode 100644 src/test/ui/char_unicode.rs delete mode 100644 src/test/ui/cmp-default.rs delete mode 100644 src/test/ui/consts/ascii_ctype.rs delete mode 100644 src/test/ui/consts/const-str-ptr.rs delete mode 100644 src/test/ui/deref-mut-on-ref.rs delete mode 100644 src/test/ui/deref-on-ref.rs delete mode 100644 src/test/ui/env-home-dir.rs delete mode 100644 src/test/ui/extend-for-unit.rs delete mode 100644 src/test/ui/offset_from.rs delete mode 100644 src/test/ui/option-ext.rs delete mode 100644 src/test/ui/result-opt-conversions.rs delete mode 100644 src/test/ui/utf8.rs delete mode 100644 src/test/ui/utf8_chars.rs delete mode 100644 src/test/ui/wrapping-int-api.rs diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 834dd4656ff76..b13019146568c 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::cmp::Ordering::{Equal, Greater, Less}; -use std::str::from_utf8; +use std::str::{from_utf8, from_utf8_unchecked}; #[test] fn test_le() { @@ -1971,3 +1971,97 @@ fn test_str_escapes() { "; assert_eq!(x, r"\\"); // extraneous whitespace stripped } + +#[test] +fn const_str_ptr() { + const A: [u8; 2] = ['h' as u8, 'i' as u8]; + const B: &'static [u8; 2] = &A; + const C: *const u8 = B as *const u8; + + unsafe { + let foo = &A as *const u8; + assert_eq!(foo, C); + assert_eq!(from_utf8_unchecked(&A), "hi"); + assert_eq!(*C, A[0]); + assert_eq!(*(&B[0] as *const u8), A[0]); + } +} + +#[test] +fn utf8() { + let yen: char = '¥'; // 0xa5 + let c_cedilla: char = 'ç'; // 0xe7 + let thorn: char = 'þ'; // 0xfe + let y_diaeresis: char = 'ÿ'; // 0xff + let pi: char = 'Π'; // 0x3a0 + + assert_eq!(yen as isize, 0xa5); + assert_eq!(c_cedilla as isize, 0xe7); + assert_eq!(thorn as isize, 0xfe); + assert_eq!(y_diaeresis as isize, 0xff); + assert_eq!(pi as isize, 0x3a0); + + assert_eq!(pi as isize, '\u{3a0}' as isize); + assert_eq!('\x0a' as isize, '\n' as isize); + + let bhutan: String = "འབྲུག་ཡུལ།".to_string(); + let japan: String = "日本".to_string(); + let uzbekistan: String = "Ўзбекистон".to_string(); + let austria: String = "Österreich".to_string(); + + let bhutan_e: String = + "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); + let japan_e: String = "\u{65e5}\u{672c}".to_string(); + let uzbekistan_e: String = + "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); + let austria_e: String = "\u{d6}sterreich".to_string(); + + let oo: char = 'Ö'; + assert_eq!(oo as isize, 0xd6); + + fn check_str_eq(a: String, b: String) { + let mut i: isize = 0; + for ab in a.bytes() { + println!("{}", i); + println!("{}", ab); + let bb: u8 = b.as_bytes()[i as usize]; + println!("{}", bb); + assert_eq!(ab, bb); + i += 1; + } + } + + check_str_eq(bhutan, bhutan_e); + check_str_eq(japan, japan_e); + check_str_eq(uzbekistan, uzbekistan_e); + check_str_eq(austria, austria_e); +} + +#[test] +fn utf8_chars() { + // Chars of 1, 2, 3, and 4 bytes + let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; + let s: String = chs.iter().cloned().collect(); + let schs: Vec = s.chars().collect(); + + assert_eq!(s.len(), 10); + assert_eq!(s.chars().count(), 4); + assert_eq!(schs.len(), 4); + assert_eq!(schs.iter().cloned().collect::(), s); + + assert!((from_utf8(s.as_bytes()).is_ok())); + // invalid prefix + assert!((!from_utf8(&[0x80]).is_ok())); + // invalid 2 byte prefix + assert!((!from_utf8(&[0xc0]).is_ok())); + assert!((!from_utf8(&[0xc0, 0x10]).is_ok())); + // invalid 3 byte prefix + assert!((!from_utf8(&[0xe0]).is_ok())); + assert!((!from_utf8(&[0xe0, 0x10]).is_ok())); + assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); + // invalid 4 byte prefix + assert!((!from_utf8(&[0xf0]).is_ok())); + assert!((!from_utf8(&[0xf0, 0x10]).is_ok())); + assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); + assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); +} diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 3244bbc2d670d..66c25e449df2b 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -408,3 +408,56 @@ fn ascii_const() { const BYTE_IS_ASCII: bool = 97u8.is_ascii(); assert!(BYTE_IS_ASCII); } + +#[test] +fn ascii_ctype_const() { + macro_rules! suite { + ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { + $( + mod $fn { + const CHAR_A_LOWER: bool = 'a'.$fn(); + const CHAR_A_UPPER: bool = 'A'.$fn(); + const CHAR_NINE: bool = '9'.$fn(); + const CHAR_DOT: bool = '.'.$fn(); + const CHAR_SPACE: bool = ' '.$fn(); + + const U8_A_LOWER: bool = b'a'.$fn(); + const U8_A_UPPER: bool = b'A'.$fn(); + const U8_NINE: bool = b'9'.$fn(); + const U8_DOT: bool = b'.'.$fn(); + const U8_SPACE: bool = b' '.$fn(); + + pub fn run() { + assert_eq!(CHAR_A_LOWER, $a); + assert_eq!(CHAR_A_UPPER, $A); + assert_eq!(CHAR_NINE, $nine); + assert_eq!(CHAR_DOT, $dot); + assert_eq!(CHAR_SPACE, $space); + + assert_eq!(U8_A_LOWER, $a); + assert_eq!(U8_A_UPPER, $A); + assert_eq!(U8_NINE, $nine); + assert_eq!(U8_DOT, $dot); + assert_eq!(U8_SPACE, $space); + } + } + )* + + $( $fn::run(); )* + } + } + + suite! { + // 'a' 'A' '9' '.' ' ' + is_ascii_alphabetic => [true, true, false, false, false]; + is_ascii_uppercase => [false, true, false, false, false]; + is_ascii_lowercase => [true, false, false, false, false]; + is_ascii_alphanumeric => [true, true, true, false, false]; + is_ascii_digit => [false, false, true, false, false]; + is_ascii_hexdigit => [true, true, true, false, false]; + is_ascii_punctuation => [false, false, false, true, false]; + is_ascii_graphic => [true, true, true, true, false]; + is_ascii_whitespace => [false, false, false, false, true]; + is_ascii_control => [false, false, false, false, false]; + } +} diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs index acbd913982c1f..75528ebb54eaf 100644 --- a/library/core/tests/atomic.rs +++ b/library/core/tests/atomic.rs @@ -101,3 +101,82 @@ fn static_init() { assert!(S_INT.fetch_add(1, SeqCst) == 0); assert!(S_UINT.fetch_add(1, SeqCst) == 0); } + +#[test] +fn atomic_access_bool() { + static mut ATOMIC: AtomicBool = AtomicBool::new(false); + + unsafe { + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.store(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_or(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_and(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.fetch_nand(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_xor(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + } +} + +#[test] +fn atomic_alignment() { + use std::mem::{align_of, size_of}; + + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::>(), size_of::>()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "8")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "16")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "32")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "64")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "128")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); + #[cfg(target_has_atomic = "ptr")] + assert_eq!(align_of::(), size_of::()); +} + +#[test] +fn atomic_compare_exchange() { + use Ordering::*; + + static ATOMIC: AtomicIsize = AtomicIsize::new(0); + + ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); + ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); + ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); + ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); +} diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs index e89eb2c7f94d5..e40f0482aee3e 100644 --- a/library/core/tests/bool.rs +++ b/library/core/tests/bool.rs @@ -1,3 +1,87 @@ +use core::cmp::Ordering::{Equal, Greater, Less}; +use core::ops::{BitAnd, BitOr, BitXor}; + +#[test] +fn test_bool() { + assert_eq!(false.eq(&true), false); + assert_eq!(false == false, true); + assert_eq!(false != true, true); + assert_eq!(false.ne(&false), false); + + assert_eq!(false.bitand(false), false); + assert_eq!(true.bitand(false), false); + assert_eq!(false.bitand(true), false); + assert_eq!(true.bitand(true), true); + + assert_eq!(false & false, false); + assert_eq!(true & false, false); + assert_eq!(false & true, false); + assert_eq!(true & true, true); + + assert_eq!(false.bitor(false), false); + assert_eq!(true.bitor(false), true); + assert_eq!(false.bitor(true), true); + assert_eq!(true.bitor(true), true); + + assert_eq!(false | false, false); + assert_eq!(true | false, true); + assert_eq!(false | true, true); + assert_eq!(true | true, true); + + assert_eq!(false.bitxor(false), false); + assert_eq!(true.bitxor(false), true); + assert_eq!(false.bitxor(true), true); + assert_eq!(true.bitxor(true), false); + + assert_eq!(false ^ false, false); + assert_eq!(true ^ false, true); + assert_eq!(false ^ true, true); + assert_eq!(true ^ true, false); + + assert_eq!(!true, false); + assert_eq!(!false, true); + + let s = false.to_string(); + assert_eq!(s, "false"); + let s = true.to_string(); + assert_eq!(s, "true"); + + assert!(true > false); + assert!(!(false > true)); + + assert!(false < true); + assert!(!(true < false)); + + assert!(false <= false); + assert!(false >= false); + assert!(true <= true); + assert!(true >= true); + + assert!(false <= true); + assert!(!(false >= true)); + assert!(true >= false); + assert!(!(true <= false)); + + assert_eq!(true.cmp(&true), Equal); + assert_eq!(false.cmp(&false), Equal); + assert_eq!(true.cmp(&false), Greater); + assert_eq!(false.cmp(&true), Less); +} + +#[test] +pub fn test_bool_not() { + if !false { + assert!((true)); + } else { + assert!((false)); + } + if !true { + assert!((false)); + } else { + assert!((true)); + } +} + #[test] fn test_bool_to_option() { assert_eq!(false.then_some(0), None); diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 835289daf715a..11cf7add07ada 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -132,3 +132,74 @@ fn ordering_const() { const THEN: Ordering = Equal.then(ORDERING); assert_eq!(THEN, Greater); } + +#[test] +fn cmp_default() { + // Test default methods in PartialOrd and PartialEq + + #[derive(Debug)] + struct Fool(bool); + + impl PartialEq for Fool { + fn eq(&self, other: &Fool) -> bool { + let Fool(this) = *self; + let Fool(other) = *other; + this != other + } + } + + struct Int(isize); + + impl PartialEq for Int { + fn eq(&self, other: &Int) -> bool { + let Int(this) = *self; + let Int(other) = *other; + this == other + } + } + + impl PartialOrd for Int { + fn partial_cmp(&self, other: &Int) -> Option { + let Int(this) = *self; + let Int(other) = *other; + this.partial_cmp(&other) + } + } + + struct RevInt(isize); + + impl PartialEq for RevInt { + fn eq(&self, other: &RevInt) -> bool { + let RevInt(this) = *self; + let RevInt(other) = *other; + this == other + } + } + + impl PartialOrd for RevInt { + fn partial_cmp(&self, other: &RevInt) -> Option { + let RevInt(this) = *self; + let RevInt(other) = *other; + other.partial_cmp(&this) + } + } + + assert!(Int(2) > Int(1)); + assert!(Int(2) >= Int(1)); + assert!(Int(1) >= Int(1)); + assert!(Int(1) < Int(2)); + assert!(Int(1) <= Int(2)); + assert!(Int(1) <= Int(1)); + + assert!(RevInt(2) < RevInt(1)); + assert!(RevInt(2) <= RevInt(1)); + assert!(RevInt(1) <= RevInt(1)); + assert!(RevInt(1) > RevInt(2)); + assert!(RevInt(1) >= RevInt(2)); + assert!(RevInt(1) >= RevInt(1)); + + assert_eq!(Fool(true), Fool(false)); + assert!(Fool(true) != Fool(true)); + assert!(Fool(false) != Fool(false)); + assert_eq!(Fool(false), Fool(true)); +} diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 75ca897cadc91..7d1980c27d487 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -3482,3 +3482,15 @@ fn test_flatten_non_fused_inner() { assert_eq!(iter.next(), Some(1)); assert_eq!(iter.next(), None); } + +#[test] +pub fn extend_for_unit() { + let mut x = 0; + { + let iter = (0..5).map(|_| { + x += 1; + }); + ().extend(iter); + } + assert_eq!(x, 5); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 14ef03fd53eba..07a36c3ec1e3d 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -8,6 +8,7 @@ #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] +#![feature(cfg_target_has_atomic)] #![feature(const_assume)] #![feature(const_cell_into_inner)] #![feature(core_intrinsics)] @@ -81,6 +82,7 @@ mod hash; mod intrinsics; mod iter; mod lazy; +mod macros; mod manually_drop; mod mem; mod nonzero; @@ -97,3 +99,4 @@ mod str_lossy; mod task; mod time; mod tuple; +mod unicode; diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs new file mode 100644 index 0000000000000..482f3c1c99840 --- /dev/null +++ b/library/core/tests/macros.rs @@ -0,0 +1,14 @@ +#[test] +fn assert_eq_trailing_comma() { + assert_eq!(1, 1,); +} + +#[test] +fn assert_escape() { + assert!(r#"☃\backslash"#.contains("\\")); +} + +#[test] +fn assert_ne_trailing_comma() { + assert_ne!(1, 2,); +} diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs index 5d4ecb2669a96..01defab2b38f0 100644 --- a/library/core/tests/num/wrapping.rs +++ b/library/core/tests/num/wrapping.rs @@ -74,3 +74,236 @@ wrapping_test!(u64, u64::MIN, u64::MAX); #[cfg(not(target_os = "emscripten"))] wrapping_test!(u128, u128::MIN, u128::MAX); wrapping_test!(usize, usize::MIN, usize::MAX); + +// Don't warn about overflowing ops on 32-bit platforms +#[cfg_attr(target_pointer_width = "32", allow(const_err))] +fn wrapping_int_api() { + assert_eq!(i8::MAX.wrapping_add(1), i8::MIN); + assert_eq!(i16::MAX.wrapping_add(1), i16::MIN); + assert_eq!(i32::MAX.wrapping_add(1), i32::MIN); + assert_eq!(i64::MAX.wrapping_add(1), i64::MIN); + assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); + + assert_eq!(i8::MIN.wrapping_sub(1), i8::MAX); + assert_eq!(i16::MIN.wrapping_sub(1), i16::MAX); + assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX); + assert_eq!(i64::MIN.wrapping_sub(1), i64::MAX); + assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); + + assert_eq!(u8::MAX.wrapping_add(1), u8::MIN); + assert_eq!(u16::MAX.wrapping_add(1), u16::MIN); + assert_eq!(u32::MAX.wrapping_add(1), u32::MIN); + assert_eq!(u64::MAX.wrapping_add(1), u64::MIN); + assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); + + assert_eq!(u8::MIN.wrapping_sub(1), u8::MAX); + assert_eq!(u16::MIN.wrapping_sub(1), u16::MAX); + assert_eq!(u32::MIN.wrapping_sub(1), u32::MAX); + assert_eq!(u64::MIN.wrapping_sub(1), u64::MAX); + assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); + + assert_eq!((0xfe_u8 as i8).wrapping_mul(16), (0xe0_u8 as i8)); + assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), (0xedc0_u16 as i16)); + assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), (0xedcb_a980_u32 as i32)); + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as i64) + ); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), (0xedcb_a980_u32 as isize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), + (0xedcb_a987_6543_2170_u64 as isize) + ); + } + } + + assert_eq!((0xfe as u8).wrapping_mul(16), (0xe0 as u8)); + assert_eq!((0xfedc as u16).wrapping_mul(16), (0xedc0 as u16)); + assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), (0xedcb_a980 as u32)); + assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), (0xedcb_a987_6543_2170 as u64)); + + match () { + #[cfg(target_pointer_width = "32")] + () => { + assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), (0xedcb_a980 as usize)); + } + #[cfg(target_pointer_width = "64")] + () => { + assert_eq!( + (0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), + (0xedcb_a987_6543_2170 as usize) + ); + } + } + + macro_rules! check_mul_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), ($e) * $f); + }; + } + macro_rules! check_mul_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_mul($f), $e); + }; + } + + check_mul_no_wrap!(0xfe_u8 as i8, -1); + check_mul_no_wrap!(0xfedc_u16 as i16, -1); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_mul_no_wrap!(0xfe_u8 as i8, -2); + check_mul_no_wrap!(0xfedc_u16 as i16, -2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); + + check_mul_no_wrap!(0xfe_u8 as i8, 2); + check_mul_no_wrap!(0xfedc_u16 as i16, 2); + check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); + + check_mul_wraps!(0x80_u8 as i8, -1); + check_mul_wraps!(0x8000_u16 as i16, -1); + check_mul_wraps!(0x8000_0000_u32 as i32, -1); + check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_mul_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_div_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), ($e) / $f); + }; + } + macro_rules! check_div_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_div($f), $e); + }; + } + + check_div_no_wrap!(0xfe_u8 as i8, -1); + check_div_no_wrap!(0xfedc_u16 as i16, -1); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_div_no_wrap!(0xfe_u8 as i8, -2); + check_div_no_wrap!(0xfedc_u16 as i16, -2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_div_no_wrap!(0xfe_u8 as i8, 2); + check_div_no_wrap!(0xfedc_u16 as i16, 2); + check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_div_wraps!(-128 as i8, -1); + check_div_wraps!(0x8000_u16 as i16, -1); + check_div_wraps!(0x8000_0000_u32 as i32, -1); + check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_div_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_rem_no_wrap { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), ($e) % $f); + }; + } + macro_rules! check_rem_wraps { + ($e:expr, $f:expr) => { + assert_eq!(($e).wrapping_rem($f), 0); + }; + } + + check_rem_no_wrap!(0xfe_u8 as i8, -1); + check_rem_no_wrap!(0xfedc_u16 as i16, -1); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); + + check_rem_no_wrap!(0xfe_u8 as i8, -2); + check_rem_no_wrap!(0xfedc_u16 as i16, -2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); + + check_rem_no_wrap!(0xfe_u8 as i8, 2); + check_rem_no_wrap!(0xfedc_u16 as i16, 2); + check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); + check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); + + check_rem_wraps!(0x80_u8 as i8, -1); + check_rem_wraps!(0x8000_u16 as i16, -1); + check_rem_wraps!(0x8000_0000_u32 as i32, -1); + check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_rem_wraps!(0x8000_0000_u32 as isize, -1); + } + #[cfg(target_pointer_width = "64")] + () => { + check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); + } + } + + macro_rules! check_neg_no_wrap { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), -($e)); + }; + } + macro_rules! check_neg_wraps { + ($e:expr) => { + assert_eq!(($e).wrapping_neg(), ($e)); + }; + } + + check_neg_no_wrap!(0xfe_u8 as i8); + check_neg_no_wrap!(0xfedc_u16 as i16); + check_neg_no_wrap!(0xfedc_ba98_u32 as i32); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); + check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); + + check_neg_wraps!(0x80_u8 as i8); + check_neg_wraps!(0x8000_u16 as i16); + check_neg_wraps!(0x8000_0000_u32 as i32); + check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); + match () { + #[cfg(target_pointer_width = "32")] + () => { + check_neg_wraps!(0x8000_0000_u32 as isize); + } + #[cfg(target_pointer_width = "64")] + () => { + check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); + } + } +} diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs index e9d595e65e2b2..53e5539fad91c 100644 --- a/library/core/tests/ops.rs +++ b/library/core/tests/ops.rs @@ -1,4 +1,5 @@ use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive}; +use core::ops::{Deref, DerefMut}; // Test the Range structs and syntax. @@ -197,3 +198,35 @@ fn range_structural_match() { _ => unreachable!(), } } + +// Test Deref implementations + +#[test] +fn deref_mut_on_ref() { + // Test that `&mut T` implements `DerefMut` + + fn inc + DerefMut>(mut t: T) { + *t += 1; + } + + let mut x: isize = 5; + inc(&mut x); + assert_eq!(x, 6); +} + +#[test] +fn deref_on_ref() { + // Test that `&T` and `&mut T` implement `Deref` + + fn deref>(t: T) -> U { + *t + } + + let x: isize = 3; + let y = deref(&x); + assert_eq!(y, 3); + + let mut x: isize = 4; + let y = deref(&mut x); + assert_eq!(y, 4); +} diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index ae814efec2086..5388b4756245a 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -402,3 +402,13 @@ fn test_unwrap_drop() { assert_eq!(x.get(), 0); } + +#[test] +pub fn option_ext() { + let thing = "{{ f }}"; + let f = thing.find("{{"); + + if f.is_none() { + println!("None!"); + } +} diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index bf977c141cbf8..47f0a573ce13e 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -400,3 +400,16 @@ fn align_offset_weird_strides() { } assert!(!x); } + +#[test] +fn offset_from() { + let mut a = [0; 5]; + let ptr1: *mut i32 = &mut a[1]; + let ptr2: *mut i32 = &mut a[3]; + unsafe { + assert_eq!(ptr2.offset_from(ptr1), 2); + assert_eq!(ptr1.offset_from(ptr2), -2); + assert_eq!(ptr1.offset(2), ptr2); + assert_eq!(ptr2.offset(-2), ptr1); + } +} diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index 39ea4831b9b86..81660870e95e4 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -320,3 +320,41 @@ fn result_const() { const IS_ERR: bool = RESULT.is_err(); assert!(!IS_ERR) } + +#[test] +fn result_opt_conversions() { + #[derive(Copy, Clone, Debug, PartialEq)] + struct BadNumErr; + + fn try_num(x: i32) -> Result { + if x <= 5 { Ok(x + 1) } else { Err(BadNumErr) } + } + + type ResOpt = Result, BadNumErr>; + type OptRes = Option>; + + let mut x: ResOpt = Ok(Some(5)); + let mut y: OptRes = Some(Ok(5)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Ok(None); + y = None; + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + x = Err(BadNumErr); + y = Some(Err(BadNumErr)); + assert_eq!(x, y.transpose()); + assert_eq!(x.transpose(), y); + + let res: Result, BadNumErr> = (0..10) + .map(|x| { + let y = try_num(x)?; + Ok(if y % 2 == 0 { Some(y - 1) } else { None }) + }) + .filter_map(Result::transpose) + .collect(); + + assert_eq!(res, Err(BadNumErr)) +} diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs new file mode 100644 index 0000000000000..c28ea859115e1 --- /dev/null +++ b/library/core/tests/unicode.rs @@ -0,0 +1,5 @@ +#[test] +pub fn version() { + let (major, _minor, _update) = core::unicode::UNICODE_VERSION; + assert!(major >= 10); +} diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs index c94fc41178dfe..0e55ec648c9c5 100644 --- a/library/std/tests/env.rs +++ b/library/std/tests/env.rs @@ -1,5 +1,6 @@ use std::env::*; use std::ffi::{OsStr, OsString}; +use std::path::PathBuf; use rand::distributions::Alphanumeric; use rand::{thread_rng, Rng}; @@ -76,3 +77,63 @@ fn test_env_set_var() { assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" })); } + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] +#[allow(deprecated)] +fn env_home_dir() { + fn var_to_os_string(var: Result) -> Option { + match var { + Ok(var) => Some(OsString::from(var)), + Err(VarError::NotUnicode(var)) => Some(var), + _ => None, + } + } + + cfg_if::cfg_if! { + if #[cfg(unix)] { + let oldhome = var_to_os_string(var("HOME")); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + if cfg!(target_os = "android") { + assert!(home_dir().is_none()); + } else { + // When HOME is not set, some platforms return `None`, + // but others return `Some` with a default. + // Just check that it is not "/home/MountainView". + assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + } + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + } else if #[cfg(windows)] { + let oldhome = var_to_os_string(var("HOME")); + let olduserprofile = var_to_os_string(var("USERPROFILE")); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + assert!(home_dir().is_some()); + + set_var("HOME", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + + set_var("USERPROFILE", "/home/MountainView"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + set_var("HOME", "/home/MountainView"); + set_var("USERPROFILE", "/home/PaloAlto"); + assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); + + remove_var("HOME"); + remove_var("USERPROFILE"); + + if let Some(oldhome) = oldhome { set_var("HOME", oldhome); } + if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); } + } + } +} diff --git a/src/test/ui/sleep.rs b/library/std/tests/thread.rs similarity index 61% rename from src/test/ui/sleep.rs rename to library/std/tests/thread.rs index 3b3a4a4f3250c..047dec007b7cb 100644 --- a/src/test/ui/sleep.rs +++ b/library/std/tests/thread.rs @@ -1,18 +1,17 @@ -// run-pass -// ignore-emscripten no threads support - -use std::thread::{self, sleep}; -use std::time::Duration; use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; use std::u64; -fn main() { +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn sleep() { let finished = Arc::new(Mutex::new(false)); let t_finished = finished.clone(); thread::spawn(move || { - sleep(Duration::new(u64::MAX, 0)); + thread::sleep(Duration::new(u64::MAX, 0)); *t_finished.lock().unwrap() = true; }); - sleep(Duration::from_millis(100)); + thread::sleep(Duration::from_millis(100)); assert_eq!(*finished.lock().unwrap(), false); } diff --git a/src/test/ui/assert-eq-trailing-comma.rs b/src/test/ui/assert-eq-trailing-comma.rs deleted file mode 100644 index 7071f80d7f7ba..0000000000000 --- a/src/test/ui/assert-eq-trailing-comma.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert_eq!(1, 1,); -} diff --git a/src/test/ui/assert-escape.rs b/src/test/ui/assert-escape.rs deleted file mode 100644 index 00e51d42cab9e..0000000000000 --- a/src/test/ui/assert-escape.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert!(r#"☃\backslash"#.contains("\\")); -} diff --git a/src/test/ui/assert-ne-trailing-comma.rs b/src/test/ui/assert-ne-trailing-comma.rs deleted file mode 100644 index 03308db9a1fee..0000000000000 --- a/src/test/ui/assert-ne-trailing-comma.rs +++ /dev/null @@ -1,5 +0,0 @@ -// run-pass - -fn main() { - assert_ne!(1, 2,); -} diff --git a/src/test/ui/atomic-access-bool.rs b/src/test/ui/atomic-access-bool.rs deleted file mode 100644 index e9d48bb3b43d8..0000000000000 --- a/src/test/ui/atomic-access-bool.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - -#![allow(stable_features)] -#![feature(atomic_access)] -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering::*; - -static mut ATOMIC: AtomicBool = AtomicBool::new(false); - -fn main() { - unsafe { - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.store(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_or(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_and(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.fetch_nand(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_xor(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - } -} diff --git a/src/test/ui/atomic-alignment.rs b/src/test/ui/atomic-alignment.rs deleted file mode 100644 index 5bda90d2eab02..0000000000000 --- a/src/test/ui/atomic-alignment.rs +++ /dev/null @@ -1,38 +0,0 @@ -// run-pass - -#![feature(cfg_target_has_atomic)] -#![feature(integer_atomics)] - -use std::mem::{align_of, size_of}; -use std::sync::atomic::*; - -fn main() { - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::>(), size_of::>()); - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "8")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "16")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "16")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "32")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "32")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "64")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "64")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "128")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "128")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::(), size_of::()); - #[cfg(target_has_atomic = "ptr")] - assert_eq!(align_of::(), size_of::()); -} diff --git a/src/test/ui/atomic-compare_exchange.rs b/src/test/ui/atomic-compare_exchange.rs deleted file mode 100644 index 9b327eef3c894..0000000000000 --- a/src/test/ui/atomic-compare_exchange.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -#![allow(stable_features)] - -#![feature(extended_compare_and_swap)] -use std::sync::atomic::AtomicIsize; -use std::sync::atomic::Ordering::*; - -static ATOMIC: AtomicIsize = AtomicIsize::new(0); - -fn main() { - // Make sure codegen can emit all the intrinsics correctly - ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); - ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); -} diff --git a/src/test/ui/bool-not.rs b/src/test/ui/bool-not.rs deleted file mode 100644 index 84713d6818a3e..0000000000000 --- a/src/test/ui/bool-not.rs +++ /dev/null @@ -1,6 +0,0 @@ -// run-pass - -pub fn main() { - if !false { assert!((true)); } else { assert!((false)); } - if !true { assert!((false)); } else { assert!((true)); } -} diff --git a/src/test/ui/bool.rs b/src/test/ui/bool.rs deleted file mode 100644 index 92f36c8fd25ad..0000000000000 --- a/src/test/ui/bool.rs +++ /dev/null @@ -1,72 +0,0 @@ -// run-pass -// Basic boolean tests - - -use std::cmp::Ordering::{Equal, Greater, Less}; -use std::ops::{BitAnd, BitOr, BitXor}; - -fn main() { - assert_eq!(false.eq(&true), false); - assert_eq!(false == false, true); - assert_eq!(false != true, true); - assert_eq!(false.ne(&false), false); - - assert_eq!(false.bitand(false), false); - assert_eq!(true.bitand(false), false); - assert_eq!(false.bitand(true), false); - assert_eq!(true.bitand(true), true); - - assert_eq!(false & false, false); - assert_eq!(true & false, false); - assert_eq!(false & true, false); - assert_eq!(true & true, true); - - assert_eq!(false.bitor(false), false); - assert_eq!(true.bitor(false), true); - assert_eq!(false.bitor(true), true); - assert_eq!(true.bitor(true), true); - - assert_eq!(false | false, false); - assert_eq!(true | false, true); - assert_eq!(false | true, true); - assert_eq!(true | true, true); - - assert_eq!(false.bitxor(false), false); - assert_eq!(true.bitxor(false), true); - assert_eq!(false.bitxor(true), true); - assert_eq!(true.bitxor(true), false); - - assert_eq!(false ^ false, false); - assert_eq!(true ^ false, true); - assert_eq!(false ^ true, true); - assert_eq!(true ^ true, false); - - assert_eq!(!true, false); - assert_eq!(!false, true); - - let s = false.to_string(); - assert_eq!(s, "false"); - let s = true.to_string(); - assert_eq!(s, "true"); - - assert!(true > false); - assert!(!(false > true)); - - assert!(false < true); - assert!(!(true < false)); - - assert!(false <= false); - assert!(false >= false); - assert!(true <= true); - assert!(true >= true); - - assert!(false <= true); - assert!(!(false >= true)); - assert!(true >= false); - assert!(!(true <= false)); - - assert_eq!(true.cmp(&true), Equal); - assert_eq!(false.cmp(&false), Equal); - assert_eq!(true.cmp(&false), Greater); - assert_eq!(false.cmp(&true), Less); -} diff --git a/src/test/ui/char_unicode.rs b/src/test/ui/char_unicode.rs deleted file mode 100644 index 65dda47066f4e..0000000000000 --- a/src/test/ui/char_unicode.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -/// Tests access to the Unicode version constant. -pub fn main() { - check(std::char::UNICODE_VERSION); -} - -pub fn check(unicode_version: (u8, u8, u8)) { - assert!(unicode_version.0 >= 10); -} diff --git a/src/test/ui/cmp-default.rs b/src/test/ui/cmp-default.rs deleted file mode 100644 index bb5c39f5cdea9..0000000000000 --- a/src/test/ui/cmp-default.rs +++ /dev/null @@ -1,73 +0,0 @@ -// run-pass - -use std::cmp::Ordering; - -// Test default methods in PartialOrd and PartialEq -// -#[derive(Debug)] -struct Fool(bool); - -impl PartialEq for Fool { - fn eq(&self, other: &Fool) -> bool { - let Fool(this) = *self; - let Fool(other) = *other; - this != other - } -} - -struct Int(isize); - -impl PartialEq for Int { - fn eq(&self, other: &Int) -> bool { - let Int(this) = *self; - let Int(other) = *other; - this == other - } -} - -impl PartialOrd for Int { - fn partial_cmp(&self, other: &Int) -> Option { - let Int(this) = *self; - let Int(other) = *other; - this.partial_cmp(&other) - } -} - -struct RevInt(isize); - -impl PartialEq for RevInt { - fn eq(&self, other: &RevInt) -> bool { - let RevInt(this) = *self; - let RevInt(other) = *other; - this == other - } -} - -impl PartialOrd for RevInt { - fn partial_cmp(&self, other: &RevInt) -> Option { - let RevInt(this) = *self; - let RevInt(other) = *other; - other.partial_cmp(&this) - } -} - -pub fn main() { - assert!(Int(2) > Int(1)); - assert!(Int(2) >= Int(1)); - assert!(Int(1) >= Int(1)); - assert!(Int(1) < Int(2)); - assert!(Int(1) <= Int(2)); - assert!(Int(1) <= Int(1)); - - assert!(RevInt(2) < RevInt(1)); - assert!(RevInt(2) <= RevInt(1)); - assert!(RevInt(1) <= RevInt(1)); - assert!(RevInt(1) > RevInt(2)); - assert!(RevInt(1) >= RevInt(2)); - assert!(RevInt(1) >= RevInt(1)); - - assert_eq!(Fool(true), Fool(false)); - assert!(Fool(true) != Fool(true)); - assert!(Fool(false) != Fool(false)); - assert_eq!(Fool(false), Fool(true)); -} diff --git a/src/test/ui/consts/ascii_ctype.rs b/src/test/ui/consts/ascii_ctype.rs deleted file mode 100644 index ef2f7322f2718..0000000000000 --- a/src/test/ui/consts/ascii_ctype.rs +++ /dev/null @@ -1,53 +0,0 @@ -// run-pass - -macro_rules! suite { - ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => { - $( - mod $fn { - const CHAR_A_LOWER: bool = 'a'.$fn(); - const CHAR_A_UPPER: bool = 'A'.$fn(); - const CHAR_NINE: bool = '9'.$fn(); - const CHAR_DOT: bool = '.'.$fn(); - const CHAR_SPACE: bool = ' '.$fn(); - - const U8_A_LOWER: bool = b'a'.$fn(); - const U8_A_UPPER: bool = b'A'.$fn(); - const U8_NINE: bool = b'9'.$fn(); - const U8_DOT: bool = b'.'.$fn(); - const U8_SPACE: bool = b' '.$fn(); - - pub fn run() { - assert_eq!(CHAR_A_LOWER, $a); - assert_eq!(CHAR_A_UPPER, $A); - assert_eq!(CHAR_NINE, $nine); - assert_eq!(CHAR_DOT, $dot); - assert_eq!(CHAR_SPACE, $space); - - assert_eq!(U8_A_LOWER, $a); - assert_eq!(U8_A_UPPER, $A); - assert_eq!(U8_NINE, $nine); - assert_eq!(U8_DOT, $dot); - assert_eq!(U8_SPACE, $space); - } - } - )* - - fn main() { - $( $fn::run(); )* - } - } -} - -suite! { - // 'a' 'A' '9' '.' ' ' - is_ascii_alphabetic => [true, true, false, false, false]; - is_ascii_uppercase => [false, true, false, false, false]; - is_ascii_lowercase => [true, false, false, false, false]; - is_ascii_alphanumeric => [true, true, true, false, false]; - is_ascii_digit => [false, false, true, false, false]; - is_ascii_hexdigit => [true, true, true, false, false]; - is_ascii_punctuation => [false, false, false, true, false]; - is_ascii_graphic => [true, true, true, true, false]; - is_ascii_whitespace => [false, false, false, false, true]; - is_ascii_control => [false, false, false, false, false]; -} diff --git a/src/test/ui/consts/const-str-ptr.rs b/src/test/ui/consts/const-str-ptr.rs deleted file mode 100644 index 56fd9d9f55ffc..0000000000000 --- a/src/test/ui/consts/const-str-ptr.rs +++ /dev/null @@ -1,17 +0,0 @@ -// run-pass -#![allow(unused_imports)] -use std::{str, string}; - -const A: [u8; 2] = ['h' as u8, 'i' as u8]; -const B: &'static [u8; 2] = &A; -const C: *const u8 = B as *const u8; - -pub fn main() { - unsafe { - let foo = &A as *const u8; - assert_eq!(foo, C); - assert_eq!(str::from_utf8_unchecked(&A), "hi"); - assert_eq!(*C, A[0]); - assert_eq!(*(&B[0] as *const u8), A[0]); - } -} diff --git a/src/test/ui/deref-mut-on-ref.rs b/src/test/ui/deref-mut-on-ref.rs deleted file mode 100644 index a6df5495a2775..0000000000000 --- a/src/test/ui/deref-mut-on-ref.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass -// Test that `&mut T` implements `DerefMut` - - -use std::ops::{Deref, DerefMut}; - -fn inc + DerefMut>(mut t: T) { - *t += 1; -} - -fn main() { - let mut x: isize = 5; - inc(&mut x); - assert_eq!(x, 6); -} diff --git a/src/test/ui/deref-on-ref.rs b/src/test/ui/deref-on-ref.rs deleted file mode 100644 index 973e61c9d59fa..0000000000000 --- a/src/test/ui/deref-on-ref.rs +++ /dev/null @@ -1,19 +0,0 @@ -// run-pass -// Test that `&T` and `&mut T` implement `Deref` - - -use std::ops::Deref; - -fn deref>(t: T) -> U { - *t -} - -fn main() { - let x: isize = 3; - let y = deref(&x); - assert_eq!(y, 3); - - let mut x: isize = 4; - let y = deref(&mut x); - assert_eq!(y, 4); -} diff --git a/src/test/ui/env-home-dir.rs b/src/test/ui/env-home-dir.rs deleted file mode 100644 index c597b4732d158..0000000000000 --- a/src/test/ui/env-home-dir.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -#![allow(unused_variables)] -#![allow(deprecated)] -// ignore-emscripten env vars don't work? -// ignore-sgx env vars cannot be modified - -use std::env::*; -use std::path::PathBuf; - -#[cfg(unix)] -fn main() { - let oldhome = var("HOME"); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - if cfg!(target_os = "android") { - assert!(home_dir().is_none()); - } else { - // When HOME is not set, some platforms return `None`, - // but others return `Some` with a default. - // Just check that it is not "/home/MountainView". - assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - } -} - -#[cfg(windows)] -fn main() { - let oldhome = var("HOME"); - let olduserprofile = var("USERPROFILE"); - - remove_var("HOME"); - remove_var("USERPROFILE"); - - assert!(home_dir().is_some()); - - set_var("HOME", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - remove_var("HOME"); - - set_var("USERPROFILE", "/home/MountainView"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); - - set_var("HOME", "/home/MountainView"); - set_var("USERPROFILE", "/home/PaloAlto"); - assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView"))); -} diff --git a/src/test/ui/extend-for-unit.rs b/src/test/ui/extend-for-unit.rs deleted file mode 100644 index 01d743f70bc0a..0000000000000 --- a/src/test/ui/extend-for-unit.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - -pub fn main() { - let mut x = 0; - { - let iter = (0..5).map(|_| { - x += 1; - }); - ().extend(iter); - } - assert_eq!(x, 5); -} diff --git a/src/test/ui/offset_from.rs b/src/test/ui/offset_from.rs deleted file mode 100644 index aa59c119706ea..0000000000000 --- a/src/test/ui/offset_from.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -fn main() { - let mut a = [0; 5]; - let ptr1: *mut i32 = &mut a[1]; - let ptr2: *mut i32 = &mut a[3]; - unsafe { - assert_eq!(ptr2.offset_from(ptr1), 2); - assert_eq!(ptr1.offset_from(ptr2), -2); - assert_eq!(ptr1.offset(2), ptr2); - assert_eq!(ptr2.offset(-2), ptr1); - } -} diff --git a/src/test/ui/option-ext.rs b/src/test/ui/option-ext.rs deleted file mode 100644 index 76d0cf43984b3..0000000000000 --- a/src/test/ui/option-ext.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -pub fn main() { - let thing = "{{ f }}"; - let f = thing.find("{{"); - - if f.is_none() { - println!("None!"); - } -} diff --git a/src/test/ui/result-opt-conversions.rs b/src/test/ui/result-opt-conversions.rs deleted file mode 100644 index 57f258aab654a..0000000000000 --- a/src/test/ui/result-opt-conversions.rs +++ /dev/null @@ -1,47 +0,0 @@ -// run-pass - -#[derive(Copy, Clone, Debug, PartialEq)] -struct BadNumErr; - -fn try_num(x: i32) -> Result { - if x <= 5 { - Ok(x + 1) - } else { - Err(BadNumErr) - } -} - -type ResOpt = Result, BadNumErr>; -type OptRes = Option>; - -fn main() { - let mut x: ResOpt = Ok(Some(5)); - let mut y: OptRes = Some(Ok(5)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Ok(None); - y = None; - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - x = Err(BadNumErr); - y = Some(Err(BadNumErr)); - assert_eq!(x, y.transpose()); - assert_eq!(x.transpose(), y); - - let res: Result, BadNumErr> = - (0..10) - .map(|x| { - let y = try_num(x)?; - Ok(if y % 2 == 0 { - Some(y - 1) - } else { - None - }) - }) - .filter_map(Result::transpose) - .collect(); - - assert_eq!(res, Err(BadNumErr)) -} diff --git a/src/test/ui/utf8.rs b/src/test/ui/utf8.rs deleted file mode 100644 index 75b6ddf7895c7..0000000000000 --- a/src/test/ui/utf8.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -pub fn main() { - let yen: char = '¥'; // 0xa5 - let c_cedilla: char = 'ç'; // 0xe7 - let thorn: char = 'þ'; // 0xfe - let y_diaeresis: char = 'ÿ'; // 0xff - let pi: char = 'Π'; // 0x3a0 - - assert_eq!(yen as isize, 0xa5); - assert_eq!(c_cedilla as isize, 0xe7); - assert_eq!(thorn as isize, 0xfe); - assert_eq!(y_diaeresis as isize, 0xff); - assert_eq!(pi as isize, 0x3a0); - - assert_eq!(pi as isize, '\u{3a0}' as isize); - assert_eq!('\x0a' as isize, '\n' as isize); - - let bhutan: String = "འབྲུག་ཡུལ།".to_string(); - let japan: String = "日本".to_string(); - let uzbekistan: String = "Ўзбекистон".to_string(); - let austria: String = "Österreich".to_string(); - - let bhutan_e: String = - "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string(); - let japan_e: String = "\u{65e5}\u{672c}".to_string(); - let uzbekistan_e: String = - "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string(); - let austria_e: String = "\u{d6}sterreich".to_string(); - - let oo: char = 'Ö'; - assert_eq!(oo as isize, 0xd6); - - fn check_str_eq(a: String, b: String) { - let mut i: isize = 0; - for ab in a.bytes() { - println!("{}", i); - println!("{}", ab); - let bb: u8 = b.as_bytes()[i as usize]; - println!("{}", bb); - assert_eq!(ab, bb); - i += 1; - } - } - - check_str_eq(bhutan, bhutan_e); - check_str_eq(japan, japan_e); - check_str_eq(uzbekistan, uzbekistan_e); - check_str_eq(austria, austria_e); -} diff --git a/src/test/ui/utf8_chars.rs b/src/test/ui/utf8_chars.rs deleted file mode 100644 index d764509813de1..0000000000000 --- a/src/test/ui/utf8_chars.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -use std::str; - -pub fn main() { - // Chars of 1, 2, 3, and 4 bytes - let chs: Vec = vec!['e', 'é', '€', '\u{10000}']; - let s: String = chs.iter().cloned().collect(); - let schs: Vec = s.chars().collect(); - - assert_eq!(s.len(), 10); - assert_eq!(s.chars().count(), 4); - assert_eq!(schs.len(), 4); - assert_eq!(schs.iter().cloned().collect::(), s); - - assert!((str::from_utf8(s.as_bytes()).is_ok())); - // invalid prefix - assert!((!str::from_utf8(&[0x80]).is_ok())); - // invalid 2 byte prefix - assert!((!str::from_utf8(&[0xc0]).is_ok())); - assert!((!str::from_utf8(&[0xc0, 0x10]).is_ok())); - // invalid 3 byte prefix - assert!((!str::from_utf8(&[0xe0]).is_ok())); - assert!((!str::from_utf8(&[0xe0, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xe0, 0xff, 0x10]).is_ok())); - // invalid 4 byte prefix - assert!((!str::from_utf8(&[0xf0]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0xff, 0x10]).is_ok())); - assert!((!str::from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok())); -} diff --git a/src/test/ui/wrapping-int-api.rs b/src/test/ui/wrapping-int-api.rs deleted file mode 100644 index ecdd742fb4e08..0000000000000 --- a/src/test/ui/wrapping-int-api.rs +++ /dev/null @@ -1,228 +0,0 @@ -// run-pass -// Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}. - -// Don't warn about overflowing ops on 32-bit platforms -#![cfg_attr(target_pointer_width = "32", allow(const_err))] - -use std::{i8, i16, i32, i64, isize}; -use std::{u8, u16, u32, u64, usize}; - -fn main() { - assert_eq!( i8::MAX.wrapping_add(1), i8::MIN); - assert_eq!( i16::MAX.wrapping_add(1), i16::MIN); - assert_eq!( i32::MAX.wrapping_add(1), i32::MIN); - assert_eq!( i64::MAX.wrapping_add(1), i64::MIN); - assert_eq!(isize::MAX.wrapping_add(1), isize::MIN); - - assert_eq!( i8::MIN.wrapping_sub(1), i8::MAX); - assert_eq!( i16::MIN.wrapping_sub(1), i16::MAX); - assert_eq!( i32::MIN.wrapping_sub(1), i32::MAX); - assert_eq!( i64::MIN.wrapping_sub(1), i64::MAX); - assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX); - - assert_eq!( u8::MAX.wrapping_add(1), u8::MIN); - assert_eq!( u16::MAX.wrapping_add(1), u16::MIN); - assert_eq!( u32::MAX.wrapping_add(1), u32::MIN); - assert_eq!( u64::MAX.wrapping_add(1), u64::MIN); - assert_eq!(usize::MAX.wrapping_add(1), usize::MIN); - - assert_eq!( u8::MIN.wrapping_sub(1), u8::MAX); - assert_eq!( u16::MIN.wrapping_sub(1), u16::MAX); - assert_eq!( u32::MIN.wrapping_sub(1), u32::MAX); - assert_eq!( u64::MIN.wrapping_sub(1), u64::MAX); - assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX); - - assert_eq!((0xfe_u8 as i8).wrapping_mul(16), - (0xe0_u8 as i8)); - assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), - (0xedc0_u16 as i16)); - assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), - (0xedcb_a980_u32 as i32)); - assert_eq!((0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as i64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), - (0xedcb_a980_u32 as isize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!((0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16), - (0xedcb_a987_6543_2170_u64 as isize)); - } - } - - assert_eq!((0xfe as u8).wrapping_mul(16), - (0xe0 as u8)); - assert_eq!((0xfedc as u16).wrapping_mul(16), - (0xedc0 as u16)); - assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), - (0xedcb_a980 as u32)); - assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), - (0xedcb_a987_6543_2170 as u64)); - - match () { - #[cfg(target_pointer_width = "32")] - () => { - assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), - (0xedcb_a980 as usize)); - } - #[cfg(target_pointer_width = "64")] - () => { - assert_eq!((0xfedc_ba98_7654_3217 as usize).wrapping_mul(16), - (0xedcb_a987_6543_2170 as usize)); - } - } - - macro_rules! check_mul_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), ($e) * $f); } - } - macro_rules! check_mul_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), $e); } - } - - check_mul_no_wrap!(0xfe_u8 as i8, -1); - check_mul_no_wrap!(0xfedc_u16 as i16, -1); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_mul_no_wrap!(0xfe_u8 as i8, -2); - check_mul_no_wrap!(0xfedc_u16 as i16, -2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2); - - check_mul_no_wrap!(0xfe_u8 as i8, 2); - check_mul_no_wrap!(0xfedc_u16 as i16, 2); - check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2); - - check_mul_wraps!(0x80_u8 as i8, -1); - check_mul_wraps!(0x8000_u16 as i16, -1); - check_mul_wraps!(0x8000_0000_u32 as i32, -1); - check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_mul_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_div_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), ($e) / $f); } - } - macro_rules! check_div_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), $e); } - } - - check_div_no_wrap!(0xfe_u8 as i8, -1); - check_div_no_wrap!(0xfedc_u16 as i16, -1); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_div_no_wrap!(0xfe_u8 as i8, -2); - check_div_no_wrap!(0xfedc_u16 as i16, -2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_div_no_wrap!(0xfe_u8 as i8, 2); - check_div_no_wrap!(0xfedc_u16 as i16, 2); - check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_div_wraps!(-128 as i8, -1); - check_div_wraps!(0x8000_u16 as i16, -1); - check_div_wraps!(0x8000_0000_u32 as i32, -1); - check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_div_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - - macro_rules! check_rem_no_wrap { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), ($e) % $f); } - } - macro_rules! check_rem_wraps { - ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), 0); } - } - - check_rem_no_wrap!(0xfe_u8 as i8, -1); - check_rem_no_wrap!(0xfedc_u16 as i16, -1); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1); - - check_rem_no_wrap!(0xfe_u8 as i8, -2); - check_rem_no_wrap!(0xfedc_u16 as i16, -2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2); - - check_rem_no_wrap!(0xfe_u8 as i8, 2); - check_rem_no_wrap!(0xfedc_u16 as i16, 2); - check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2); - check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2); - - check_rem_wraps!(0x80_u8 as i8, -1); - check_rem_wraps!(0x8000_u16 as i16, -1); - check_rem_wraps!(0x8000_0000_u32 as i32, -1); - check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_rem_wraps!(0x8000_0000_u32 as isize, -1); - } - #[cfg(target_pointer_width = "64")] - () => { - check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1); - } - } - - macro_rules! check_neg_no_wrap { - ($e:expr) => { assert_eq!(($e).wrapping_neg(), -($e)); } - } - macro_rules! check_neg_wraps { - ($e:expr) => { assert_eq!(($e).wrapping_neg(), ($e)); } - } - - check_neg_no_wrap!(0xfe_u8 as i8); - check_neg_no_wrap!(0xfedc_u16 as i16); - check_neg_no_wrap!(0xfedc_ba98_u32 as i32); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64); - check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize); - - check_neg_wraps!(0x80_u8 as i8); - check_neg_wraps!(0x8000_u16 as i16); - check_neg_wraps!(0x8000_0000_u32 as i32); - check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64); - match () { - #[cfg(target_pointer_width = "32")] - () => { - check_neg_wraps!(0x8000_0000_u32 as isize); - } - #[cfg(target_pointer_width = "64")] - () => { - check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize); - } - } - -} From 7b62e09b0333e268e5546d52f2072eb340cec7ea Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Tue, 24 Nov 2020 00:55:10 +0100 Subject: [PATCH 118/118] Allow disabling TrapUnreachable via -Ztrap-unreachable=no This is useful for embedded targets where small code size is desired. For example, on my project (thumbv7em-none-eabi) this yields a 0.6% code size reduction. --- compiler/rustc_codegen_llvm/src/back/write.rs | 3 ++- compiler/rustc_interface/src/tests.rs | 1 + compiler/rustc_session/src/options.rs | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 6f956c3bcc1ce..7407dfc455d84 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -152,7 +152,8 @@ pub fn target_machine_factory( let features = features.join(","); let features = CString::new(features).unwrap(); let abi = SmallCStr::new(&sess.target.llvm_abiname); - let trap_unreachable = sess.target.trap_unreachable; + let trap_unreachable = + sess.opts.debugging_opts.trap_unreachable.unwrap_or(sess.target.trap_unreachable); let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; let asm_comments = sess.asm_comments(); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 1fc2d281e7935..a47f21e47b54a 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -592,6 +592,7 @@ fn test_debugging_options_tracking_hash() { tracked!(thinlto, Some(true)); tracked!(tune_cpu, Some(String::from("abc"))); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); + tracked!(trap_unreachable, Some(false)); tracked!(treat_err_as_bug, Some(1)); tracked!(unleash_the_miri_inside_of_you, true); tracked!(use_ctors_section, Some(true)); diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1cd3d11e32153..c203dcf358d06 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1113,6 +1113,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "choose the TLS model to use (`rustc --print tls-models` for details)"), trace_macros: bool = (false, parse_bool, [UNTRACKED], "for every macro invocation, print its name and arguments (default: no)"), + trap_unreachable: Option = (None, parse_opt_bool, [TRACKED], + "generate trap instructions for unreachable intrinsics (default: use target setting, usually yes)"), treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], "treat error number `val` that occurs as bug"), trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED],