about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTakayuki Nakata <f.seasons017@gmail.com>2020-11-27 10:25:07 +0900
committerTakayuki Nakata <f.seasons017@gmail.com>2020-11-27 10:25:07 +0900
commit0924d6286aa56dd9c6759f2c06c9148ce92d857a (patch)
tree9ccabcf9dd71fa234d1d9929a82e65b6b524d4d1
parentf303168a0d374c7e6d0b0aa9fd7852042602f791 (diff)
parent403816fbc95526ba6111734f4931c69caff61b13 (diff)
downloadrust-0924d6286aa56dd9c6759f2c06c9148ce92d857a.tar.gz
rust-0924d6286aa56dd9c6759f2c06c9148ce92d857a.zip
Merge remote-tracking branch 'upstream/master' into sync-from-rust
-rw-r--r--README.md26
-rw-r--r--clippy_lints/src/deprecated_lints.rs20
-rw-r--r--clippy_lints/src/future_not_send.rs9
-rw-r--r--clippy_lints/src/lib.rs45
-rw-r--r--clippy_lints/src/loops.rs34
-rw-r--r--clippy_lints/src/manual_non_exhaustive.rs33
-rw-r--r--clippy_lints/src/manual_strip.rs34
-rw-r--r--clippy_lints/src/matches.rs66
-rw-r--r--clippy_lints/src/methods/mod.rs43
-rw-r--r--clippy_lints/src/strings.rs100
-rw-r--r--clippy_lints/src/types.rs12
-rw-r--r--clippy_lints/src/utils/attrs.rs19
-rw-r--r--clippy_lints/src/utils/conf.rs2
-rw-r--r--clippy_lints/src/utils/mod.rs45
-rw-r--r--clippy_lints/src/utils/paths.rs2
-rw-r--r--tests/ui-toml/invalid_min_rust_version/clippy.toml1
-rw-r--r--tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs3
-rw-r--r--tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr4
-rw-r--r--tests/ui-toml/min_rust_version/clippy.toml1
-rw-r--r--tests/ui-toml/min_rust_version/min_rust_version.rs68
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--tests/ui/as_conversions.rs14
-rw-r--r--tests/ui/as_conversions.stderr6
-rw-r--r--tests/ui/auxiliary/macro_rules.rs14
-rw-r--r--tests/ui/deprecated.rs2
-rw-r--r--tests/ui/deprecated.stderr46
-rw-r--r--tests/ui/deprecated_old.rs2
-rw-r--r--tests/ui/deprecated_old.stderr30
-rw-r--r--tests/ui/min_rust_version_attr.rs51
-rw-r--r--tests/ui/min_rust_version_invalid_attr.rs4
-rw-r--r--tests/ui/min_rust_version_invalid_attr.stderr8
-rw-r--r--tests/ui/min_rust_version_multiple_inner_attr.rs11
-rw-r--r--tests/ui/min_rust_version_multiple_inner_attr.stderr38
-rw-r--r--tests/ui/min_rust_version_no_patch.rs14
-rw-r--r--tests/ui/min_rust_version_outer_attr.rs4
-rw-r--r--tests/ui/min_rust_version_outer_attr.stderr8
-rw-r--r--tests/ui/needless_collect_indirect.rs20
-rw-r--r--tests/ui/redundant_pattern_matching_option.fixed8
-rw-r--r--tests/ui/redundant_pattern_matching_option.rs8
-rw-r--r--tests/ui/redundant_pattern_matching_option.stderr38
-rw-r--r--tests/ui/redundant_pattern_matching_poll.fixed73
-rw-r--r--tests/ui/redundant_pattern_matching_poll.rs88
-rw-r--r--tests/ui/redundant_pattern_matching_poll.stderr128
-rw-r--r--tests/ui/redundant_pattern_matching_result.fixed (renamed from tests/ui/redundant_pattern_matching.fixed)1
-rw-r--r--tests/ui/redundant_pattern_matching_result.rs (renamed from tests/ui/redundant_pattern_matching.rs)1
-rw-r--r--tests/ui/redundant_pattern_matching_result.stderr (renamed from tests/ui/redundant_pattern_matching.stderr)44
-rw-r--r--tests/ui/str_to_string.rs7
-rw-r--r--tests/ui/str_to_string.stderr19
-rw-r--r--tests/ui/string_to_string.rs7
-rw-r--r--tests/ui/string_to_string.stderr11
-rw-r--r--tests/ui/temporary_assignment.rs1
-rw-r--r--tests/ui/temporary_assignment.stderr8
-rw-r--r--tests/ui/unnecessary_cast.rs3
-rw-r--r--tests/ui/unnecessary_cast_fixable.fixed2
-rw-r--r--tests/ui/unnecessary_cast_fixable.rs2
-rw-r--r--tests/ui/unnecessary_cast_fixable.stderr32
-rw-r--r--tests/ui/wildcard_enum_match_arm.fixed3
-rw-r--r--tests/ui/wildcard_enum_match_arm.rs3
-rw-r--r--tests/ui/wildcard_enum_match_arm.stderr10
-rwxr-xr-xutil/dev7
60 files changed, 1129 insertions, 216 deletions
diff --git a/README.md b/README.md
index 1da626b505d..35683e87133 100644
--- a/README.md
+++ b/README.md
@@ -194,6 +194,32 @@ cargo clippy -- -A clippy::all -W clippy::useless_format -W clippy::...
 ```
 Note that if you've run clippy before, this may only take effect after you've modified a file or ran `cargo clean`.
 
+### Specifying the minimum supported Rust version
+
+Projects that intend to support old versions of Rust can disable lints pertaining to newer features by
+specifying the minimum supported Rust version (MSRV) in the clippy configuration file.
+
+```toml
+msrv = "1.30.0"
+```
+
+The MSRV can also be specified as an inner attribute, like below.
+
+```rust
+#![feature(custom_inner_attributes)]
+#![clippy::msrv = "1.30.0"]
+
+fn main() {
+  ...
+}
+```
+
+Tilde/Caret version requirements (like `^1.0` or `~1.2`) can be specified as well.
+
+Note: `custom_inner_attributes` is an unstable feature so it has to be enabled explicitly.
+
+Lints that recognize this configuration option can be found [here](https://rust-lang.github.io/rust-clippy/master/index.html#msrv)
+
 ## Contributing
 
 If you want to contribute to Clippy, you can find more information in [CONTRIBUTING.md](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md).
diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs
index 1c3285ed701..bec0c9f93a0 100644
--- a/clippy_lints/src/deprecated_lints.rs
+++ b/clippy_lints/src/deprecated_lints.rs
@@ -54,26 +54,6 @@ declare_deprecated_lint! {
 declare_deprecated_lint! {
     /// **What it does:** Nothing. This lint has been deprecated.
     ///
-    /// **Deprecation reason:** This used to check for `.to_string()` method calls on values
-    /// of type `&str`. This is not unidiomatic and with specialization coming, `to_string` could be
-    /// specialized to be as efficient as `to_owned`.
-    pub STR_TO_STRING,
-    "using `str::to_string` is common even today and specialization will likely happen soon"
-}
-
-declare_deprecated_lint! {
-    /// **What it does:** Nothing. This lint has been deprecated.
-    ///
-    /// **Deprecation reason:** This used to check for `.to_string()` method calls on values
-    /// of type `String`. This is not unidiomatic and with specialization coming, `to_string` could be
-    /// specialized to be as efficient as `clone`.
-    pub STRING_TO_STRING,
-    "using `string::to_string` is common even today and specialization will likely happen soon"
-}
-
-declare_deprecated_lint! {
-    /// **What it does:** Nothing. This lint has been deprecated.
-    ///
     /// **Deprecation reason:** This lint should never have applied to non-pointer types, as transmuting
     /// between non-pointer types of differing alignment is well-defined behavior (it's semantically
     /// equivalent to a memcpy). This lint has thus been refactored into two separate lints:
diff --git a/clippy_lints/src/future_not_send.rs b/clippy_lints/src/future_not_send.rs
index f9697afe405..eb5857348fd 100644
--- a/clippy_lints/src/future_not_send.rs
+++ b/clippy_lints/src/future_not_send.rs
@@ -92,13 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
                         |db| {
                             cx.tcx.infer_ctxt().enter(|infcx| {
                                 for FulfillmentError { obligation, .. } in send_errors {
-                                    infcx.maybe_note_obligation_cause_for_async_await(
-                                        db,
-                                        &obligation,
-                                    );
-                                    if let Trait(trait_pred, _) =
-                                        obligation.predicate.skip_binders()
-                                    {
+                                    infcx.maybe_note_obligation_cause_for_async_await(db, &obligation);
+                                    if let Trait(trait_pred, _) = obligation.predicate.skip_binders() {
                                         db.note(&format!(
                                             "`{}` doesn't implement `{}`",
                                             trait_pred.self_ty(),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 7e8cbd00c22..67a3a3fcf48 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -44,6 +44,7 @@ extern crate rustc_target;
 extern crate rustc_trait_selection;
 extern crate rustc_typeck;
 
+use crate::utils::parse_msrv;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::LintId;
 use rustc_session::Session;
@@ -441,14 +442,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         "`Vec::as_mut_slice` has been stabilized in 1.7",
     );
     store.register_removed(
-        "clippy::str_to_string",
-        "using `str::to_string` is common even today and specialization will likely happen soon",
-    );
-    store.register_removed(
-        "clippy::string_to_string",
-        "using `string::to_string` is common even today and specialization will likely happen soon",
-    );
-    store.register_removed(
         "clippy::misaligned_transmute",
         "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
     );
@@ -839,6 +832,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &strings::STRING_ADD_ASSIGN,
         &strings::STRING_FROM_UTF8_AS_BYTES,
         &strings::STRING_LIT_AS_BYTES,
+        &strings::STRING_TO_STRING,
+        &strings::STR_TO_STRING,
         &suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL,
         &suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL,
         &swap::ALMOST_SWAPPED,
@@ -933,7 +928,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &zero_div_zero::ZERO_DIVIDED_BY_ZERO,
     ]);
     // end register lints, do not remove this comment, it’s used in `update_lints`
-
     store.register_late_pass(|| box await_holding_invalid::AwaitHolding);
     store.register_late_pass(|| box serde_api::SerdeAPI);
     store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new());
@@ -969,7 +963,23 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box strings::StringAdd);
     store.register_late_pass(|| box implicit_return::ImplicitReturn);
     store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub);
-    store.register_late_pass(|| box methods::Methods);
+
+    let parsed_msrv = conf.msrv.as_ref().and_then(|s| {
+        parse_msrv(s, None, None).or_else(|| {
+            sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s));
+            None
+        })
+    });
+
+    let msrv = parsed_msrv.clone();
+    store.register_late_pass(move || box methods::Methods::new(msrv.clone()));
+    let msrv = parsed_msrv.clone();
+    store.register_late_pass(move || box matches::Matches::new(msrv.clone()));
+    let msrv = parsed_msrv.clone();
+    store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv.clone()));
+    let msrv = parsed_msrv;
+    store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv.clone()));
+
     store.register_late_pass(|| box map_clone::MapClone);
     store.register_late_pass(|| box map_err_ignore::MapErrIgnore);
     store.register_late_pass(|| box shadow::Shadow);
@@ -983,7 +993,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box types::Casts);
     let type_complexity_threshold = conf.type_complexity_threshold;
     store.register_late_pass(move || box types::TypeComplexity::new(type_complexity_threshold));
-    store.register_late_pass(|| box matches::Matches::default());
     store.register_late_pass(|| box minmax::MinMaxPass);
     store.register_late_pass(|| box open_options::OpenOptions);
     store.register_late_pass(|| box zero_div_zero::ZeroDiv);
@@ -1144,7 +1153,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box if_let_mutex::IfLetMutex);
     store.register_late_pass(|| box mut_mutex_lock::MutMutexLock);
     store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
-    store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive);
     store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
     store.register_early_pass(|| box redundant_field_names::RedundantFieldNames);
     store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero);
@@ -1166,13 +1174,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     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);
     store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem);
     let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>();
     store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
     store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
     store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
     store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops);
+    store.register_late_pass(|| box strings::StrToString);
+    store.register_late_pass(|| box strings::StringToString);
 
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
@@ -1215,6 +1224,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&shadow::SHADOW_REUSE),
         LintId::of(&shadow::SHADOW_SAME),
         LintId::of(&strings::STRING_ADD),
+        LintId::of(&strings::STRING_TO_STRING),
+        LintId::of(&strings::STR_TO_STRING),
         LintId::of(&types::RC_BUFFER),
         LintId::of(&unwrap_in_result::UNWRAP_IN_RESULT),
         LintId::of(&verbose_file_reads::VERBOSE_FILE_READS),
@@ -1931,14 +1942,6 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
         "`Vec::as_mut_slice` has been stabilized in 1.7",
     );
     store.register_removed(
-        "str_to_string",
-        "using `str::to_string` is common even today and specialization will likely happen soon",
-    );
-    store.register_removed(
-        "string_to_string",
-        "using `string::to_string` is common even today and specialization will likely happen soon",
-    );
-    store.register_removed(
         "misaligned_transmute",
         "this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr",
     );
diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs
index 0d31e9cfc3d..143cbea5537 100644
--- a/clippy_lints/src/loops.rs
+++ b/clippy_lints/src/loops.rs
@@ -2950,7 +2950,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
         for ref stmt in block.stmts {
             if_chain! {
                 if let StmtKind::Local(
-                    Local { pat: Pat { kind: PatKind::Binding(_, _, ident, .. ), .. },
+                    Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
                     init: Some(ref init_expr), .. }
                 ) = stmt.kind;
                 if let ExprKind::MethodCall(ref method_name, _, &[ref iter_source], ..) = init_expr.kind;
@@ -2964,6 +2964,16 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo
                 if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
                 if iter_calls.len() == 1;
                 then {
+                    let mut used_count_visitor = UsedCountVisitor {
+                        cx,
+                        id: *pat_id,
+                        count: 0,
+                    };
+                    walk_block(&mut used_count_visitor, block);
+                    if used_count_visitor.count > 1 {
+                        return;
+                    }
+
                     // Suggest replacing iter_call with iter_replacement, and removing stmt
                     let iter_call = &iter_calls[0];
                     span_lint_and_then(
@@ -3087,6 +3097,28 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
     }
 }
 
+struct UsedCountVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    id: HirId,
+    count: usize,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
+    type Map = Map<'tcx>;
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
+        if same_var(self.cx, expr, self.id) {
+            self.count += 1;
+        } else {
+            walk_expr(self, expr);
+        }
+    }
+
+    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    }
+}
+
 /// 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<Vec<IterFunction>> {
diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs
index a1450b0d5fe..703e6feeca5 100644
--- a/clippy_lints/src/manual_non_exhaustive.rs
+++ b/clippy_lints/src/manual_non_exhaustive.rs
@@ -1,11 +1,20 @@
-use crate::utils::{snippet_opt, span_lint_and_then};
+use crate::utils::{meets_msrv, snippet_opt, span_lint_and_then};
 use if_chain::if_chain;
 use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind};
 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_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Span};
+use semver::{Version, VersionReq};
+
+const MANUAL_NON_EXHAUSTIVE_MSRV: Version = Version {
+    major: 1,
+    minor: 40,
+    patch: 0,
+    pre: Vec::new(),
+    build: Vec::new(),
+};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for manual implementations of the non-exhaustive pattern.
@@ -55,10 +64,26 @@ declare_clippy_lint! {
     "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
 }
 
-declare_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
+#[derive(Clone)]
+pub struct ManualNonExhaustive {
+    msrv: Option<VersionReq>,
+}
+
+impl ManualNonExhaustive {
+    #[must_use]
+    pub fn new(msrv: Option<VersionReq>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
 
 impl EarlyLintPass for ManualNonExhaustive {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        if !meets_msrv(self.msrv.as_ref(), &MANUAL_NON_EXHAUSTIVE_MSRV) {
+            return;
+        }
+
         match &item.kind {
             ItemKind::Enum(def, _) => {
                 check_manual_non_exhaustive_enum(cx, item, &def.variants);
@@ -73,6 +98,8 @@ impl EarlyLintPass for ManualNonExhaustive {
             _ => {},
         }
     }
+
+    extract_msrv_attr!(EarlyContext);
 }
 
 fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) {
diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs
index 4afb0ab3bad..e17e3adb94f 100644
--- a/clippy_lints/src/manual_strip.rs
+++ b/clippy_lints/src/manual_strip.rs
@@ -1,7 +1,7 @@
 use crate::consts::{constant, Constant};
 use crate::utils::usage::mutated_variables;
 use crate::utils::{
-    eq_expr_value, higher, match_def_path, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
+    eq_expr_value, higher, match_def_path, meets_msrv, multispan_sugg, paths, qpath_res, snippet, span_lint_and_then,
 };
 
 use if_chain::if_chain;
@@ -10,12 +10,21 @@ use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::BinOpKind;
 use rustc_hir::{BorrowKind, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Spanned;
 use rustc_span::Span;
+use semver::{Version, VersionReq};
+
+const MANUAL_STRIP_MSRV: Version = Version {
+    major: 1,
+    minor: 45,
+    patch: 0,
+    pre: Vec::new(),
+    build: Vec::new(),
+};
 
 declare_clippy_lint! {
     /// **What it does:**
@@ -51,7 +60,18 @@ declare_clippy_lint! {
     "suggests using `strip_{prefix,suffix}` over `str::{starts,ends}_with` and slicing"
 }
 
-declare_lint_pass!(ManualStrip => [MANUAL_STRIP]);
+pub struct ManualStrip {
+    msrv: Option<VersionReq>,
+}
+
+impl ManualStrip {
+    #[must_use]
+    pub fn new(msrv: Option<VersionReq>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(ManualStrip => [MANUAL_STRIP]);
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 enum StripKind {
@@ -61,6 +81,10 @@ enum StripKind {
 
 impl<'tcx> LateLintPass<'tcx> for ManualStrip {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !meets_msrv(self.msrv.as_ref(), &MANUAL_STRIP_MSRV) {
+            return;
+        }
+
         if_chain! {
             if let Some((cond, then, _)) = higher::if_block(&expr);
             if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind;
@@ -114,6 +138,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise.
diff --git a/clippy_lints/src/matches.rs b/clippy_lints/src/matches.rs
index c6dca54e250..d695af4de21 100644
--- a/clippy_lints/src/matches.rs
+++ b/clippy_lints/src/matches.rs
@@ -3,8 +3,8 @@ use crate::utils::sugg::Sugg;
 use crate::utils::usage::is_unused;
 use crate::utils::{
     expr_block, get_arg_name, get_parent_expr, in_macro, indent_of, is_allowed, is_expn_of, is_refutable,
-    is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, multispan_sugg, remove_blocks, snippet,
-    snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
+    is_type_diagnostic_item, is_wild, match_qpath, match_type, match_var, meets_msrv, multispan_sugg, remove_blocks,
+    snippet, snippet_block, snippet_with_applicability, span_lint_and_help, span_lint_and_note, span_lint_and_sugg,
     span_lint_and_then,
 };
 use crate::utils::{paths, search_same, SpanlessEq, SpanlessHash};
@@ -23,6 +23,7 @@ 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::{sym, Symbol};
+use semver::{Version, VersionReq};
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry;
 use std::collections::Bound;
@@ -411,8 +412,8 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Lint for redundant pattern matching over `Result` or
-    /// `Option`
+    /// **What it does:** Lint for redundant pattern matching over `Result`, `Option` or
+    /// `std::task::Poll`
     ///
     /// **Why is this bad?** It's more concise and clear to just use the proper
     /// utility function
@@ -422,10 +423,13 @@ declare_clippy_lint! {
     /// **Example:**
     ///
     /// ```rust
+    /// # use std::task::Poll;
     /// if let Ok(_) = Ok::<i32, i32>(42) {}
     /// if let Err(_) = Err::<i32, i32>(42) {}
     /// if let None = None::<()> {}
     /// if let Some(_) = Some(42) {}
+    /// if let Poll::Pending = Poll::Pending::<()> {}
+    /// if let Poll::Ready(_) = Poll::Ready(42) {}
     /// match Ok::<i32, i32>(42) {
     ///     Ok(_) => true,
     ///     Err(_) => false,
@@ -435,10 +439,13 @@ declare_clippy_lint! {
     /// The more idiomatic use would be:
     ///
     /// ```rust
+    /// # use std::task::Poll;
     /// if Ok::<i32, i32>(42).is_ok() {}
     /// if Err::<i32, i32>(42).is_err() {}
     /// if None::<()>.is_none() {}
     /// if Some(42).is_some() {}
+    /// if Poll::Pending::<()>.is_pending() {}
+    /// if Poll::Ready(42).is_ready() {}
     /// Ok::<i32, i32>(42).is_ok();
     /// ```
     pub REDUNDANT_PATTERN_MATCHING,
@@ -521,9 +528,20 @@ declare_clippy_lint! {
 
 #[derive(Default)]
 pub struct Matches {
+    msrv: Option<VersionReq>,
     infallible_destructuring_match_linted: bool,
 }
 
+impl Matches {
+    #[must_use]
+    pub fn new(msrv: Option<VersionReq>) -> Self {
+        Self {
+            msrv,
+            ..Matches::default()
+        }
+    }
+}
+
 impl_lint_pass!(Matches => [
     SINGLE_MATCH,
     MATCH_REF_PATS,
@@ -543,6 +561,14 @@ impl_lint_pass!(Matches => [
     MATCH_SAME_ARMS,
 ]);
 
+const MATCH_LIKE_MATCHES_MACRO_MSRV: Version = Version {
+    major: 1,
+    minor: 42,
+    patch: 0,
+    pre: Vec::new(),
+    build: Vec::new(),
+};
+
 impl<'tcx> LateLintPass<'tcx> for Matches {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if in_external_macro(cx.sess(), expr.span) || in_macro(expr.span) {
@@ -550,7 +576,12 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         }
 
         redundant_pattern_match::check(cx, expr);
-        if !check_match_like_matches(cx, expr) {
+
+        if meets_msrv(self.msrv.as_ref(), &MATCH_LIKE_MATCHES_MACRO_MSRV) {
+            if !check_match_like_matches(cx, expr) {
+                lint_match_arms(cx, expr);
+            }
+        } else {
             lint_match_arms(cx, expr);
         }
 
@@ -634,6 +665,8 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 #[rustfmt::skip]
@@ -1538,6 +1571,8 @@ mod redundant_pattern_match {
                         "is_err()"
                     } else if match_qpath(path, &paths::OPTION_SOME) {
                         "is_some()"
+                    } else if match_qpath(path, &paths::POLL_READY) {
+                        "is_ready()"
                     } else {
                         return;
                     }
@@ -1545,7 +1580,15 @@ mod redundant_pattern_match {
                     return;
                 }
             },
-            PatKind::Path(ref path) if match_qpath(path, &paths::OPTION_NONE) => "is_none()",
+            PatKind::Path(ref path) => {
+                if match_qpath(path, &paths::OPTION_NONE) {
+                    "is_none()"
+                } else if match_qpath(path, &paths::POLL_PENDING) {
+                    "is_pending()"
+                } else {
+                    return;
+                }
+            },
             _ => return,
         };
 
@@ -1628,6 +1671,17 @@ mod redundant_pattern_match {
                             "is_some()",
                             "is_none()",
                         )
+                        .or_else(|| {
+                            find_good_method_for_match(
+                                arms,
+                                path_left,
+                                path_right,
+                                &paths::POLL_READY,
+                                &paths::POLL_PENDING,
+                                "is_ready()",
+                                "is_pending()",
+                            )
+                        })
                     } else {
                         None
                     }
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index fa174404365..50dd760432d 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -20,7 +20,7 @@ use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, TraitRef, Ty, TyS};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{sym, SymbolStr};
 
@@ -30,10 +30,11 @@ use crate::utils::usage::mutated_variables;
 use crate::utils::{
     contains_ty, get_arg_name, get_parent_expr, get_trait_def_id, has_iter_method, higher, implements_trait, in_macro,
     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,
+    match_trait_method, match_type, match_var, meets_msrv, 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_sugg, span_lint_and_then, sugg, walk_ptrs_ty_depth, SpanlessEq,
 };
+use semver::{Version, VersionReq};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `.unwrap()` calls on `Option`s and on `Result`s.
@@ -1404,7 +1405,18 @@ declare_clippy_lint! {
     "use `.collect()` instead of `::from_iter()`"
 }
 
-declare_lint_pass!(Methods => [
+pub struct Methods {
+    msrv: Option<VersionReq>,
+}
+
+impl Methods {
+    #[must_use]
+    pub fn new(msrv: Option<VersionReq>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(Methods => [
     UNWRAP_USED,
     EXPECT_USED,
     SHOULD_IMPLEMENT_TRAIT,
@@ -1531,8 +1543,12 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 check_pointer_offset(cx, expr, arg_lists[0])
             },
             ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
-            ["map", "as_ref"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false),
-            ["map", "as_mut"] => lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true),
+            ["map", "as_ref"] => {
+                lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref())
+            },
+            ["map", "as_mut"] => {
+                lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref())
+            },
             ["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"),
@@ -1738,6 +1754,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 /// Checks for the `OR_FUN_CALL` lint.
@@ -3453,6 +3471,14 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
     );
 }
 
+const OPTION_AS_REF_DEREF_MSRV: Version = Version {
+    major: 1,
+    minor: 40,
+    patch: 0,
+    pre: Vec::new(),
+    build: Vec::new(),
+};
+
 /// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
 fn lint_option_as_ref_deref<'tcx>(
     cx: &LateContext<'tcx>,
@@ -3460,7 +3486,12 @@ fn lint_option_as_ref_deref<'tcx>(
     as_ref_args: &[hir::Expr<'_>],
     map_args: &[hir::Expr<'_>],
     is_mut: bool,
+    msrv: Option<&VersionReq>,
 ) {
+    if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) {
+        return;
+    }
+
     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]);
diff --git a/clippy_lints/src/strings.rs b/clippy_lints/src/strings.rs
index ede37624f71..42c45be3b45 100644
--- a/clippy_lints/src/strings.rs
+++ b/clippy_lints/src/strings.rs
@@ -2,6 +2,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, LangItem, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 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::Spanned;
 use rustc_span::sym;
@@ -11,7 +12,7 @@ use if_chain::if_chain;
 use crate::utils::SpanlessEq;
 use crate::utils::{
     get_parent_expr, is_allowed, is_type_diagnostic_item, match_function_call, method_calls, paths, span_lint,
-    span_lint_and_sugg,
+    span_lint_and_help, span_lint_and_sugg,
 };
 
 declare_clippy_lint! {
@@ -289,3 +290,100 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
         }
     }
 }
+
+declare_clippy_lint! {
+    /// **What it does:** This lint checks for `.to_string()` method calls on values of type `&str`.
+    ///
+    /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string.
+    /// When called on a `&str` it turns the `&str` into the owned variant `String`, which can be better
+    /// expressed with `.to_owned()`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // example code where clippy issues a warning
+    /// let _ = "str".to_string();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// // example code which does not raise clippy warning
+    /// let _ = "str".to_owned();
+    /// ```
+    pub STR_TO_STRING,
+    restriction,
+    "using `to_string()` on a `&str`, which should be `to_owned()`"
+}
+
+declare_lint_pass!(StrToString => [STR_TO_STRING]);
+
+impl LateLintPass<'_> for StrToString {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if_chain! {
+            if let ExprKind::MethodCall(path, _, args, _) = &expr.kind;
+            if path.ident.name == sym!(to_string);
+            let ty = cx.typeck_results().expr_ty(&args[0]);
+            if let ty::Ref(_, ty, ..) = ty.kind();
+            if *ty.kind() == ty::Str;
+            then {
+                span_lint_and_help(
+                    cx,
+                    STR_TO_STRING,
+                    expr.span,
+                    "`to_string()` called on a `&str`",
+                    None,
+                    "consider using `.to_owned()`",
+                );
+            }
+        }
+    }
+}
+
+declare_clippy_lint! {
+    /// **What it does:** This lint checks for `.to_string()` method calls on values of type `String`.
+    ///
+    /// **Why is this bad?** The `to_string` method is also used on other types to convert them to a string.
+    /// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`.
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// // example code where clippy issues a warning
+    /// let msg = String::from("Hello World");
+    /// let _ = msg.to_string();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// // example code which does not raise clippy warning
+    /// let msg = String::from("Hello World");
+    /// let _ = msg.clone();
+    /// ```
+    pub STRING_TO_STRING,
+    restriction,
+    "using `to_string()` on a `String`, which should be `clone()`"
+}
+
+declare_lint_pass!(StringToString => [STRING_TO_STRING]);
+
+impl LateLintPass<'_> for StringToString {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if_chain! {
+            if let ExprKind::MethodCall(path, _, args, _) = &expr.kind;
+            if path.ident.name == sym!(to_string);
+            let ty = cx.typeck_results().expr_ty(&args[0]);
+            if is_type_diagnostic_item(cx, ty, sym!(string_type));
+            then {
+                span_lint_and_help(
+                    cx,
+                    STRING_TO_STRING,
+                    expr.span,
+                    "`to_string()` called on a `String`",
+                    None,
+                    "consider using `.clone()`",
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/types.rs b/clippy_lints/src/types.rs
index f0e10e374e1..c8bdc5a71e6 100644
--- a/clippy_lints/src/types.rs
+++ b/clippy_lints/src/types.rs
@@ -8,6 +8,7 @@ use if_chain::if_chain;
 use rustc_ast::{FloatTy, IntTy, LitFloatType, LitIntType, LitKind, UintTy};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
+use rustc_hir::def::Res;
 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, GenericBounds, GenericParamKind, HirId,
@@ -1632,7 +1633,14 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
         if expr.span.from_expansion() {
             return;
         }
-        if let ExprKind::Cast(ref ex, _) = expr.kind {
+        if let ExprKind::Cast(ref ex, cast_to) = expr.kind {
+            if let TyKind::Path(QPath::Resolved(_, path)) = cast_to.kind {
+                if let Res::Def(_, def_id) = path.res {
+                    if cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr) {
+                        return;
+                    }
+                }
+            }
             let (cast_from, cast_to) = (cx.typeck_results().expr_ty(ex), cx.typeck_results().expr_ty(expr));
             lint_fn_to_numeric_cast(cx, expr, ex, cast_from, cast_to);
             if let Some(lit) = get_numeric_literal(ex) {
@@ -1711,7 +1719,7 @@ fn show_unnecessary_cast(cx: &LateContext<'_>, expr: &Expr<'_>, literal_str: &st
         expr.span,
         &format!("casting {} literal to `{}` is unnecessary", literal_kind_name, cast_to),
         "try",
-        format!("{}_{}", literal_str, cast_to),
+        format!("{}_{}", literal_str.trim_end_matches('.'), cast_to),
         Applicability::MachineApplicable,
     );
 }
diff --git a/clippy_lints/src/utils/attrs.rs b/clippy_lints/src/utils/attrs.rs
index e6d41341a55..24052a243af 100644
--- a/clippy_lints/src/utils/attrs.rs
+++ b/clippy_lints/src/utils/attrs.rs
@@ -21,6 +21,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, DeprecationStatus)] = &[
         DeprecationStatus::Replaced("cognitive_complexity"),
     ),
     ("dump", DeprecationStatus::None),
+    ("msrv", DeprecationStatus::None),
 ];
 
 pub struct LimitStack {
@@ -123,6 +124,24 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
     }
 }
 
+pub fn get_unique_inner_attr(sess: &Session, attrs: &[ast::Attribute], name: &'static str) -> Option<ast::Attribute> {
+    let mut unique_attr = None;
+    for attr in get_attr(sess, attrs, name) {
+        match attr.style {
+            ast::AttrStyle::Inner if unique_attr.is_none() => unique_attr = Some(attr.clone()),
+            ast::AttrStyle::Inner => {
+                sess.struct_span_err(attr.span, &format!("`{}` is defined multiple times", name))
+                    .span_note(unique_attr.as_ref().unwrap().span, "first definition found here")
+                    .emit();
+            },
+            ast::AttrStyle::Outer => {
+                sess.span_err(attr.span, &format!("`{}` cannot be an outer attribute", name));
+            },
+        }
+    }
+    unique_attr
+}
+
 /// Return true if the attributes contain any of `proc_macro`,
 /// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
 pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 0ac8fff69f0..fc6304118d9 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -106,6 +106,8 @@ macro_rules! define_Conf {
 
 pub use self::helpers::Conf;
 define_Conf! {
+    /// Lint: MANUAL_NON_EXHAUSTIVE, MANUAL_STRIP, OPTION_AS_REF_DEREF, MATCH_LIKE_MATCHES_MACRO. The minimum rust version that the project supports
+    (msrv, "msrv": Option<String>, None),
     /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses
     (blacklisted_names, "blacklisted_names": Vec<String>, ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()),
     /// Lint: COGNITIVE_COMPLEXITY. The maximum cognitive complexity a function can have
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index e9c71e23a67..6f89e51279a 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -51,6 +51,7 @@ use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, layout::IntegerExt, Ty, TyCtxt, TypeFoldable};
+use rustc_session::Session;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::sym as rustc_sym;
@@ -58,10 +59,54 @@ use rustc_span::symbol::{self, kw, Symbol};
 use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
 use rustc_target::abi::Integer;
 use rustc_trait_selection::traits::query::normalize::AtExt;
+use semver::{Version, VersionReq};
 use smallvec::SmallVec;
 
 use crate::consts::{constant, Constant};
 
+pub fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<VersionReq> {
+    if let Ok(version) = VersionReq::parse(msrv) {
+        return Some(version);
+    } else if let Some(sess) = sess {
+        if let Some(span) = span {
+            sess.span_err(span, &format!("`{}` is not a valid Rust version", msrv));
+        }
+    }
+    None
+}
+
+pub fn meets_msrv(msrv: Option<&VersionReq>, lint_msrv: &Version) -> bool {
+    msrv.map_or(true, |msrv| !msrv.matches(lint_msrv))
+}
+
+macro_rules! extract_msrv_attr {
+    (LateContext) => {
+        extract_msrv_attr!(@LateContext, ());
+    };
+    (EarlyContext) => {
+        extract_msrv_attr!(@EarlyContext);
+    };
+    (@$context:ident$(, $call:tt)?) => {
+        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) {
+            use $crate::utils::get_unique_inner_attr;
+            match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
+                Some(msrv_attr) => {
+                    if let Some(msrv) = msrv_attr.value_str() {
+                        self.msrv = $crate::utils::parse_msrv(
+                            &msrv.to_string(),
+                            Some(cx.sess$($call)?),
+                            Some(msrv_attr.span),
+                        );
+                    } else {
+                        cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute");
+                    }
+                },
+                _ => (),
+            }
+        }
+    };
+}
+
 /// Returns `true` if the two spans come from differing expansions (i.e., one is
 /// from a macro and one isn't).
 #[must_use]
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index 137f5d18b66..829e9a2989c 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -90,6 +90,8 @@ pub const PATH_BUF: [&str; 3] = ["std", "path", "PathBuf"];
 pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
+pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
+pub const POLL_READY: [&str; 5] = ["core", "task", "poll", "Poll", "Ready"];
 pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
 pub const PTR_NULL: [&str; 3] = ["core", "ptr", "null"];
 pub const PTR_NULL_MUT: [&str; 3] = ["core", "ptr", "null_mut"];
diff --git a/tests/ui-toml/invalid_min_rust_version/clippy.toml b/tests/ui-toml/invalid_min_rust_version/clippy.toml
new file mode 100644
index 00000000000..088b12b2dac
--- /dev/null
+++ b/tests/ui-toml/invalid_min_rust_version/clippy.toml
@@ -0,0 +1 @@
+msrv = "invalid.version"
diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs
new file mode 100644
index 00000000000..2ebf28645e5
--- /dev/null
+++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs
@@ -0,0 +1,3 @@
+#![allow(clippy::redundant_clone)]
+
+fn main() {}
diff --git a/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr
new file mode 100644
index 00000000000..e9d8fd2e0f5
--- /dev/null
+++ b/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr
@@ -0,0 +1,4 @@
+error: error reading Clippy's configuration file. `invalid.version` is not a valid Rust version
+
+error: aborting due to previous error
+
diff --git a/tests/ui-toml/min_rust_version/clippy.toml b/tests/ui-toml/min_rust_version/clippy.toml
new file mode 100644
index 00000000000..8e17d8074c4
--- /dev/null
+++ b/tests/ui-toml/min_rust_version/clippy.toml
@@ -0,0 +1 @@
+msrv = "1.0.0"
diff --git a/tests/ui-toml/min_rust_version/min_rust_version.rs b/tests/ui-toml/min_rust_version/min_rust_version.rs
new file mode 100644
index 00000000000..bc41efa42a1
--- /dev/null
+++ b/tests/ui-toml/min_rust_version/min_rust_version.rs
@@ -0,0 +1,68 @@
+#![allow(clippy::redundant_clone)]
+#![warn(clippy::manual_non_exhaustive)]
+
+use std::ops::Deref;
+
+mod enums {
+    enum E {
+        A,
+        B,
+        #[doc(hidden)]
+        _C,
+    }
+
+    // user forgot to remove the marker
+    #[non_exhaustive]
+    enum Ep {
+        A,
+        B,
+        #[doc(hidden)]
+        _C,
+    }
+}
+
+fn option_as_ref_deref() {
+    let mut opt = Some(String::from("123"));
+
+    let _ = opt.as_ref().map(String::as_str);
+    let _ = opt.as_ref().map(|x| x.as_str());
+    let _ = opt.as_mut().map(String::as_mut_str);
+    let _ = opt.as_mut().map(|x| x.as_mut_str());
+}
+
+fn match_like_matches() {
+    let _y = match Some(5) {
+        Some(0) => true,
+        _ => false,
+    };
+}
+
+fn match_same_arms() {
+    match (1, 2, 3) {
+        (1, .., 3) => 42,
+        (.., 3) => 42, //~ ERROR match arms have same body
+        _ => 0,
+    };
+}
+
+fn match_same_arms2() {
+    let _ = match Some(42) {
+        Some(_) => 24,
+        None => 24, //~ ERROR match arms have same body
+    };
+}
+
+fn manual_strip_msrv() {
+    let s = "hello, world!";
+    if s.starts_with("hello, ") {
+        assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
+    }
+}
+
+fn main() {
+    option_as_ref_deref();
+    match_like_matches();
+    match_same_arms();
+    match_same_arms2();
+    manual_strip_msrv();
+}
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index a58e7e918e2..af3d9ecf6e8 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/tests/ui/as_conversions.rs b/tests/ui/as_conversions.rs
index e01ba0c64df..cd745feec6d 100644
--- a/tests/ui/as_conversions.rs
+++ b/tests/ui/as_conversions.rs
@@ -1,7 +1,19 @@
-#[warn(clippy::as_conversions)]
+// aux-build:macro_rules.rs
+
+#![warn(clippy::as_conversions)]
+
+#[macro_use]
+extern crate macro_rules;
+
+fn with_external_macro() {
+    as_conv_with_arg!(0u32 as u64);
+    as_conv!();
+}
 
 fn main() {
     let i = 0u32 as u64;
 
     let j = &i as *const u64 as *mut u64;
+
+    with_external_macro();
 }
diff --git a/tests/ui/as_conversions.stderr b/tests/ui/as_conversions.stderr
index 312d3a7460e..f5f75d3aee0 100644
--- a/tests/ui/as_conversions.stderr
+++ b/tests/ui/as_conversions.stderr
@@ -1,5 +1,5 @@
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:4:13
+  --> $DIR/as_conversions.rs:14:13
    |
 LL |     let i = 0u32 as u64;
    |             ^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     let i = 0u32 as u64;
    = help: consider using a safe wrapper for this conversion
 
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:6:13
+  --> $DIR/as_conversions.rs:16:13
    |
 LL |     let j = &i as *const u64 as *mut u64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     let j = &i as *const u64 as *mut u64;
    = help: consider using a safe wrapper for this conversion
 
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:6:13
+  --> $DIR/as_conversions.rs:16:13
    |
 LL |     let j = &i as *const u64 as *mut u64;
    |             ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs
index 93303865e17..f985a15eda2 100644
--- a/tests/ui/auxiliary/macro_rules.rs
+++ b/tests/ui/auxiliary/macro_rules.rs
@@ -70,3 +70,17 @@ macro_rules! ref_arg_function {
         fn fun_example(ref _x: usize) {}
     };
 }
+
+#[macro_export]
+macro_rules! as_conv_with_arg {
+    (0u32 as u64) => {
+        ()
+    };
+}
+
+#[macro_export]
+macro_rules! as_conv {
+    () => {
+        0u32 as u64
+    };
+}
diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs
index 4cbc5630d75..e1ee8dbca2c 100644
--- a/tests/ui/deprecated.rs
+++ b/tests/ui/deprecated.rs
@@ -1,5 +1,3 @@
-#[warn(clippy::str_to_string)]
-#[warn(clippy::string_to_string)]
 #[warn(clippy::unstable_as_slice)]
 #[warn(clippy::unstable_as_mut_slice)]
 #[warn(clippy::misaligned_transmute)]
diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr
index a348d01d734..edbb891afe0 100644
--- a/tests/ui/deprecated.stderr
+++ b/tests/ui/deprecated.stderr
@@ -1,88 +1,76 @@
-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)]
-   |        ^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
-
-error: lint `clippy::string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon`
-  --> $DIR/deprecated.rs:2:8
-   |
-LL | #[warn(clippy::string_to_string)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
-  --> $DIR/deprecated.rs:3:8
+  --> $DIR/deprecated.rs:1:8
    |
 LL | #[warn(clippy::unstable_as_slice)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7`
-  --> $DIR/deprecated.rs:4:8
+  --> $DIR/deprecated.rs:2:8
    |
 LL | #[warn(clippy::unstable_as_mut_slice)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr`
-  --> $DIR/deprecated.rs:5:8
+  --> $DIR/deprecated.rs:3:8
    |
 LL | #[warn(clippy::misaligned_transmute)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unused_collect` has been removed: ``collect` has been marked as #[must_use] in rustc and that covers all cases of this lint`
-  --> $DIR/deprecated.rs:6:8
+  --> $DIR/deprecated.rs:4:8
    |
 LL | #[warn(clippy::unused_collect)]
    |        ^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::invalid_ref` has been removed: `superseded by rustc lint `invalid_value``
-  --> $DIR/deprecated.rs:7:8
+  --> $DIR/deprecated.rs:5:8
    |
 LL | #[warn(clippy::invalid_ref)]
    |        ^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::into_iter_on_array` has been removed: `this lint has been uplifted to rustc and is now called `array_into_iter``
-  --> $DIR/deprecated.rs:8:8
+  --> $DIR/deprecated.rs:6:8
    |
 LL | #[warn(clippy::into_iter_on_array)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::unused_label` has been removed: `this lint has been uplifted to rustc and is now called `unused_labels``
-  --> $DIR/deprecated.rs:9:8
+  --> $DIR/deprecated.rs:7:8
    |
 LL | #[warn(clippy::unused_label)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::regex_macro` has been removed: `the regex! macro has been removed from the regex crate in 2018`
-  --> $DIR/deprecated.rs:10:8
+  --> $DIR/deprecated.rs:8:8
    |
 LL | #[warn(clippy::regex_macro)]
    |        ^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::drop_bounds` has been removed: `this lint has been uplifted to rustc and is now called `drop_bounds``
-  --> $DIR/deprecated.rs:11:8
+  --> $DIR/deprecated.rs:9:8
    |
 LL | #[warn(clippy::drop_bounds)]
    |        ^^^^^^^^^^^^^^^^^^^
 
 error: lint `clippy::temporary_cstring_as_ptr` has been removed: `this lint has been uplifted to rustc and is now called `temporary_cstring_as_ptr``
-  --> $DIR/deprecated.rs:12:8
+  --> $DIR/deprecated.rs:10:8
    |
 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
+  --> $DIR/deprecated.rs:11: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`
+error: lint `clippy::unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
   --> $DIR/deprecated.rs:1:8
    |
-LL | #[warn(clippy::str_to_string)]
-   |        ^^^^^^^^^^^^^^^^^^^^^
+LL | #[warn(clippy::unstable_as_slice)]
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 14 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/deprecated_old.rs b/tests/ui/deprecated_old.rs
index 2e5c5b7ead1..e89dca4fcfd 100644
--- a/tests/ui/deprecated_old.rs
+++ b/tests/ui/deprecated_old.rs
@@ -1,5 +1,3 @@
-#[warn(str_to_string)]
-#[warn(string_to_string)]
 #[warn(unstable_as_slice)]
 #[warn(unstable_as_mut_slice)]
 #[warn(misaligned_transmute)]
diff --git a/tests/ui/deprecated_old.stderr b/tests/ui/deprecated_old.stderr
index ff3e9e8fcf3..2fe1facf0c7 100644
--- a/tests/ui/deprecated_old.stderr
+++ b/tests/ui/deprecated_old.stderr
@@ -1,40 +1,28 @@
-error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
-  --> $DIR/deprecated_old.rs:1:8
-   |
-LL | #[warn(str_to_string)]
-   |        ^^^^^^^^^^^^^
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
-
-error: lint `string_to_string` has been removed: `using `string::to_string` is common even today and specialization will likely happen soon`
-  --> $DIR/deprecated_old.rs:2:8
-   |
-LL | #[warn(string_to_string)]
-   |        ^^^^^^^^^^^^^^^^
-
 error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
-  --> $DIR/deprecated_old.rs:3:8
+  --> $DIR/deprecated_old.rs:1:8
    |
 LL | #[warn(unstable_as_slice)]
    |        ^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `unstable_as_mut_slice` has been removed: ``Vec::as_mut_slice` has been stabilized in 1.7`
-  --> $DIR/deprecated_old.rs:4:8
+  --> $DIR/deprecated_old.rs:2:8
    |
 LL | #[warn(unstable_as_mut_slice)]
    |        ^^^^^^^^^^^^^^^^^^^^^
 
 error: lint `misaligned_transmute` has been removed: `this lint has been split into cast_ptr_alignment and transmute_ptr_to_ptr`
-  --> $DIR/deprecated_old.rs:5:8
+  --> $DIR/deprecated_old.rs:3:8
    |
 LL | #[warn(misaligned_transmute)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
-error: lint `str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
+error: lint `unstable_as_slice` has been removed: ``Vec::as_slice` has been stabilized in 1.7`
   --> $DIR/deprecated_old.rs:1:8
    |
-LL | #[warn(str_to_string)]
-   |        ^^^^^^^^^^^^^
+LL | #[warn(unstable_as_slice)]
+   |        ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/min_rust_version_attr.rs b/tests/ui/min_rust_version_attr.rs
new file mode 100644
index 00000000000..8ed483a3ac6
--- /dev/null
+++ b/tests/ui/min_rust_version_attr.rs
@@ -0,0 +1,51 @@
+#![allow(clippy::redundant_clone)]
+#![feature(custom_inner_attributes)]
+#![clippy::msrv = "1.0.0"]
+
+use std::ops::Deref;
+
+fn option_as_ref_deref() {
+    let mut opt = Some(String::from("123"));
+
+    let _ = opt.as_ref().map(String::as_str);
+    let _ = opt.as_ref().map(|x| x.as_str());
+    let _ = opt.as_mut().map(String::as_mut_str);
+    let _ = opt.as_mut().map(|x| x.as_mut_str());
+}
+
+fn match_like_matches() {
+    let _y = match Some(5) {
+        Some(0) => true,
+        _ => false,
+    };
+}
+
+fn match_same_arms() {
+    match (1, 2, 3) {
+        (1, .., 3) => 42,
+        (.., 3) => 42, //~ ERROR match arms have same body
+        _ => 0,
+    };
+}
+
+fn match_same_arms2() {
+    let _ = match Some(42) {
+        Some(_) => 24,
+        None => 24, //~ ERROR match arms have same body
+    };
+}
+
+fn manual_strip_msrv() {
+    let s = "hello, world!";
+    if s.starts_with("hello, ") {
+        assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
+    }
+}
+
+fn main() {
+    option_as_ref_deref();
+    match_like_matches();
+    match_same_arms();
+    match_same_arms2();
+    manual_strip_msrv();
+}
diff --git a/tests/ui/min_rust_version_invalid_attr.rs b/tests/ui/min_rust_version_invalid_attr.rs
new file mode 100644
index 00000000000..f20841891a7
--- /dev/null
+++ b/tests/ui/min_rust_version_invalid_attr.rs
@@ -0,0 +1,4 @@
+#![feature(custom_inner_attributes)]
+#![clippy::msrv = "invalid.version"]
+
+fn main() {}
diff --git a/tests/ui/min_rust_version_invalid_attr.stderr b/tests/ui/min_rust_version_invalid_attr.stderr
new file mode 100644
index 00000000000..6ff88ca56f8
--- /dev/null
+++ b/tests/ui/min_rust_version_invalid_attr.stderr
@@ -0,0 +1,8 @@
+error: `invalid.version` is not a valid Rust version
+  --> $DIR/min_rust_version_invalid_attr.rs:2:1
+   |
+LL | #![clippy::msrv = "invalid.version"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/min_rust_version_multiple_inner_attr.rs b/tests/ui/min_rust_version_multiple_inner_attr.rs
new file mode 100644
index 00000000000..e882d5ccf91
--- /dev/null
+++ b/tests/ui/min_rust_version_multiple_inner_attr.rs
@@ -0,0 +1,11 @@
+#![feature(custom_inner_attributes)]
+#![clippy::msrv = "1.40"]
+#![clippy::msrv = "=1.35.0"]
+#![clippy::msrv = "1.10.1"]
+
+mod foo {
+    #![clippy::msrv = "1"]
+    #![clippy::msrv = "1.0.0"]
+}
+
+fn main() {}
diff --git a/tests/ui/min_rust_version_multiple_inner_attr.stderr b/tests/ui/min_rust_version_multiple_inner_attr.stderr
new file mode 100644
index 00000000000..e3ff6605cde
--- /dev/null
+++ b/tests/ui/min_rust_version_multiple_inner_attr.stderr
@@ -0,0 +1,38 @@
+error: `msrv` is defined multiple times
+  --> $DIR/min_rust_version_multiple_inner_attr.rs:3:1
+   |
+LL | #![clippy::msrv = "=1.35.0"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first definition found here
+  --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1
+   |
+LL | #![clippy::msrv = "1.40"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `msrv` is defined multiple times
+  --> $DIR/min_rust_version_multiple_inner_attr.rs:4:1
+   |
+LL | #![clippy::msrv = "1.10.1"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first definition found here
+  --> $DIR/min_rust_version_multiple_inner_attr.rs:2:1
+   |
+LL | #![clippy::msrv = "1.40"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `msrv` is defined multiple times
+  --> $DIR/min_rust_version_multiple_inner_attr.rs:8:5
+   |
+LL |     #![clippy::msrv = "1.0.0"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: first definition found here
+  --> $DIR/min_rust_version_multiple_inner_attr.rs:7:5
+   |
+LL |     #![clippy::msrv = "1"]
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/min_rust_version_no_patch.rs b/tests/ui/min_rust_version_no_patch.rs
new file mode 100644
index 00000000000..515fe8f95e9
--- /dev/null
+++ b/tests/ui/min_rust_version_no_patch.rs
@@ -0,0 +1,14 @@
+#![allow(clippy::redundant_clone)]
+#![feature(custom_inner_attributes)]
+#![clippy::msrv = "^1.0"]
+
+fn manual_strip_msrv() {
+    let s = "hello, world!";
+    if s.starts_with("hello, ") {
+        assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
+    }
+}
+
+fn main() {
+    manual_strip_msrv()
+}
diff --git a/tests/ui/min_rust_version_outer_attr.rs b/tests/ui/min_rust_version_outer_attr.rs
new file mode 100644
index 00000000000..551948bd72e
--- /dev/null
+++ b/tests/ui/min_rust_version_outer_attr.rs
@@ -0,0 +1,4 @@
+#![feature(custom_inner_attributes)]
+
+#[clippy::msrv = "invalid.version"]
+fn main() {}
diff --git a/tests/ui/min_rust_version_outer_attr.stderr b/tests/ui/min_rust_version_outer_attr.stderr
new file mode 100644
index 00000000000..579ee7a87d2
--- /dev/null
+++ b/tests/ui/min_rust_version_outer_attr.stderr
@@ -0,0 +1,8 @@
+error: `msrv` cannot be an outer attribute
+  --> $DIR/min_rust_version_outer_attr.rs:3:1
+   |
+LL | #[clippy::msrv = "invalid.version"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/tests/ui/needless_collect_indirect.rs b/tests/ui/needless_collect_indirect.rs
index 4f6e5357727..0918a6868ab 100644
--- a/tests/ui/needless_collect_indirect.rs
+++ b/tests/ui/needless_collect_indirect.rs
@@ -22,4 +22,24 @@ fn main() {
     let sample = vec![a.clone(), "b".to_string(), "c".to_string()];
     let non_copy_contains = sample.into_iter().collect::<Vec<_>>();
     non_copy_contains.contains(&a);
+
+    // Fix #5991
+    let vec_a = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+    let vec_b = vec_a.iter().collect::<Vec<_>>();
+    if vec_b.len() > 3 {}
+    let other_vec = vec![1, 3, 12, 4, 16, 2];
+    let we_got_the_same_numbers = other_vec.iter().filter(|item| vec_b.contains(item)).collect::<Vec<_>>();
+
+    // Fix #6297
+    let sample = [1; 5];
+    let multiple_indirect = sample.iter().collect::<Vec<_>>();
+    let sample2 = vec![2, 3];
+    if multiple_indirect.is_empty() {
+        // do something
+    } else {
+        let found = sample2
+            .iter()
+            .filter(|i| multiple_indirect.iter().any(|s| **s % **i == 0))
+            .collect::<Vec<_>>();
+    }
 }
diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
index 499b975b2bb..bc369dd2491 100644
--- a/tests/ui/redundant_pattern_matching_option.fixed
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -2,13 +2,7 @@
 
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
-#![allow(
-    clippy::unit_arg,
-    unused_must_use,
-    clippy::needless_bool,
-    clippy::match_like_matches_macro,
-    deprecated
-)]
+#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)]
 
 fn main() {
     if None::<()>.is_none() {}
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
index 2a98435e790..d7616a72913 100644
--- a/tests/ui/redundant_pattern_matching_option.rs
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -2,13 +2,7 @@
 
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
-#![allow(
-    clippy::unit_arg,
-    unused_must_use,
-    clippy::needless_bool,
-    clippy::match_like_matches_macro,
-    deprecated
-)]
+#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)]
 
 fn main() {
     if let None = None::<()> {}
diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr
index eebb3448491..7ddfbe503a2 100644
--- a/tests/ui/redundant_pattern_matching_option.stderr
+++ b/tests/ui/redundant_pattern_matching_option.stderr
@@ -1,5 +1,5 @@
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:14:12
+  --> $DIR/redundant_pattern_matching_option.rs:8:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
@@ -7,43 +7,43 @@ LL |     if let None = None::<()> {}
    = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:16:12
+  --> $DIR/redundant_pattern_matching_option.rs:10:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:18:12
+  --> $DIR/redundant_pattern_matching_option.rs:12:12
    |
 LL |     if let Some(_) = Some(42) {
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:24:15
+  --> $DIR/redundant_pattern_matching_option.rs:18:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:26:15
+  --> $DIR/redundant_pattern_matching_option.rs:20:15
    |
 LL |     while let None = Some(42) {}
    |     ----------^^^^----------- help: try this: `while Some(42).is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:28:15
+  --> $DIR/redundant_pattern_matching_option.rs:22:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:31:15
+  --> $DIR/redundant_pattern_matching_option.rs:25:15
    |
 LL |     while let Some(_) = v.pop() {
    |     ----------^^^^^^^---------- help: try this: `while v.pop().is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:39:5
+  --> $DIR/redundant_pattern_matching_option.rs:33:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -52,7 +52,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:44:5
+  --> $DIR/redundant_pattern_matching_option.rs:38:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
@@ -61,7 +61,7 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:49:13
+  --> $DIR/redundant_pattern_matching_option.rs:43:13
    |
 LL |       let _ = match None::<()> {
    |  _____________^
@@ -71,49 +71,49 @@ LL | |     };
    | |_____^ help: try this: `None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:55:20
+  --> $DIR/redundant_pattern_matching_option.rs:49:20
    |
 LL |     let x = if let Some(_) = opt { true } else { false };
    |             -------^^^^^^^------ help: try this: `if opt.is_some()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:60:20
+  --> $DIR/redundant_pattern_matching_option.rs:54:20
    |
 LL |     let _ = if let Some(_) = gen_opt() {
    |             -------^^^^^^^------------ help: try this: `if gen_opt().is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:62:19
+  --> $DIR/redundant_pattern_matching_option.rs:56:19
    |
 LL |     } else if let None = gen_opt() {
    |            -------^^^^------------ help: try this: `if gen_opt().is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:83:12
+  --> $DIR/redundant_pattern_matching_option.rs:77:12
    |
 LL |     if let Some(_) = Some(42) {}
    |     -------^^^^^^^----------- help: try this: `if Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:85:12
+  --> $DIR/redundant_pattern_matching_option.rs:79:12
    |
 LL |     if let None = None::<()> {}
    |     -------^^^^------------- help: try this: `if None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:87:15
+  --> $DIR/redundant_pattern_matching_option.rs:81:15
    |
 LL |     while let Some(_) = Some(42) {}
    |     ----------^^^^^^^----------- help: try this: `while Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:89:15
+  --> $DIR/redundant_pattern_matching_option.rs:83:15
    |
 LL |     while let None = None::<()> {}
    |     ----------^^^^------------- help: try this: `while None::<()>.is_none()`
 
 error: redundant pattern matching, consider using `is_some()`
-  --> $DIR/redundant_pattern_matching_option.rs:91:5
+  --> $DIR/redundant_pattern_matching_option.rs:85:5
    |
 LL | /     match Some(42) {
 LL | |         Some(_) => true,
@@ -122,7 +122,7 @@ LL | |     };
    | |_____^ help: try this: `Some(42).is_some()`
 
 error: redundant pattern matching, consider using `is_none()`
-  --> $DIR/redundant_pattern_matching_option.rs:96:5
+  --> $DIR/redundant_pattern_matching_option.rs:90:5
    |
 LL | /     match None::<()> {
 LL | |         Some(_) => false,
diff --git a/tests/ui/redundant_pattern_matching_poll.fixed b/tests/ui/redundant_pattern_matching_poll.fixed
new file mode 100644
index 00000000000..564c427f063
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_poll.fixed
@@ -0,0 +1,73 @@
+// run-rustfix
+
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)]
+
+use std::task::Poll::{self, Pending, Ready};
+
+fn main() {
+    if Pending::<()>.is_pending() {}
+
+    if Ready(42).is_ready() {}
+
+    if Ready(42).is_ready() {
+        foo();
+    } else {
+        bar();
+    }
+
+    while Ready(42).is_ready() {}
+
+    while Ready(42).is_pending() {}
+
+    while Pending::<()>.is_pending() {}
+
+    if Pending::<i32>.is_pending() {}
+
+    if Ready(42).is_ready() {}
+
+    Ready(42).is_ready();
+
+    Pending::<()>.is_pending();
+
+    let _ = Pending::<()>.is_pending();
+
+    let poll = Ready(false);
+    let x = if poll.is_ready() { true } else { false };
+    takes_poll(x);
+
+    poll_const();
+
+    let _ = if gen_poll().is_ready() {
+        1
+    } else if gen_poll().is_pending() {
+        2
+    } else {
+        3
+    };
+}
+
+fn gen_poll() -> Poll<()> {
+    Pending
+}
+
+fn takes_poll(_: bool) {}
+
+fn foo() {}
+
+fn bar() {}
+
+const fn poll_const() {
+    if Ready(42).is_ready() {}
+
+    if Pending::<()>.is_pending() {}
+
+    while Ready(42).is_ready() {}
+
+    while Pending::<()>.is_pending() {}
+
+    Ready(42).is_ready();
+
+    Pending::<()>.is_pending();
+}
diff --git a/tests/ui/redundant_pattern_matching_poll.rs b/tests/ui/redundant_pattern_matching_poll.rs
new file mode 100644
index 00000000000..d453d4184af
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_poll.rs
@@ -0,0 +1,88 @@
+// run-rustfix
+
+#![warn(clippy::all)]
+#![warn(clippy::redundant_pattern_matching)]
+#![allow(unused_must_use, clippy::needless_bool, clippy::match_like_matches_macro)]
+
+use std::task::Poll::{self, Pending, Ready};
+
+fn main() {
+    if let Pending = Pending::<()> {}
+
+    if let Ready(_) = Ready(42) {}
+
+    if let Ready(_) = Ready(42) {
+        foo();
+    } else {
+        bar();
+    }
+
+    while let Ready(_) = Ready(42) {}
+
+    while let Pending = Ready(42) {}
+
+    while let Pending = Pending::<()> {}
+
+    if Pending::<i32>.is_pending() {}
+
+    if Ready(42).is_ready() {}
+
+    match Ready(42) {
+        Ready(_) => true,
+        Pending => false,
+    };
+
+    match Pending::<()> {
+        Ready(_) => false,
+        Pending => true,
+    };
+
+    let _ = match Pending::<()> {
+        Ready(_) => false,
+        Pending => true,
+    };
+
+    let poll = Ready(false);
+    let x = if let Ready(_) = poll { true } else { false };
+    takes_poll(x);
+
+    poll_const();
+
+    let _ = if let Ready(_) = gen_poll() {
+        1
+    } else if let Pending = gen_poll() {
+        2
+    } else {
+        3
+    };
+}
+
+fn gen_poll() -> Poll<()> {
+    Pending
+}
+
+fn takes_poll(_: bool) {}
+
+fn foo() {}
+
+fn bar() {}
+
+const fn poll_const() {
+    if let Ready(_) = Ready(42) {}
+
+    if let Pending = Pending::<()> {}
+
+    while let Ready(_) = Ready(42) {}
+
+    while let Pending = Pending::<()> {}
+
+    match Ready(42) {
+        Ready(_) => true,
+        Pending => false,
+    };
+
+    match Pending::<()> {
+        Ready(_) => false,
+        Pending => true,
+    };
+}
diff --git a/tests/ui/redundant_pattern_matching_poll.stderr b/tests/ui/redundant_pattern_matching_poll.stderr
new file mode 100644
index 00000000000..42e5d6f41fe
--- /dev/null
+++ b/tests/ui/redundant_pattern_matching_poll.stderr
@@ -0,0 +1,128 @@
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:10:12
+   |
+LL |     if let Pending = Pending::<()> {}
+   |     -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()`
+   |
+   = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:12:12
+   |
+LL |     if let Ready(_) = Ready(42) {}
+   |     -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:14:12
+   |
+LL |     if let Ready(_) = Ready(42) {
+   |     -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:20:15
+   |
+LL |     while let Ready(_) = Ready(42) {}
+   |     ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:22:15
+   |
+LL |     while let Pending = Ready(42) {}
+   |     ----------^^^^^^^------------ help: try this: `while Ready(42).is_pending()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:24:15
+   |
+LL |     while let Pending = Pending::<()> {}
+   |     ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:30:5
+   |
+LL | /     match Ready(42) {
+LL | |         Ready(_) => true,
+LL | |         Pending => false,
+LL | |     };
+   | |_____^ help: try this: `Ready(42).is_ready()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:35:5
+   |
+LL | /     match Pending::<()> {
+LL | |         Ready(_) => false,
+LL | |         Pending => true,
+LL | |     };
+   | |_____^ help: try this: `Pending::<()>.is_pending()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:40:13
+   |
+LL |       let _ = match Pending::<()> {
+   |  _____________^
+LL | |         Ready(_) => false,
+LL | |         Pending => true,
+LL | |     };
+   | |_____^ help: try this: `Pending::<()>.is_pending()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:46:20
+   |
+LL |     let x = if let Ready(_) = poll { true } else { false };
+   |             -------^^^^^^^^------- help: try this: `if poll.is_ready()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:51:20
+   |
+LL |     let _ = if let Ready(_) = gen_poll() {
+   |             -------^^^^^^^^------------- help: try this: `if gen_poll().is_ready()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:53:19
+   |
+LL |     } else if let Pending = gen_poll() {
+   |            -------^^^^^^^------------- help: try this: `if gen_poll().is_pending()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:71:12
+   |
+LL |     if let Ready(_) = Ready(42) {}
+   |     -------^^^^^^^^------------ help: try this: `if Ready(42).is_ready()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:73:12
+   |
+LL |     if let Pending = Pending::<()> {}
+   |     -------^^^^^^^---------------- help: try this: `if Pending::<()>.is_pending()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:75:15
+   |
+LL |     while let Ready(_) = Ready(42) {}
+   |     ----------^^^^^^^^------------ help: try this: `while Ready(42).is_ready()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:77:15
+   |
+LL |     while let Pending = Pending::<()> {}
+   |     ----------^^^^^^^---------------- help: try this: `while Pending::<()>.is_pending()`
+
+error: redundant pattern matching, consider using `is_ready()`
+  --> $DIR/redundant_pattern_matching_poll.rs:79:5
+   |
+LL | /     match Ready(42) {
+LL | |         Ready(_) => true,
+LL | |         Pending => false,
+LL | |     };
+   | |_____^ help: try this: `Ready(42).is_ready()`
+
+error: redundant pattern matching, consider using `is_pending()`
+  --> $DIR/redundant_pattern_matching_poll.rs:84:5
+   |
+LL | /     match Pending::<()> {
+LL | |         Ready(_) => false,
+LL | |         Pending => true,
+LL | |     };
+   | |_____^ help: try this: `Pending::<()>.is_pending()`
+
+error: aborting due to 18 previous errors
+
diff --git a/tests/ui/redundant_pattern_matching.fixed b/tests/ui/redundant_pattern_matching_result.fixed
index aa20512296a..e94c5704b48 100644
--- a/tests/ui/redundant_pattern_matching.fixed
+++ b/tests/ui/redundant_pattern_matching_result.fixed
@@ -3,7 +3,6 @@
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(
-    clippy::unit_arg,
     unused_must_use,
     clippy::needless_bool,
     clippy::match_like_matches_macro,
diff --git a/tests/ui/redundant_pattern_matching.rs b/tests/ui/redundant_pattern_matching_result.rs
index d76f9c288ff..5d175294232 100644
--- a/tests/ui/redundant_pattern_matching.rs
+++ b/tests/ui/redundant_pattern_matching_result.rs
@@ -3,7 +3,6 @@
 #![warn(clippy::all)]
 #![warn(clippy::redundant_pattern_matching)]
 #![allow(
-    clippy::unit_arg,
     unused_must_use,
     clippy::needless_bool,
     clippy::match_like_matches_macro,
diff --git a/tests/ui/redundant_pattern_matching.stderr b/tests/ui/redundant_pattern_matching_result.stderr
index aeb309f5ba1..d6a46babb77 100644
--- a/tests/ui/redundant_pattern_matching.stderr
+++ b/tests/ui/redundant_pattern_matching_result.stderr
@@ -1,5 +1,5 @@
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:16:12
+  --> $DIR/redundant_pattern_matching_result.rs:15:12
    |
 LL |     if let Ok(_) = &result {}
    |     -------^^^^^---------- help: try this: `if result.is_ok()`
@@ -7,31 +7,31 @@ 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:18:12
+  --> $DIR/redundant_pattern_matching_result.rs:17:12
    |
 LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:20:12
+  --> $DIR/redundant_pattern_matching_result.rs:19:12
    |
 LL |     if let Err(_) = Err::<i32, i32>(42) {}
    |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:22:15
+  --> $DIR/redundant_pattern_matching_result.rs:21:15
    |
 LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:24:15
+  --> $DIR/redundant_pattern_matching_result.rs:23:15
    |
 LL |     while let Err(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:34:5
+  --> $DIR/redundant_pattern_matching_result.rs:33:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -40,7 +40,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:39:5
+  --> $DIR/redundant_pattern_matching_result.rs:38:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -49,7 +49,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:44:5
+  --> $DIR/redundant_pattern_matching_result.rs:43:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => false,
@@ -58,7 +58,7 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:49:5
+  --> $DIR/redundant_pattern_matching_result.rs:48:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -67,73 +67,73 @@ LL | |     };
    | |_____^ help: try this: `Err::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:54:20
+  --> $DIR/redundant_pattern_matching_result.rs:53:20
    |
 LL |     let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
    |             -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:60:20
+  --> $DIR/redundant_pattern_matching_result.rs:59: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:62:19
+  --> $DIR/redundant_pattern_matching_result.rs:61: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:85:19
+  --> $DIR/redundant_pattern_matching_result.rs:84: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:86:16
+  --> $DIR/redundant_pattern_matching_result.rs:85: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:92:12
+  --> $DIR/redundant_pattern_matching_result.rs:91: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:93:15
+  --> $DIR/redundant_pattern_matching_result.rs:92: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:111:12
+  --> $DIR/redundant_pattern_matching_result.rs:110:12
    |
 LL |     if let Ok(_) = Ok::<i32, i32>(42) {}
    |     -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:113:12
+  --> $DIR/redundant_pattern_matching_result.rs:112:12
    |
 LL |     if let Err(_) = Err::<i32, i32>(42) {}
    |     -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:115:15
+  --> $DIR/redundant_pattern_matching_result.rs:114:15
    |
 LL |     while let Ok(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:117:15
+  --> $DIR/redundant_pattern_matching_result.rs:116:15
    |
 LL |     while let Err(_) = Ok::<i32, i32>(10) {}
    |     ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()`
 
 error: redundant pattern matching, consider using `is_ok()`
-  --> $DIR/redundant_pattern_matching.rs:119:5
+  --> $DIR/redundant_pattern_matching_result.rs:118:5
    |
 LL | /     match Ok::<i32, i32>(42) {
 LL | |         Ok(_) => true,
@@ -142,7 +142,7 @@ LL | |     };
    | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()`
 
 error: redundant pattern matching, consider using `is_err()`
-  --> $DIR/redundant_pattern_matching.rs:124:5
+  --> $DIR/redundant_pattern_matching_result.rs:123:5
    |
 LL | /     match Err::<i32, i32>(42) {
 LL | |         Ok(_) => false,
diff --git a/tests/ui/str_to_string.rs b/tests/ui/str_to_string.rs
new file mode 100644
index 00000000000..08f73402518
--- /dev/null
+++ b/tests/ui/str_to_string.rs
@@ -0,0 +1,7 @@
+#![warn(clippy::str_to_string)]
+
+fn main() {
+    let hello = "hello world".to_string();
+    let msg = &hello[..];
+    msg.to_string();
+}
diff --git a/tests/ui/str_to_string.stderr b/tests/ui/str_to_string.stderr
new file mode 100644
index 00000000000..b1f73eda5d2
--- /dev/null
+++ b/tests/ui/str_to_string.stderr
@@ -0,0 +1,19 @@
+error: `to_string()` called on a `&str`
+  --> $DIR/str_to_string.rs:4:17
+   |
+LL |     let hello = "hello world".to_string();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::str-to-string` implied by `-D warnings`
+   = help: consider using `.to_owned()`
+
+error: `to_string()` called on a `&str`
+  --> $DIR/str_to_string.rs:6:5
+   |
+LL |     msg.to_string();
+   |     ^^^^^^^^^^^^^^^
+   |
+   = help: consider using `.to_owned()`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/string_to_string.rs b/tests/ui/string_to_string.rs
new file mode 100644
index 00000000000..4c66855f709
--- /dev/null
+++ b/tests/ui/string_to_string.rs
@@ -0,0 +1,7 @@
+#![warn(clippy::string_to_string)]
+#![allow(clippy::redundant_clone)]
+
+fn main() {
+    let mut message = String::from("Hello");
+    let mut v = message.to_string();
+}
diff --git a/tests/ui/string_to_string.stderr b/tests/ui/string_to_string.stderr
new file mode 100644
index 00000000000..1ebd17999bd
--- /dev/null
+++ b/tests/ui/string_to_string.stderr
@@ -0,0 +1,11 @@
+error: `to_string()` called on a `String`
+  --> $DIR/string_to_string.rs:6:17
+   |
+LL |     let mut v = message.to_string();
+   |                 ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::string-to-string` implied by `-D warnings`
+   = help: consider using `.clone()`
+
+error: aborting due to previous error
+
diff --git a/tests/ui/temporary_assignment.rs b/tests/ui/temporary_assignment.rs
index b4a931043b0..ac4c1bc6597 100644
--- a/tests/ui/temporary_assignment.rs
+++ b/tests/ui/temporary_assignment.rs
@@ -1,5 +1,4 @@
 #![warn(clippy::temporary_assignment)]
-#![allow(const_item_mutation)]
 
 use std::ops::{Deref, DerefMut};
 
diff --git a/tests/ui/temporary_assignment.stderr b/tests/ui/temporary_assignment.stderr
index 4cc32c79f05..7d79901a28d 100644
--- a/tests/ui/temporary_assignment.stderr
+++ b/tests/ui/temporary_assignment.stderr
@@ -1,5 +1,5 @@
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:48:5
+  --> $DIR/temporary_assignment.rs:47:5
    |
 LL |     Struct { field: 0 }.field = 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     Struct { field: 0 }.field = 1;
    = note: `-D clippy::temporary-assignment` implied by `-D warnings`
 
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:49:5
+  --> $DIR/temporary_assignment.rs:48:5
    |
 LL | /     MultiStruct {
 LL | |         structure: Struct { field: 0 },
@@ -17,13 +17,13 @@ LL | |     .field = 1;
    | |______________^
 
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:54:5
+  --> $DIR/temporary_assignment.rs:53:5
    |
 LL |     ArrayStruct { array: [0] }.array[0] = 1;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: assignment to temporary
-  --> $DIR/temporary_assignment.rs:55:5
+  --> $DIR/temporary_assignment.rs:54:5
    |
 LL |     (0, 0).0 = 1;
    |     ^^^^^^^^^^^^
diff --git a/tests/ui/unnecessary_cast.rs b/tests/ui/unnecessary_cast.rs
index df9b227eeb3..e8f2fb46665 100644
--- a/tests/ui/unnecessary_cast.rs
+++ b/tests/ui/unnecessary_cast.rs
@@ -20,4 +20,7 @@ fn main() {
     foo!(a, i32);
     foo!(b, f32);
     foo!(c, f64);
+
+    // do not lint cast to cfg-dependant type
+    1 as std::os::raw::c_char;
 }
diff --git a/tests/ui/unnecessary_cast_fixable.fixed b/tests/ui/unnecessary_cast_fixable.fixed
index 350da4965d1..7fbce58a82f 100644
--- a/tests/ui/unnecessary_cast_fixable.fixed
+++ b/tests/ui/unnecessary_cast_fixable.fixed
@@ -11,6 +11,8 @@ fn main() {
     let _ = -100_f32;
     let _ = -100_f64;
     let _ = -100_f64;
+    100_f32;
+    100_f64;
     // Should not trigger
     #[rustfmt::skip]
     let v = vec!(1);
diff --git a/tests/ui/unnecessary_cast_fixable.rs b/tests/ui/unnecessary_cast_fixable.rs
index ad2fb2e6289..a71363ea4d2 100644
--- a/tests/ui/unnecessary_cast_fixable.rs
+++ b/tests/ui/unnecessary_cast_fixable.rs
@@ -11,6 +11,8 @@ fn main() {
     let _ = -100 as f32;
     let _ = -100 as f64;
     let _ = -100_i32 as f64;
+    100. as f32;
+    100. as f64;
     // Should not trigger
     #[rustfmt::skip]
     let v = vec!(1);
diff --git a/tests/ui/unnecessary_cast_fixable.stderr b/tests/ui/unnecessary_cast_fixable.stderr
index 5a210fc8909..3695a8f819c 100644
--- a/tests/ui/unnecessary_cast_fixable.stderr
+++ b/tests/ui/unnecessary_cast_fixable.stderr
@@ -36,59 +36,71 @@ error: casting integer literal to `f64` is unnecessary
 LL |     let _ = -100_i32 as f64;
    |             ^^^^^^^^^^^^^^^ help: try: `-100_f64`
 
+error: casting float literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast_fixable.rs:14:5
+   |
+LL |     100. as f32;
+   |     ^^^^^^^^^^^ help: try: `100_f32`
+
+error: casting float literal to `f64` is unnecessary
+  --> $DIR/unnecessary_cast_fixable.rs:15:5
+   |
+LL |     100. as f64;
+   |     ^^^^^^^^^^^ help: try: `100_f64`
+
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:25:5
+  --> $DIR/unnecessary_cast_fixable.rs:27:5
    |
 LL |     1 as u32;
    |     ^^^^^^^^ help: try: `1_u32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:26:5
+  --> $DIR/unnecessary_cast_fixable.rs:28:5
    |
 LL |     0x10 as i32;
    |     ^^^^^^^^^^^ help: try: `0x10_i32`
 
 error: casting integer literal to `usize` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:27:5
+  --> $DIR/unnecessary_cast_fixable.rs:29:5
    |
 LL |     0b10 as usize;
    |     ^^^^^^^^^^^^^ help: try: `0b10_usize`
 
 error: casting integer literal to `u16` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:28:5
+  --> $DIR/unnecessary_cast_fixable.rs:30:5
    |
 LL |     0o73 as u16;
    |     ^^^^^^^^^^^ help: try: `0o73_u16`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:29:5
+  --> $DIR/unnecessary_cast_fixable.rs:31:5
    |
 LL |     1_000_000_000 as u32;
    |     ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:31:5
+  --> $DIR/unnecessary_cast_fixable.rs:33:5
    |
 LL |     1.0 as f64;
    |     ^^^^^^^^^^ help: try: `1.0_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:32:5
+  --> $DIR/unnecessary_cast_fixable.rs:34:5
    |
 LL |     0.5 as f32;
    |     ^^^^^^^^^^ help: try: `0.5_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:36:13
+  --> $DIR/unnecessary_cast_fixable.rs:38:13
    |
 LL |     let _ = -1 as i32;
    |             ^^^^^^^^^ help: try: `-1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:37:13
+  --> $DIR/unnecessary_cast_fixable.rs:39:13
    |
 LL |     let _ = -1.0 as f32;
    |             ^^^^^^^^^^^ help: try: `-1.0_f32`
 
-error: aborting due to 15 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/wildcard_enum_match_arm.fixed b/tests/ui/wildcard_enum_match_arm.fixed
index b1e5742b785..c266f684a36 100644
--- a/tests/ui/wildcard_enum_match_arm.fixed
+++ b/tests/ui/wildcard_enum_match_arm.fixed
@@ -7,7 +7,8 @@
     dead_code,
     clippy::single_match,
     clippy::wildcard_in_or_patterns,
-    clippy::unnested_or_patterns, clippy::diverging_sub_expression
+    clippy::unnested_or_patterns,
+    clippy::diverging_sub_expression
 )]
 
 use std::io::ErrorKind;
diff --git a/tests/ui/wildcard_enum_match_arm.rs b/tests/ui/wildcard_enum_match_arm.rs
index cd3ec3ea8d2..2dbf726d5d0 100644
--- a/tests/ui/wildcard_enum_match_arm.rs
+++ b/tests/ui/wildcard_enum_match_arm.rs
@@ -7,7 +7,8 @@
     dead_code,
     clippy::single_match,
     clippy::wildcard_in_or_patterns,
-    clippy::unnested_or_patterns, clippy::diverging_sub_expression
+    clippy::unnested_or_patterns,
+    clippy::diverging_sub_expression
 )]
 
 use std::io::ErrorKind;
diff --git a/tests/ui/wildcard_enum_match_arm.stderr b/tests/ui/wildcard_enum_match_arm.stderr
index e03b3be43ed..0da2b68ba0b 100644
--- a/tests/ui/wildcard_enum_match_arm.stderr
+++ b/tests/ui/wildcard_enum_match_arm.stderr
@@ -1,5 +1,5 @@
 error: wildcard match will miss any future added variants
-  --> $DIR/wildcard_enum_match_arm.rs:38:9
+  --> $DIR/wildcard_enum_match_arm.rs:39:9
    |
 LL |         _ => eprintln!("Not red"),
    |         ^ help: try this: `Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
@@ -11,25 +11,25 @@ LL | #![deny(clippy::wildcard_enum_match_arm)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: wildcard match will miss any future added variants
-  --> $DIR/wildcard_enum_match_arm.rs:42:9
+  --> $DIR/wildcard_enum_match_arm.rs:43:9
    |
 LL |         _not_red => eprintln!("Not red"),
    |         ^^^^^^^^ help: try this: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan`
 
 error: wildcard match will miss any future added variants
-  --> $DIR/wildcard_enum_match_arm.rs:46:9
+  --> $DIR/wildcard_enum_match_arm.rs:47:9
    |
 LL |         not_red => format!("{:?}", not_red),
    |         ^^^^^^^ help: try this: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan`
 
 error: wildcard match will miss any future added variants
-  --> $DIR/wildcard_enum_match_arm.rs:62:9
+  --> $DIR/wildcard_enum_match_arm.rs:63:9
    |
 LL |         _ => "No red",
    |         ^ help: try this: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan`
 
 error: match on non-exhaustive enum doesn't explicitly match all known variants
-  --> $DIR/wildcard_enum_match_arm.rs:79:9
+  --> $DIR/wildcard_enum_match_arm.rs:80:9
    |
 LL |         _ => {},
    |         ^ help: try this: `std::io::ErrorKind::PermissionDenied | std::io::ErrorKind::ConnectionRefused | std::io::ErrorKind::ConnectionReset | std::io::ErrorKind::ConnectionAborted | std::io::ErrorKind::NotConnected | std::io::ErrorKind::AddrInUse | std::io::ErrorKind::AddrNotAvailable | std::io::ErrorKind::BrokenPipe | std::io::ErrorKind::AlreadyExists | std::io::ErrorKind::WouldBlock | std::io::ErrorKind::InvalidInput | std::io::ErrorKind::InvalidData | std::io::ErrorKind::TimedOut | std::io::ErrorKind::WriteZero | std::io::ErrorKind::Interrupted | std::io::ErrorKind::Other | std::io::ErrorKind::UnexpectedEof | _`
diff --git a/util/dev b/util/dev
deleted file mode 100755
index 319de217e0d..00000000000
--- a/util/dev
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-CARGO_TARGET_DIR=$(pwd)/target/
-export CARGO_TARGET_DIR
-
-echo 'Deprecated! `util/dev` usage is deprecated, please use `cargo dev` instead.'
-
-cd clippy_dev && cargo run -- "$@"