about summary refs log tree commit diff
diff options
context:
space:
mode:
authorflip1995 <hello@philkrones.com>2020-07-03 12:50:41 +0200
committerflip1995 <hello@philkrones.com>2020-07-03 12:50:41 +0200
commita7c58e66d4b4f1434d62ead0eec57fda36dd238f (patch)
treeb0af7be5f4a43a1830058eca8915faa4e99d033d
parent30c046ede47ea45a772d2656b0365a4807263bca (diff)
parent52cc5fce1e7dfd440a2ae9c892bcea2aa988c5bb (diff)
downloadrust-a7c58e66d4b4f1434d62ead0eec57fda36dd238f.tar.gz
rust-a7c58e66d4b4f1434d62ead0eec57fda36dd238f.zip
Merge remote-tracking branch 'upstream/master' into rustup
-rw-r--r--.github/workflows/clippy_bors.yml3
-rw-r--r--CHANGELOG.md2
-rw-r--r--clippy_lints/src/attrs.rs95
-rw-r--r--clippy_lints/src/await_holding_lock.rs2
-rw-r--r--clippy_lints/src/deprecated_lints.rs10
-rw-r--r--clippy_lints/src/dereference.rs10
-rw-r--r--clippy_lints/src/lib.rs17
-rw-r--r--clippy_lints/src/map_identity.rs126
-rw-r--r--clippy_lints/src/methods/mod.rs2
-rw-r--r--clippy_lints/src/misc.rs92
-rw-r--r--clippy_lints/src/needless_pass_by_value.rs3
-rw-r--r--clippy_lints/src/regex.rs57
-rw-r--r--clippy_lints/src/unnested_or_patterns.rs4
-rw-r--r--clippy_lints/src/utils/paths.rs1
-rw-r--r--clippy_lints/src/utils/sugg.rs22
-rw-r--r--clippy_lints/src/write.rs33
-rw-r--r--src/lintlist/mod.rs21
-rw-r--r--tests/compile-test.rs3
-rw-r--r--tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock109
-rw-r--r--tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr2
-rw-r--r--tests/ui/attrs.rs6
-rw-r--r--tests/ui/attrs.stderr33
-rw-r--r--tests/ui/clone_on_copy.fixed40
-rw-r--r--tests/ui/clone_on_copy.rs40
-rw-r--r--tests/ui/clone_on_copy.stderr34
-rw-r--r--tests/ui/cmp_owned/asymmetric_partial_eq.fixed93
-rw-r--r--tests/ui/cmp_owned/asymmetric_partial_eq.rs93
-rw-r--r--tests/ui/cmp_owned/asymmetric_partial_eq.stderr46
-rw-r--r--tests/ui/deprecated.rs1
-rw-r--r--tests/ui/deprecated.stderr8
-rw-r--r--tests/ui/map_flatten.fixed1
-rw-r--r--tests/ui/map_flatten.rs1
-rw-r--r--tests/ui/map_flatten.stderr4
-rw-r--r--tests/ui/map_identity.fixed23
-rw-r--r--tests/ui/map_identity.rs25
-rw-r--r--tests/ui/map_identity.stderr37
-rw-r--r--tests/ui/regex.rs2
-rw-r--r--tests/ui/unnecessary_clone.rs25
-rw-r--r--tests/ui/unnecessary_clone.stderr58
-rw-r--r--tests/ui/unnested_or_patterns3.rs6
-rwxr-xr-xutil/dev7
41 files changed, 951 insertions, 246 deletions
diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml
index 0c80394f03e..fd0cd7a1890 100644
--- a/.github/workflows/clippy_bors.yml
+++ b/.github/workflows/clippy_bors.yml
@@ -240,7 +240,8 @@ jobs:
         - 'Geal/nom'
         - 'rust-lang/stdarch'
         - 'serde-rs/serde'
-        - 'chronotope/chrono'
+        # FIXME: chrono currently cannot be compiled with `--all-targets`
+        # - 'chronotope/chrono'
         - 'hyperium/hyper'
         - 'rust-random/rand'
         - 'rust-lang/futures-rs'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index adc945a6944..b88044d6ce8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1352,6 +1352,7 @@ Released 2018-09-13
 [`bad_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#bad_bit_mask
 [`bind_instead_of_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#bind_instead_of_map
 [`blacklisted_name`]: https://rust-lang.github.io/rust-clippy/master/index.html#blacklisted_name
+[`blanket_clippy_restriction_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#blanket_clippy_restriction_lints
 [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
 [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
@@ -1508,6 +1509,7 @@ Released 2018-09-13
 [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone
 [`map_entry`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_entry
 [`map_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_flatten
+[`map_identity`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_identity
 [`map_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
 [`match_as_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_as_ref
 [`match_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#match_bool
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 2505ff32fe5..2d0855f6895 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -2,8 +2,8 @@
 
 use crate::reexport::Name;
 use crate::utils::{
-    first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_sugg,
-    span_lint_and_then, without_block_comments,
+    first_line_of_span, is_present_in_source, match_def_path, paths, snippet_opt, span_lint, span_lint_and_help,
+    span_lint_and_sugg, span_lint_and_then, without_block_comments,
 };
 use if_chain::if_chain;
 use rustc_ast::ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
@@ -17,7 +17,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{Symbol, SymbolStr};
 use semver::Version;
 
 static UNIX_SYSTEMS: &[&str] = &[
@@ -183,6 +183,29 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
+    /// **What it does:** Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category.
+    ///
+    /// **Why is this bad?** Restriction lints sometimes are in contrast with other lints or even go against idiomatic rust.
+    /// These lints should only be enabled on a lint-by-lint basis and with careful consideration.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    /// Bad:
+    /// ```rust
+    /// #![deny(clippy::restriction)]
+    /// ```
+    ///
+    /// Good:
+    /// ```rust
+    /// #![deny(clippy::as_conversions)]
+    /// ```
+    pub BLANKET_CLIPPY_RESTRICTION_LINTS,
+    style,
+    "enabling the complete restriction group"
+}
+
+declare_clippy_lint! {
     /// **What it does:** Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it
     /// with `#[rustfmt::skip]`.
     ///
@@ -249,15 +272,17 @@ declare_lint_pass!(Attributes => [
     DEPRECATED_SEMVER,
     USELESS_ATTRIBUTE,
     UNKNOWN_CLIPPY_LINTS,
+    BLANKET_CLIPPY_RESTRICTION_LINTS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Attributes {
     fn check_attribute(&mut self, cx: &LateContext<'tcx>, attr: &'tcx Attribute) {
         if let Some(items) = &attr.meta_item_list() {
             if let Some(ident) = attr.ident() {
-                match &*ident.as_str() {
+                let ident = &*ident.as_str();
+                match ident {
                     "allow" | "warn" | "deny" | "forbid" => {
-                        check_clippy_lint_names(cx, items);
+                        check_clippy_lint_names(cx, ident, items);
                     },
                     _ => {},
                 }
@@ -363,38 +388,43 @@ impl<'tcx> LateLintPass<'tcx> for Attributes {
     }
 }
 
-#[allow(clippy::single_match_else)]
-fn check_clippy_lint_names(cx: &LateContext<'_>, items: &[NestedMetaItem]) {
-    let lint_store = cx.lints();
-    for lint in items {
+fn check_clippy_lint_names(cx: &LateContext<'_>, ident: &str, items: &[NestedMetaItem]) {
+    fn extract_name(lint: &NestedMetaItem) -> Option<SymbolStr> {
         if_chain! {
             if let Some(meta_item) = lint.meta_item();
             if meta_item.path.segments.len() > 1;
             if let tool_name = meta_item.path.segments[0].ident;
             if tool_name.as_str() == "clippy";
-            let name = meta_item.path.segments.last().unwrap().ident.name;
-            if let CheckLintNameResult::Tool(Err((None, _))) = lint_store.check_lint_name(
-                &name.as_str(),
-                Some(tool_name.name),
-            );
+            let lint_name = meta_item.path.segments.last().unwrap().ident.name;
             then {
+                return Some(lint_name.as_str());
+            }
+        }
+        None
+    }
+
+    let lint_store = cx.lints();
+    for lint in items {
+        if let Some(lint_name) = extract_name(lint) {
+            if let CheckLintNameResult::Tool(Err((None, _))) =
+                lint_store.check_lint_name(&lint_name, Some(sym!(clippy)))
+            {
                 span_lint_and_then(
                     cx,
                     UNKNOWN_CLIPPY_LINTS,
                     lint.span(),
-                    &format!("unknown clippy lint: clippy::{}", name),
+                    &format!("unknown clippy lint: clippy::{}", lint_name),
                     |diag| {
-                        let name_lower = name.as_str().to_lowercase();
-                        let symbols = lint_store.get_lints().iter().map(
-                            |l| Symbol::intern(&l.name_lower())
-                        ).collect::<Vec<_>>();
-                        let sugg = find_best_match_for_name(
-                            symbols.iter(),
-                            &format!("clippy::{}", name_lower),
-                            None,
-                        );
-                        if name.as_str().chars().any(char::is_uppercase)
-                            && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok() {
+                        let name_lower = lint_name.to_lowercase();
+                        let symbols = lint_store
+                            .get_lints()
+                            .iter()
+                            .map(|l| Symbol::intern(&l.name_lower()))
+                            .collect::<Vec<_>>();
+                        let sugg = find_best_match_for_name(symbols.iter(), &format!("clippy::{}", name_lower), None);
+                        if lint_name.chars().any(char::is_uppercase)
+                            && lint_store.find_lints(&format!("clippy::{}", name_lower)).is_ok()
+                        {
                             diag.span_suggestion(
                                 lint.span(),
                                 "lowercase the lint name",
@@ -409,10 +439,19 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, items: &[NestedMetaItem]) {
                                 Applicability::MachineApplicable,
                             );
                         }
-                    }
+                    },
+                );
+            } else if lint_name == "restriction" && ident != "allow" {
+                span_lint_and_help(
+                    cx,
+                    BLANKET_CLIPPY_RESTRICTION_LINTS,
+                    lint.span(),
+                    "restriction lints are not meant to be all enabled",
+                    None,
+                    "try enabling only the lints you really need",
                 );
             }
-        };
+        }
     }
 }
 
diff --git a/clippy_lints/src/await_holding_lock.rs b/clippy_lints/src/await_holding_lock.rs
index 20b91bc0f1b..d337262dfa6 100644
--- a/clippy_lints/src/await_holding_lock.rs
+++ b/clippy_lints/src/await_holding_lock.rs
@@ -11,7 +11,7 @@ declare_clippy_lint! {
     /// non-async-aware MutexGuard.
     ///
     /// **Why is this bad?** The Mutex types found in syd::sync and parking_lot
-    /// are not designed to operator in an async context across await points.
+    /// are not designed to operate in an async context across await points.
     ///
     /// There are two potential solutions. One is to use an asynx-aware Mutex
     /// type. Many asynchronous foundation crates provide such a Mutex type. The
diff --git a/clippy_lints/src/deprecated_lints.rs b/clippy_lints/src/deprecated_lints.rs
index 6e8ca647dd7..818d8188a78 100644
--- a/clippy_lints/src/deprecated_lints.rs
+++ b/clippy_lints/src/deprecated_lints.rs
@@ -153,5 +153,13 @@ declare_deprecated_lint! {
     ///
     /// **Deprecation reason:** Associated-constants are now preferred.
     pub REPLACE_CONSTS,
-    "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants"
+    "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants"
+}
+
+declare_deprecated_lint! {
+    /// **What it does:** Nothing. This lint has been deprecated.
+    ///
+    /// **Deprecation reason:** The regex! macro does not exist anymore.
+    pub REGEX_MACRO,
+    "the regex! macro has been removed from the regex crate in 2018"
 }
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index d740d88a77d..323cad7fa1a 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -73,9 +73,10 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
 fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var_span: Span, expr_span: Span) {
     match method_name {
         "deref" => {
-            if cx.tcx.lang_items().deref_trait().map_or(false, |id| {
+            let impls_deref_trait = cx.tcx.lang_items().deref_trait().map_or(false, |id| {
                 implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
-            }) {
+            });
+            if impls_deref_trait {
                 span_lint_and_sugg(
                     cx,
                     EXPLICIT_DEREF_METHODS,
@@ -88,9 +89,10 @@ fn lint_deref(cx: &LateContext<'_>, method_name: &str, call_expr: &Expr<'_>, var
             }
         },
         "deref_mut" => {
-            if cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| {
+            let impls_deref_mut_trait = cx.tcx.lang_items().deref_mut_trait().map_or(false, |id| {
                 implements_trait(cx, cx.tables().expr_ty(&call_expr), id, &[])
-            }) {
+            });
+            if impls_deref_mut_trait {
                 span_lint_and_sugg(
                     cx,
                     EXPLICIT_DEREF_METHODS,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 501220f28e5..d31a597b66a 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -229,6 +229,7 @@ mod main_recursion;
 mod manual_async_fn;
 mod manual_non_exhaustive;
 mod map_clone;
+mod map_identity;
 mod map_unit_fn;
 mod match_on_vec_items;
 mod matches;
@@ -459,7 +460,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     );
     store.register_removed(
         "clippy::replace_consts",
-        "associated-constants `MIN`/`MAX` of integers are prefer to `{min,max}_value()` and module constants",
+        "associated-constants `MIN`/`MAX` of integers are prefered to `{min,max}_value()` and module constants",
+    );
+    store.register_removed(
+        "clippy::regex_macro",
+        "the regex! macro has been removed from the regex crate in 2018",
     );
     // end deprecated lints, do not remove this comment, it’s used in `update_lints`
 
@@ -473,6 +478,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &assign_ops::ASSIGN_OP_PATTERN,
         &assign_ops::MISREFACTORED_ASSIGN_OP,
         &atomic_ordering::INVALID_ATOMIC_ORDERING,
+        &attrs::BLANKET_CLIPPY_RESTRICTION_LINTS,
         &attrs::DEPRECATED_CFG_ATTR,
         &attrs::DEPRECATED_SEMVER,
         &attrs::EMPTY_LINE_AFTER_OUTER_ATTR,
@@ -608,6 +614,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &manual_async_fn::MANUAL_ASYNC_FN,
         &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
         &map_clone::MAP_CLONE,
+        &map_identity::MAP_IDENTITY,
         &map_unit_fn::OPTION_MAP_UNIT_FN,
         &map_unit_fn::RESULT_MAP_UNIT_FN,
         &match_on_vec_items::MATCH_ON_VEC_ITEMS,
@@ -752,7 +759,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &reference::DEREF_ADDROF,
         &reference::REF_IN_DEREF,
         &regex::INVALID_REGEX,
-        &regex::REGEX_MACRO,
         &regex::TRIVIAL_REGEX,
         &returns::NEEDLESS_RETURN,
         &returns::UNUSED_UNIT,
@@ -1057,6 +1063,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_early_pass(|| box unnested_or_patterns::UnnestedOrPatterns);
     store.register_late_pass(|| box macro_use::MacroUseImports::default());
+    store.register_late_pass(|| box map_identity::MapIdentity);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1186,6 +1193,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
         LintId::of(&assign_ops::MISREFACTORED_ASSIGN_OP),
         LintId::of(&atomic_ordering::INVALID_ATOMIC_ORDERING),
+        LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
         LintId::of(&attrs::DEPRECATED_CFG_ATTR),
         LintId::of(&attrs::DEPRECATED_SEMVER),
         LintId::of(&attrs::MISMATCHED_TARGET_OS),
@@ -1273,6 +1281,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
         LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
         LintId::of(&map_clone::MAP_CLONE),
+        LintId::of(&map_identity::MAP_IDENTITY),
         LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
         LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
         LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
@@ -1374,7 +1383,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&reference::DEREF_ADDROF),
         LintId::of(&reference::REF_IN_DEREF),
         LintId::of(&regex::INVALID_REGEX),
-        LintId::of(&regex::REGEX_MACRO),
         LintId::of(&regex::TRIVIAL_REGEX),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&returns::UNUSED_UNIT),
@@ -1437,6 +1445,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_group(true, "clippy::style", Some("clippy_style"), vec![
         LintId::of(&assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
         LintId::of(&assign_ops::ASSIGN_OP_PATTERN),
+        LintId::of(&attrs::BLANKET_CLIPPY_RESTRICTION_LINTS),
         LintId::of(&attrs::UNKNOWN_CLIPPY_LINTS),
         LintId::of(&bit_mask::VERBOSE_BIT_MASK),
         LintId::of(&blacklisted_name::BLACKLISTED_NAME),
@@ -1510,7 +1519,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
         LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING),
         LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
-        LintId::of(&regex::REGEX_MACRO),
         LintId::of(&regex::TRIVIAL_REGEX),
         LintId::of(&returns::NEEDLESS_RETURN),
         LintId::of(&returns::UNUSED_UNIT),
@@ -1550,6 +1558,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::EXPLICIT_COUNTER_LOOP),
         LintId::of(&loops::MUT_RANGE_BOUND),
         LintId::of(&loops::WHILE_LET_LOOP),
+        LintId::of(&map_identity::MAP_IDENTITY),
         LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
         LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
         LintId::of(&matches::MATCH_AS_REF),
diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs
new file mode 100644
index 00000000000..24ec78c8846
--- /dev/null
+++ b/clippy_lints/src/map_identity.rs
@@ -0,0 +1,126 @@
+use crate::utils::{
+    is_adjusted, is_type_diagnostic_item, match_path, match_trait_method, match_var, paths, remove_blocks,
+    span_lint_and_sugg,
+};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for instances of `map(f)` where `f` is the identity function.
+    ///
+    /// **Why is this bad?** It can be written more concisely without the call to `map`.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let x = [1, 2, 3];
+    /// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let x = [1, 2, 3];
+    /// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
+    /// ```
+    pub MAP_IDENTITY,
+    complexity,
+    "using iterator.map(|x| x)"
+}
+
+declare_lint_pass!(MapIdentity => [MAP_IDENTITY]);
+
+impl<'tcx> LateLintPass<'tcx> for MapIdentity {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        if_chain! {
+            if let Some([caller, func]) = get_map_argument(cx, expr);
+            if is_expr_identity_function(cx, func);
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    MAP_IDENTITY,
+                    expr.span.trim_start(caller.span).unwrap(),
+                    "unnecessary map of the identity function",
+                    "remove the call to `map`",
+                    String::new(),
+                    Applicability::MachineApplicable
+                )
+            }
+        }
+    }
+}
+
+/// Returns the arguments passed into map() if the expression is a method call to
+/// map(). Otherwise, returns None.
+fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a [Expr<'a>]> {
+    if_chain! {
+        if let ExprKind::MethodCall(ref method, _, ref args, _) = expr.kind;
+        if args.len() == 2 && method.ident.as_str() == "map";
+        let caller_ty = cx.tables().expr_ty(&args[0]);
+        if match_trait_method(cx, expr, &paths::ITERATOR)
+            || is_type_diagnostic_item(cx, caller_ty, sym!(result_type))
+            || is_type_diagnostic_item(cx, caller_ty, sym!(option_type));
+        then {
+            Some(args)
+        } else {
+            None
+        }
+    }
+}
+
+/// Checks if an expression represents the identity function
+/// Only examines closures and `std::convert::identity`
+fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    match expr.kind {
+        ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
+        ExprKind::Path(QPath::Resolved(_, ref path)) => match_path(path, &paths::STD_CONVERT_IDENTITY),
+        _ => false,
+    }
+}
+
+/// Checks if a function's body represents the identity function
+/// Looks for bodies of the form `|x| x`, `|x| return x`, `|x| { return x }` or `|x| {
+/// return x; }`
+fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
+    let params = func.params;
+    let body = remove_blocks(&func.value);
+
+    // if there's less/more than one parameter, then it is not the identity function
+    if params.len() != 1 {
+        return false;
+    }
+
+    match body.kind {
+        ExprKind::Path(QPath::Resolved(None, _)) => match_expr_param(cx, body, params[0].pat),
+        ExprKind::Ret(Some(ref ret_val)) => match_expr_param(cx, ret_val, params[0].pat),
+        ExprKind::Block(ref block, _) => {
+            if_chain! {
+                if block.stmts.len() == 1;
+                if let StmtKind::Semi(ref expr) | StmtKind::Expr(ref expr) = block.stmts[0].kind;
+                if let ExprKind::Ret(Some(ref ret_val)) = expr.kind;
+                then {
+                    match_expr_param(cx, ret_val, params[0].pat)
+                } else {
+                    false
+                }
+            }
+        },
+        _ => false,
+    }
+}
+
+/// Returns true iff an expression returns the same thing as a parameter's pattern
+fn match_expr_param(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool {
+    if let PatKind::Binding(_, _, ident, _) = pat.kind {
+        match_var(expr, ident.name) && !(cx.tables().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr))
+    } else {
+        false
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 216db12f011..160304865c5 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -2044,7 +2044,7 @@ fn lint_clone_on_copy(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Exp
         }
         span_lint_and_then(cx, CLONE_ON_COPY, expr.span, "using `clone` on a `Copy` type", |diag| {
             if let Some((text, snip)) = snip {
-                diag.span_suggestion(expr.span, text, snip, Applicability::Unspecified);
+                diag.span_suggestion(expr.span, text, snip, Applicability::MachineApplicable);
             }
         });
     }
diff --git a/clippy_lints/src/misc.rs b/clippy_lints/src/misc.rs
index d7e1a62a19d..6a256627bd1 100644
--- a/clippy_lints/src/misc.rs
+++ b/clippy_lints/src/misc.rs
@@ -3,11 +3,11 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt, StmtKind, Ty,
-    TyKind, UnOp,
+    self as hir, def, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, HirId, Mutability, PatKind, Stmt,
+    StmtKind, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::DesugaringKind;
 use rustc_span::source_map::{ExpnKind, Span};
@@ -371,8 +371,8 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints {
                 if op.is_comparison() {
                     check_nan(cx, left, expr);
                     check_nan(cx, right, expr);
-                    check_to_owned(cx, left, right);
-                    check_to_owned(cx, right, left);
+                    check_to_owned(cx, left, right, true);
+                    check_to_owned(cx, right, left, false);
                 }
                 if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) {
                     if is_allowed(cx, left) || is_allowed(cx, right) {
@@ -570,11 +570,30 @@ fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     matches!(&walk_ptrs_ty(cx.tables().expr_ty(expr)).kind, ty::Array(_, _))
 }
 
-fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
+fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
+    #[derive(Default)]
+    struct EqImpl {
+        ty_eq_other: bool,
+        other_eq_ty: bool,
+    }
+
+    impl EqImpl {
+        fn is_implemented(&self) -> bool {
+            self.ty_eq_other || self.other_eq_ty
+        }
+    }
+
+    fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> Option<EqImpl> {
+        cx.tcx.lang_items().eq_trait().map(|def_id| EqImpl {
+            ty_eq_other: implements_trait(cx, ty, def_id, &[other.into()]),
+            other_eq_ty: implements_trait(cx, other, def_id, &[ty.into()]),
+        })
+    }
+
     let (arg_ty, snip) = match expr.kind {
         ExprKind::MethodCall(.., ref args, _) if args.len() == 1 => {
             if match_trait_method(cx, expr, &paths::TO_STRING) || match_trait_method(cx, expr, &paths::TO_OWNED) {
-                (cx.tables().expr_ty_adjusted(&args[0]), snippet(cx, args[0].span, ".."))
+                (cx.tables().expr_ty(&args[0]), snippet(cx, args[0].span, ".."))
             } else {
                 return;
             }
@@ -582,7 +601,7 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
         ExprKind::Call(ref path, ref v) if v.len() == 1 => {
             if let ExprKind::Path(ref path) = path.kind {
                 if match_qpath(path, &["String", "from_str"]) || match_qpath(path, &["String", "from"]) {
-                    (cx.tables().expr_ty_adjusted(&v[0]), snippet(cx, v[0].span, ".."))
+                    (cx.tables().expr_ty(&v[0]), snippet(cx, v[0].span, ".."))
                 } else {
                     return;
                 }
@@ -593,28 +612,19 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
         _ => return,
     };
 
-    let other_ty = cx.tables().expr_ty_adjusted(other);
-    let partial_eq_trait_id = match cx.tcx.lang_items().eq_trait() {
-        Some(id) => id,
-        None => return,
-    };
+    let other_ty = cx.tables().expr_ty(other);
 
-    let deref_arg_impl_partial_eq_other = arg_ty.builtin_deref(true).map_or(false, |tam| {
-        implements_trait(cx, tam.ty, partial_eq_trait_id, &[other_ty.into()])
-    });
-    let arg_impl_partial_eq_deref_other = other_ty.builtin_deref(true).map_or(false, |tam| {
-        implements_trait(cx, arg_ty, partial_eq_trait_id, &[tam.ty.into()])
-    });
-    let arg_impl_partial_eq_other = implements_trait(cx, arg_ty, partial_eq_trait_id, &[other_ty.into()]);
+    let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
+    let with_deref = arg_ty
+        .builtin_deref(true)
+        .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty))
+        .unwrap_or_default();
 
-    if !deref_arg_impl_partial_eq_other && !arg_impl_partial_eq_deref_other && !arg_impl_partial_eq_other {
+    if !with_deref.is_implemented() && !without_deref.is_implemented() {
         return;
     }
 
-    let other_gets_derefed = match other.kind {
-        ExprKind::Unary(UnOp::UnDeref, _) => true,
-        _ => false,
-    };
+    let other_gets_derefed = matches!(other.kind, ExprKind::Unary(UnOp::UnDeref, _));
 
     let lint_span = if other_gets_derefed {
         expr.span.to(other.span)
@@ -634,18 +644,34 @@ fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>) {
                 return;
             }
 
-            let try_hint = if deref_arg_impl_partial_eq_other {
-                // suggest deref on the left
-                format!("*{}", snip)
+            let expr_snip;
+            let eq_impl;
+            if with_deref.is_implemented() {
+                expr_snip = format!("*{}", snip);
+                eq_impl = with_deref;
             } else {
-                // suggest dropping the to_owned on the left
-                snip.to_string()
+                expr_snip = snip.to_string();
+                eq_impl = without_deref;
             };
 
+            let span;
+            let hint;
+            if (eq_impl.ty_eq_other && left) || (eq_impl.other_eq_ty && !left) {
+                span = expr.span;
+                hint = expr_snip;
+            } else {
+                span = expr.span.to(other.span);
+                if eq_impl.ty_eq_other {
+                    hint = format!("{} == {}", expr_snip, snippet(cx, other.span, ".."));
+                } else {
+                    hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip);
+                }
+            }
+
             diag.span_suggestion(
-                lint_span,
+                span,
                 "try",
-                try_hint,
+                hint,
                 Applicability::MachineApplicable, // snippet
             );
         },
@@ -694,7 +720,7 @@ fn non_macro_local(cx: &LateContext<'_>, res: def::Res) -> bool {
     }
 }
 
-fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &Ty<'_>) {
+fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>) {
     if_chain! {
         if let TyKind::Ptr(ref mut_ty) = ty.kind;
         if let ExprKind::Lit(ref lit) = e.kind;
diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs
index bc70c675ad6..e72f9c77fe9 100644
--- a/clippy_lints/src/needless_pass_by_value.rs
+++ b/clippy_lints/src/needless_pass_by_value.rs
@@ -40,9 +40,8 @@ declare_clippy_lint! {
     ///     assert_eq!(v.len(), 42);
     /// }
     /// ```
-    ///
+    /// should be
     /// ```rust
-    /// // should be
     /// fn foo(v: &[i32]) {
     ///     assert_eq!(v.len(), 42);
     /// }
diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs
index b67abad6ccb..d8c8eff2c85 100644
--- a/clippy_lints/src/regex.rs
+++ b/clippy_lints/src/regex.rs
@@ -1,9 +1,9 @@
 use crate::consts::{constant, Constant};
-use crate::utils::{is_expn_of, match_def_path, match_type, paths, span_lint, span_lint_and_help};
+use crate::utils::{match_def_path, paths, span_lint, span_lint_and_help};
 use if_chain::if_chain;
 use rustc_ast::ast::{LitKind, StrStyle};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{Block, BorrowKind, Crate, Expr, ExprKind, HirId};
+use rustc_hir::{BorrowKind, Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{BytePos, Span};
@@ -46,66 +46,15 @@ declare_clippy_lint! {
     "trivial regular expressions"
 }
 
-declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `regex!(_)` which (as of now) is
-    /// usually slower than `Regex::new(_)` unless called in a loop (which is a bad
-    /// idea anyway).
-    ///
-    /// **Why is this bad?** Performance, at least for now. The macro version is
-    /// likely to catch up long-term, but for now the dynamic version is faster.
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```ignore
-    /// regex!("foo|bar")
-    /// ```
-    pub REGEX_MACRO,
-    style,
-    "use of `regex!(_)` instead of `Regex::new(_)`"
-}
-
 #[derive(Clone, Default)]
 pub struct Regex {
     spans: FxHashSet<Span>,
     last: Option<HirId>,
 }
 
-impl_lint_pass!(Regex => [INVALID_REGEX, REGEX_MACRO, TRIVIAL_REGEX]);
+impl_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
 
 impl<'tcx> LateLintPass<'tcx> for Regex {
-    fn check_crate(&mut self, _: &LateContext<'tcx>, _: &'tcx Crate<'_>) {
-        self.spans.clear();
-    }
-
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        if_chain! {
-            if self.last.is_none();
-            if let Some(ref expr) = block.expr;
-            if match_type(cx, cx.tables().expr_ty(expr), &paths::REGEX);
-            if let Some(span) = is_expn_of(expr.span, "regex");
-            then {
-                if !self.spans.contains(&span) {
-                    span_lint(
-                        cx,
-                        REGEX_MACRO,
-                        span,
-                        "`regex!(_)` found. \
-                        Please use `Regex::new(_)`, which is faster for now."
-                    );
-                    self.spans.insert(span);
-                }
-                self.last = Some(block.hir_id);
-            }
-        }
-    }
-
-    fn check_block_post(&mut self, _: &LateContext<'tcx>, block: &'tcx Block<'_>) {
-        if self.last.map_or(false, |id| block.hir_id == id) {
-            self.last = None;
-        }
-    }
-
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if let ExprKind::Call(ref fun, ref args) = expr.kind;
diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs
index 4d3682263f1..169a486d1eb 100644
--- a/clippy_lints/src/unnested_or_patterns.rs
+++ b/clippy_lints/src/unnested_or_patterns.rs
@@ -72,8 +72,8 @@ impl EarlyLintPass for UnnestedOrPatterns {
 }
 
 fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
-    if !cx.sess.opts.unstable_features.is_nightly_build() {
-        // User cannot do `#![feature(or_patterns)]`, so bail.
+    if !cx.sess.features_untracked().or_patterns {
+        // Do not suggest nesting the patterns if the feature `or_patterns` is not enabled.
         return;
     }
 
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index 3b7e9739211..4c3462802e9 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -98,7 +98,6 @@ pub const RANGE_TO_STD: [&str; 3] = ["std", "ops", "RangeTo"];
 pub const RC: [&str; 3] = ["alloc", "rc", "Rc"];
 pub const RC_PTR_EQ: [&str; 4] = ["alloc", "rc", "Rc", "ptr_eq"];
 pub const RECEIVER: [&str; 4] = ["std", "sync", "mpsc", "Receiver"];
-pub const REGEX: [&str; 3] = ["regex", "re_unicode", "Regex"];
 pub const REGEX_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "unicode", "RegexBuilder", "new"];
 pub const REGEX_BYTES_BUILDER_NEW: [&str; 5] = ["regex", "re_builder", "bytes", "RegexBuilder", "new"];
 pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "re_bytes", "Regex", "new"];
diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs
index d05e81b9505..8fc97f2fd64 100644
--- a/clippy_lints/src/utils/sugg.rs
+++ b/clippy_lints/src/utils/sugg.rs
@@ -325,22 +325,22 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
 /// parenthesis will always be added for a mix of these.
 pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> {
     /// Returns `true` if the operator is a shift operator `<<` or `>>`.
-    fn is_shift(op: &AssocOp) -> bool {
-        matches!(*op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
+    fn is_shift(op: AssocOp) -> bool {
+        matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight)
     }
 
     /// Returns `true` if the operator is a arithmetic operator
     /// (i.e., `+`, `-`, `*`, `/`, `%`).
-    fn is_arith(op: &AssocOp) -> bool {
+    fn is_arith(op: AssocOp) -> bool {
         matches!(
-            *op,
+            op,
             AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus
         )
     }
 
     /// Returns `true` if the operator `op` needs parenthesis with the operator
     /// `other` in the direction `dir`.
-    fn needs_paren(op: &AssocOp, other: &AssocOp, dir: Associativity) -> bool {
+    fn needs_paren(op: AssocOp, other: AssocOp, dir: Associativity) -> bool {
         other.precedence() < op.precedence()
             || (other.precedence() == op.precedence()
                 && ((op != other && associativity(op) != dir)
@@ -349,14 +349,14 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static>
             || is_shift(other) && is_arith(op)
     }
 
-    let lhs_paren = if let Sugg::BinOp(ref lop, _) = *lhs {
-        needs_paren(&op, lop, Associativity::Left)
+    let lhs_paren = if let Sugg::BinOp(lop, _) = *lhs {
+        needs_paren(op, lop, Associativity::Left)
     } else {
         false
     };
 
-    let rhs_paren = if let Sugg::BinOp(ref rop, _) = *rhs {
-        needs_paren(&op, rop, Associativity::Right)
+    let rhs_paren = if let Sugg::BinOp(rop, _) = *rhs {
+        needs_paren(op, rop, Associativity::Right)
     } else {
         false
     };
@@ -424,13 +424,13 @@ enum Associativity {
 /// they are considered
 /// associative.
 #[must_use]
-fn associativity(op: &AssocOp) -> Associativity {
+fn associativity(op: AssocOp) -> Associativity {
     use rustc_ast::util::parser::AssocOp::{
         Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater,
         GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract,
     };
 
-    match *op {
+    match op {
         Assign | AssignOp(_) => Associativity::Right,
         Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both,
         Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index cb769b5a2ce..732f4b28e06 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -23,7 +23,11 @@ declare_clippy_lint! {
     ///
     /// **Example:**
     /// ```rust
+    /// // Bad
     /// println!("");
+    ///
+    /// // Good
+    /// println!();
     /// ```
     pub PRINTLN_EMPTY_STRING,
     style,
@@ -32,8 +36,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// **What it does:** This lint warns when you use `print!()` with a format
-    /// string that
-    /// ends in a newline.
+    /// string that ends in a newline.
     ///
     /// **Why is this bad?** You should use `println!()` instead, which appends the
     /// newline.
@@ -125,7 +128,12 @@ declare_clippy_lint! {
     /// ```rust
     /// # use std::fmt::Write;
     /// # let mut buf = String::new();
+    ///
+    /// // Bad
     /// writeln!(buf, "");
+    ///
+    /// // Good
+    /// writeln!(buf);
     /// ```
     pub WRITELN_EMPTY_STRING,
     style,
@@ -147,7 +155,12 @@ declare_clippy_lint! {
     /// # use std::fmt::Write;
     /// # let mut buf = String::new();
     /// # let name = "World";
+    ///
+    /// // Bad
     /// write!(buf, "Hello {}!\n", name);
+    ///
+    /// // Good
+    /// writeln!(buf, "Hello {}!", name);
     /// ```
     pub WRITE_WITH_NEWLINE,
     style,
@@ -168,7 +181,12 @@ declare_clippy_lint! {
     /// ```rust
     /// # use std::fmt::Write;
     /// # let mut buf = String::new();
+    ///
+    /// // Bad
     /// writeln!(buf, "{}", "foo");
+    ///
+    /// // Good
+    /// writeln!(buf, "foo");
     /// ```
     pub WRITE_LITERAL,
     style,
@@ -279,12 +297,11 @@ impl EarlyLintPass for Write {
             if let (Some(fmt_str), expr) = self.check_tts(cx, &mac.args.inner_tokens(), true) {
                 if fmt_str.symbol == Symbol::intern("") {
                     let mut applicability = Applicability::MachineApplicable;
-                    let suggestion = match expr {
-                        Some(expr) => snippet_with_applicability(cx, expr.span, "v", &mut applicability),
-                        None => {
-                            applicability = Applicability::HasPlaceholders;
-                            Cow::Borrowed("v")
-                        },
+                    let suggestion = if let Some(e) = expr {
+                        snippet_with_applicability(cx, e.span, "v", &mut applicability)
+                    } else {
+                        applicability = Applicability::HasPlaceholders;
+                        Cow::Borrowed("v")
                     };
 
                     span_lint_and_sugg(
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index edceb755180..a2998d74130 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -81,6 +81,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "blacklisted_name",
     },
     Lint {
+        name: "blanket_clippy_restriction_lints",
+        group: "style",
+        desc: "enabling the complete restriction group",
+        deprecation: None,
+        module: "attrs",
+    },
+    Lint {
         name: "blocks_in_if_conditions",
         group: "style",
         desc: "useless or complex blocks that can be eliminated in conditions",
@@ -1145,6 +1152,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "methods",
     },
     Lint {
+        name: "map_identity",
+        group: "complexity",
+        desc: "using iterator.map(|x| x)",
+        deprecation: None,
+        module: "map_identity",
+    },
+    Lint {
         name: "map_unwrap_or",
         group: "pedantic",
         desc: "using `.map(f).unwrap_or(a)` or `.map(f).unwrap_or_else(func)`, which are more succinctly expressed as `map_or(a, f)` or `map_or_else(a, f)`",
@@ -1852,13 +1866,6 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         module: "reference",
     },
     Lint {
-        name: "regex_macro",
-        group: "style",
-        desc: "use of `regex!(_)` instead of `Regex::new(_)`",
-        deprecation: None,
-        module: "regex",
-    },
-    Lint {
         name: "rest_pat_in_fully_bound_structs",
         group: "restriction",
         desc: "a match on a struct that binds all fields but still uses the wildcard pattern",
diff --git a/tests/compile-test.rs b/tests/compile-test.rs
index 368fa6a98c5..99505fc6b29 100644
--- a/tests/compile-test.rs
+++ b/tests/compile-test.rs
@@ -155,9 +155,6 @@ fn run_ui_toml(config: &mut compiletest::Config) {
 }
 
 fn run_ui_cargo(config: &mut compiletest::Config) {
-    if cargo::is_rustc_test_suite() {
-        return;
-    }
     fn run_tests(
         config: &compiletest::Config,
         filter: &Option<String>,
diff --git a/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock
new file mode 100644
index 00000000000..7e96aa36feb
--- /dev/null
+++ b/tests/ui-cargo/multiple_crate_versions/fail/Cargo.lock
@@ -0,0 +1,109 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi 0.3.9",
+]
+
+[[package]]
+name = "bitflags"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "ctrlc"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "653abc99aa905f693d89df4797fadc08085baee379db92be9f2496cefe8a6f2c"
+dependencies = [
+ "kernel32-sys",
+ "nix",
+ "winapi 0.2.8",
+]
+
+[[package]]
+name = "kernel32-sys"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
+dependencies = [
+ "winapi 0.2.8",
+ "winapi-build",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.71"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49"
+
+[[package]]
+name = "multiple_crate_versions"
+version = "0.1.0"
+dependencies = [
+ "ansi_term",
+ "ctrlc",
+]
+
+[[package]]
+name = "nix"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2c5afeb0198ec7be8569d666644b574345aad2e95a53baf3a532da3e0f3fb32"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "libc",
+ "void",
+]
+
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+
+[[package]]
+name = "winapi"
+version = "0.2.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-build"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr
index 4f668599be9..f3113e09365 100644
--- a/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr
+++ b/tests/ui-cargo/multiple_crate_versions/fail/src/main.stderr
@@ -1,4 +1,4 @@
-error: multiple versions for dependency `winapi`: 0.2.8, 0.3.8
+error: multiple versions for dependency `winapi`: 0.2.8, 0.3.9
    |
    = note: `-D clippy::multiple-crate-versions` implied by `-D warnings`
 
diff --git a/tests/ui/attrs.rs b/tests/ui/attrs.rs
index 91b65a43be7..908d063729f 100644
--- a/tests/ui/attrs.rs
+++ b/tests/ui/attrs.rs
@@ -1,5 +1,11 @@
 #![warn(clippy::inline_always, clippy::deprecated_semver)]
 #![allow(clippy::assertions_on_constants)]
+// Test that the whole restriction group is not enabled
+#![warn(clippy::restriction)]
+#![deny(clippy::restriction)]
+#![forbid(clippy::restriction)]
+#![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)]
+
 #[inline(always)]
 fn test_attr_lint() {
     assert!(true)
diff --git a/tests/ui/attrs.stderr b/tests/ui/attrs.stderr
index 39ddf6f226d..ef4b89eaa6d 100644
--- a/tests/ui/attrs.stderr
+++ b/tests/ui/attrs.stderr
@@ -1,5 +1,5 @@
 error: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a bad idea
-  --> $DIR/attrs.rs:3:1
+  --> $DIR/attrs.rs:9:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | #[inline(always)]
    = note: `-D clippy::inline-always` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:23:14
+  --> $DIR/attrs.rs:29:14
    |
 LL | #[deprecated(since = "forever")]
    |              ^^^^^^^^^^^^^^^^^
@@ -15,10 +15,35 @@ LL | #[deprecated(since = "forever")]
    = note: `-D clippy::deprecated-semver` implied by `-D warnings`
 
 error: the since field must contain a semver-compliant version
-  --> $DIR/attrs.rs:26:14
+  --> $DIR/attrs.rs:32:14
    |
 LL | #[deprecated(since = "1")]
    |              ^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: restriction lints are not meant to be all enabled
+  --> $DIR/attrs.rs:4:9
+   |
+LL | #![warn(clippy::restriction)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::blanket-clippy-restriction-lints` implied by `-D warnings`
+   = help: try enabling only the lints you really need
+
+error: restriction lints are not meant to be all enabled
+  --> $DIR/attrs.rs:5:9
+   |
+LL | #![deny(clippy::restriction)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try enabling only the lints you really need
+
+error: restriction lints are not meant to be all enabled
+  --> $DIR/attrs.rs:6:11
+   |
+LL | #![forbid(clippy::restriction)]
+   |           ^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try enabling only the lints you really need
+
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/clone_on_copy.fixed b/tests/ui/clone_on_copy.fixed
new file mode 100644
index 00000000000..1f0ca101757
--- /dev/null
+++ b/tests/ui/clone_on_copy.fixed
@@ -0,0 +1,40 @@
+// run-rustfix
+
+#![allow(
+    unused,
+    clippy::redundant_clone,
+    clippy::deref_addrof,
+    clippy::no_effect,
+    clippy::unnecessary_operation
+)]
+
+use std::cell::RefCell;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+fn main() {}
+
+fn is_ascii(ch: char) -> bool {
+    ch.is_ascii()
+}
+
+fn clone_on_copy() {
+    42;
+
+    vec![1].clone(); // ok, not a Copy type
+    Some(vec![1]).clone(); // ok, not a Copy type
+    *(&42);
+
+    let rc = RefCell::new(0);
+    *rc.borrow();
+
+    // Issue #4348
+    let mut x = 43;
+    let _ = &x.clone(); // ok, getting a ref
+    'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
+    is_ascii('z');
+
+    // Issue #5436
+    let mut vec = Vec::new();
+    vec.push(42);
+}
diff --git a/tests/ui/clone_on_copy.rs b/tests/ui/clone_on_copy.rs
new file mode 100644
index 00000000000..ca39a654b4f
--- /dev/null
+++ b/tests/ui/clone_on_copy.rs
@@ -0,0 +1,40 @@
+// run-rustfix
+
+#![allow(
+    unused,
+    clippy::redundant_clone,
+    clippy::deref_addrof,
+    clippy::no_effect,
+    clippy::unnecessary_operation
+)]
+
+use std::cell::RefCell;
+use std::rc::{self, Rc};
+use std::sync::{self, Arc};
+
+fn main() {}
+
+fn is_ascii(ch: char) -> bool {
+    ch.is_ascii()
+}
+
+fn clone_on_copy() {
+    42.clone();
+
+    vec![1].clone(); // ok, not a Copy type
+    Some(vec![1]).clone(); // ok, not a Copy type
+    (&42).clone();
+
+    let rc = RefCell::new(0);
+    rc.borrow().clone();
+
+    // Issue #4348
+    let mut x = 43;
+    let _ = &x.clone(); // ok, getting a ref
+    'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
+    is_ascii('z'.clone());
+
+    // Issue #5436
+    let mut vec = Vec::new();
+    vec.push(42.clone());
+}
diff --git a/tests/ui/clone_on_copy.stderr b/tests/ui/clone_on_copy.stderr
new file mode 100644
index 00000000000..ec2faf4ab40
--- /dev/null
+++ b/tests/ui/clone_on_copy.stderr
@@ -0,0 +1,34 @@
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:22:5
+   |
+LL |     42.clone();
+   |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
+   |
+   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:26:5
+   |
+LL |     (&42).clone();
+   |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:29:5
+   |
+LL |     rc.borrow().clone();
+   |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:35:14
+   |
+LL |     is_ascii('z'.clone());
+   |              ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
+
+error: using `clone` on a `Copy` type
+  --> $DIR/clone_on_copy.rs:39:14
+   |
+LL |     vec.push(42.clone());
+   |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed
new file mode 100644
index 00000000000..3305ac9bf8b
--- /dev/null
+++ b/tests/ui/cmp_owned/asymmetric_partial_eq.fixed
@@ -0,0 +1,93 @@
+// run-rustfix
+#![allow(unused, clippy::redundant_clone)] // See #5700
+
+// Define the types in each module to avoid trait impls leaking between modules.
+macro_rules! impl_types {
+    () => {
+        #[derive(PartialEq)]
+        pub struct Owned;
+
+        pub struct Borrowed;
+
+        impl ToOwned for Borrowed {
+            type Owned = Owned;
+            fn to_owned(&self) -> Owned {
+                Owned {}
+            }
+        }
+
+        impl std::borrow::Borrow<Borrowed> for Owned {
+            fn borrow(&self) -> &Borrowed {
+                static VALUE: Borrowed = Borrowed {};
+                &VALUE
+            }
+        }
+    };
+}
+
+// Only Borrowed == Owned is implemented
+mod borrowed_eq_owned {
+    impl_types!();
+
+    impl PartialEq<Owned> for Borrowed {
+        fn eq(&self, _: &Owned) -> bool {
+            true
+        }
+    }
+
+    pub fn compare() {
+        let owned = Owned {};
+        let borrowed = Borrowed {};
+
+        if borrowed == owned {}
+        if borrowed == owned {}
+    }
+}
+
+// Only Owned == Borrowed is implemented
+mod owned_eq_borrowed {
+    impl_types!();
+
+    impl PartialEq<Borrowed> for Owned {
+        fn eq(&self, _: &Borrowed) -> bool {
+            true
+        }
+    }
+
+    fn compare() {
+        let owned = Owned {};
+        let borrowed = Borrowed {};
+
+        if owned == borrowed {}
+        if owned == borrowed {}
+    }
+}
+
+mod issue_4874 {
+    impl_types!();
+
+    // NOTE: PartialEq<Borrowed> for T can't be implemented due to the orphan rules
+    impl<T> PartialEq<T> for Borrowed
+    where
+        T: AsRef<str> + ?Sized,
+    {
+        fn eq(&self, _: &T) -> bool {
+            true
+        }
+    }
+
+    impl std::fmt::Display for Borrowed {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, "borrowed")
+        }
+    }
+
+    fn compare() {
+        let borrowed = Borrowed {};
+
+        if borrowed == "Hi" {}
+        if borrowed == "Hi" {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/tests/ui/cmp_owned/asymmetric_partial_eq.rs
new file mode 100644
index 00000000000..88bc2f51dd6
--- /dev/null
+++ b/tests/ui/cmp_owned/asymmetric_partial_eq.rs
@@ -0,0 +1,93 @@
+// run-rustfix
+#![allow(unused, clippy::redundant_clone)] // See #5700
+
+// Define the types in each module to avoid trait impls leaking between modules.
+macro_rules! impl_types {
+    () => {
+        #[derive(PartialEq)]
+        pub struct Owned;
+
+        pub struct Borrowed;
+
+        impl ToOwned for Borrowed {
+            type Owned = Owned;
+            fn to_owned(&self) -> Owned {
+                Owned {}
+            }
+        }
+
+        impl std::borrow::Borrow<Borrowed> for Owned {
+            fn borrow(&self) -> &Borrowed {
+                static VALUE: Borrowed = Borrowed {};
+                &VALUE
+            }
+        }
+    };
+}
+
+// Only Borrowed == Owned is implemented
+mod borrowed_eq_owned {
+    impl_types!();
+
+    impl PartialEq<Owned> for Borrowed {
+        fn eq(&self, _: &Owned) -> bool {
+            true
+        }
+    }
+
+    pub fn compare() {
+        let owned = Owned {};
+        let borrowed = Borrowed {};
+
+        if borrowed.to_owned() == owned {}
+        if owned == borrowed.to_owned() {}
+    }
+}
+
+// Only Owned == Borrowed is implemented
+mod owned_eq_borrowed {
+    impl_types!();
+
+    impl PartialEq<Borrowed> for Owned {
+        fn eq(&self, _: &Borrowed) -> bool {
+            true
+        }
+    }
+
+    fn compare() {
+        let owned = Owned {};
+        let borrowed = Borrowed {};
+
+        if owned == borrowed.to_owned() {}
+        if borrowed.to_owned() == owned {}
+    }
+}
+
+mod issue_4874 {
+    impl_types!();
+
+    // NOTE: PartialEq<Borrowed> for T can't be implemented due to the orphan rules
+    impl<T> PartialEq<T> for Borrowed
+    where
+        T: AsRef<str> + ?Sized,
+    {
+        fn eq(&self, _: &T) -> bool {
+            true
+        }
+    }
+
+    impl std::fmt::Display for Borrowed {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, "borrowed")
+        }
+    }
+
+    fn compare() {
+        let borrowed = Borrowed {};
+
+        if "Hi" == borrowed.to_string() {}
+        if borrowed.to_string() == "Hi" {}
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/cmp_owned/asymmetric_partial_eq.stderr b/tests/ui/cmp_owned/asymmetric_partial_eq.stderr
new file mode 100644
index 00000000000..43bf8851fc6
--- /dev/null
+++ b/tests/ui/cmp_owned/asymmetric_partial_eq.stderr
@@ -0,0 +1,46 @@
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:42:12
+   |
+LL |         if borrowed.to_owned() == owned {}
+   |            ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
+   |
+   = note: `-D clippy::cmp-owned` implied by `-D warnings`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:43:21
+   |
+LL |         if owned == borrowed.to_owned() {}
+   |            ---------^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            help: try: `borrowed == owned`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:61:21
+   |
+LL |         if owned == borrowed.to_owned() {}
+   |                     ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:62:12
+   |
+LL |         if borrowed.to_owned() == owned {}
+   |            ^^^^^^^^^^^^^^^^^^^---------
+   |            |
+   |            help: try: `owned == borrowed`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:88:20
+   |
+LL |         if "Hi" == borrowed.to_string() {}
+   |            --------^^^^^^^^^^^^^^^^^^^^
+   |            |
+   |            help: try: `borrowed == "Hi"`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/asymmetric_partial_eq.rs:89:12
+   |
+LL |         if borrowed.to_string() == "Hi" {}
+   |            ^^^^^^^^^^^^^^^^^^^^ help: try: `borrowed`
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/deprecated.rs b/tests/ui/deprecated.rs
index 188a641aa1a..3eefb232780 100644
--- a/tests/ui/deprecated.rs
+++ b/tests/ui/deprecated.rs
@@ -7,5 +7,6 @@
 #[warn(clippy::invalid_ref)]
 #[warn(clippy::into_iter_on_array)]
 #[warn(clippy::unused_label)]
+#[warn(clippy::regex_macro)]
 
 fn main() {}
diff --git a/tests/ui/deprecated.stderr b/tests/ui/deprecated.stderr
index a4efe3d15a9..a80e2bf31fe 100644
--- a/tests/ui/deprecated.stderr
+++ b/tests/ui/deprecated.stderr
@@ -54,11 +54,17 @@ error: lint `clippy::unused_label` has been removed: `this lint has been uplifte
 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
+   |
+LL | #[warn(clippy::regex_macro)]
+   |        ^^^^^^^^^^^^^^^^^^^
+
 error: lint `clippy::str_to_string` has been removed: `using `str::to_string` is common even today and specialization will likely happen soon`
   --> $DIR/deprecated.rs:1:8
    |
 LL | #[warn(clippy::str_to_string)]
    |        ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/map_flatten.fixed b/tests/ui/map_flatten.fixed
index 7ac368878ab..4171d80f48a 100644
--- a/tests/ui/map_flatten.fixed
+++ b/tests/ui/map_flatten.fixed
@@ -2,6 +2,7 @@
 
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(clippy::missing_docs_in_private_items)]
+#![allow(clippy::map_identity)]
 
 fn main() {
     let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect();
diff --git a/tests/ui/map_flatten.rs b/tests/ui/map_flatten.rs
index a608601039c..16a0fd090ad 100644
--- a/tests/ui/map_flatten.rs
+++ b/tests/ui/map_flatten.rs
@@ -2,6 +2,7 @@
 
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(clippy::missing_docs_in_private_items)]
+#![allow(clippy::map_identity)]
 
 fn main() {
     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
diff --git a/tests/ui/map_flatten.stderr b/tests/ui/map_flatten.stderr
index 3cf2abd5b6d..00bc41c15e9 100644
--- a/tests/ui/map_flatten.stderr
+++ b/tests/ui/map_flatten.stderr
@@ -1,5 +1,5 @@
 error: called `map(..).flatten()` on an `Iterator`. This is more succinctly expressed by calling `.flat_map(..)`
-  --> $DIR/map_flatten.rs:7:21
+  --> $DIR/map_flatten.rs:8:21
    |
 LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `flat_map` instead: `vec![5_i8; 6].into_iter().flat_map(|x| 0..x)`
@@ -7,7 +7,7 @@ LL |     let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().colle
    = note: `-D clippy::map-flatten` implied by `-D warnings`
 
 error: called `map(..).flatten()` on an `Option`. This is more succinctly expressed by calling `.and_then(..)`
-  --> $DIR/map_flatten.rs:8:24
+  --> $DIR/map_flatten.rs:9:24
    |
 LL |     let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using `and_then` instead: `(Some(Some(1))).and_then(|x| x)`
diff --git a/tests/ui/map_identity.fixed b/tests/ui/map_identity.fixed
new file mode 100644
index 00000000000..4a1452b25f3
--- /dev/null
+++ b/tests/ui/map_identity.fixed
@@ -0,0 +1,23 @@
+// run-rustfix
+#![warn(clippy::map_identity)]
+#![allow(clippy::needless_return)]
+
+fn main() {
+    let x: [u16; 3] = [1, 2, 3];
+    // should lint
+    let _: Vec<_> = x.iter().map(not_identity).collect();
+    let _: Vec<_> = x.iter().collect();
+    let _: Option<u8> = Some(3);
+    let _: Result<i8, f32> = Ok(-3);
+    // should not lint
+    let _: Vec<_> = x.iter().map(|x| 2 * x).collect();
+    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect();
+    let _: Option<u8> = None.map(|x: u8| x - 1);
+    let _: Result<i8, f32> = Err(2.3).map(|x: i8| {
+        return x + 3;
+    });
+}
+
+fn not_identity(x: &u16) -> u16 {
+    *x
+}
diff --git a/tests/ui/map_identity.rs b/tests/ui/map_identity.rs
new file mode 100644
index 00000000000..65c7e6e1ea5
--- /dev/null
+++ b/tests/ui/map_identity.rs
@@ -0,0 +1,25 @@
+// run-rustfix
+#![warn(clippy::map_identity)]
+#![allow(clippy::needless_return)]
+
+fn main() {
+    let x: [u16; 3] = [1, 2, 3];
+    // should lint
+    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
+    let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
+    let _: Option<u8> = Some(3).map(|x| x);
+    let _: Result<i8, f32> = Ok(-3).map(|x| {
+        return x;
+    });
+    // should not lint
+    let _: Vec<_> = x.iter().map(|x| 2 * x).collect();
+    let _: Vec<_> = x.iter().map(not_identity).map(|x| return x - 4).collect();
+    let _: Option<u8> = None.map(|x: u8| x - 1);
+    let _: Result<i8, f32> = Err(2.3).map(|x: i8| {
+        return x + 3;
+    });
+}
+
+fn not_identity(x: &u16) -> u16 {
+    *x
+}
diff --git a/tests/ui/map_identity.stderr b/tests/ui/map_identity.stderr
new file mode 100644
index 00000000000..e4a0320cbda
--- /dev/null
+++ b/tests/ui/map_identity.stderr
@@ -0,0 +1,37 @@
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:8:47
+   |
+LL |     let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
+   |                                               ^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+   |
+   = note: `-D clippy::map-identity` implied by `-D warnings`
+
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:9:57
+   |
+LL |     let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
+   |                                                         ^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:9:29
+   |
+LL |     let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:10:32
+   |
+LL |     let _: Option<u8> = Some(3).map(|x| x);
+   |                                ^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+  --> $DIR/map_identity.rs:11:36
+   |
+LL |       let _: Result<i8, f32> = Ok(-3).map(|x| {
+   |  ____________________________________^
+LL | |         return x;
+LL | |     });
+   | |______^ help: remove the call to `map`
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs
index b523fa5b711..9767e5bf76a 100644
--- a/tests/ui/regex.rs
+++ b/tests/ui/regex.rs
@@ -1,5 +1,5 @@
 #![allow(unused)]
-#![warn(clippy::invalid_regex, clippy::trivial_regex, clippy::regex_macro)]
+#![warn(clippy::invalid_regex, clippy::trivial_regex)]
 
 extern crate regex;
 
diff --git a/tests/ui/unnecessary_clone.rs b/tests/ui/unnecessary_clone.rs
index f1cc5b564c1..2c9d4d39e6c 100644
--- a/tests/ui/unnecessary_clone.rs
+++ b/tests/ui/unnecessary_clone.rs
@@ -13,31 +13,6 @@ impl SomeTrait for SomeImpl {}
 
 fn main() {}
 
-fn is_ascii(ch: char) -> bool {
-    ch.is_ascii()
-}
-
-fn clone_on_copy() {
-    42.clone();
-
-    vec![1].clone(); // ok, not a Copy type
-    Some(vec![1]).clone(); // ok, not a Copy type
-    (&42).clone();
-
-    let rc = RefCell::new(0);
-    rc.borrow().clone();
-
-    // Issue #4348
-    let mut x = 43;
-    let _ = &x.clone(); // ok, getting a ref
-    'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate
-    is_ascii('z'.clone());
-
-    // Issue #5436
-    let mut vec = Vec::new();
-    vec.push(42.clone());
-}
-
 fn clone_on_ref_ptr() {
     let rc = Rc::new(true);
     let arc = Arc::new(true);
diff --git a/tests/ui/unnecessary_clone.stderr b/tests/ui/unnecessary_clone.stderr
index 6176a2bc464..113fab69009 100644
--- a/tests/ui/unnecessary_clone.stderr
+++ b/tests/ui/unnecessary_clone.stderr
@@ -1,37 +1,5 @@
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:21:5
-   |
-LL |     42.clone();
-   |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
-   |
-   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
-
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:25:5
-   |
-LL |     (&42).clone();
-   |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
-
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:28:5
-   |
-LL |     rc.borrow().clone();
-   |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
-
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:34:14
-   |
-LL |     is_ascii('z'.clone());
-   |              ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
-
-error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:38:14
-   |
-LL |     vec.push(42.clone());
-   |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
-
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:48:5
+  --> $DIR/unnecessary_clone.rs:23:5
    |
 LL |     rc.clone();
    |     ^^^^^^^^^^ help: try this: `Rc::<bool>::clone(&rc)`
@@ -39,43 +7,45 @@ LL |     rc.clone();
    = note: `-D clippy::clone-on-ref-ptr` implied by `-D warnings`
 
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:51:5
+  --> $DIR/unnecessary_clone.rs:26:5
    |
 LL |     arc.clone();
    |     ^^^^^^^^^^^ help: try this: `Arc::<bool>::clone(&arc)`
 
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:54:5
+  --> $DIR/unnecessary_clone.rs:29:5
    |
 LL |     rcweak.clone();
    |     ^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&rcweak)`
 
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:57:5
+  --> $DIR/unnecessary_clone.rs:32:5
    |
 LL |     arc_weak.clone();
    |     ^^^^^^^^^^^^^^^^ help: try this: `Weak::<bool>::clone(&arc_weak)`
 
 error: using `.clone()` on a ref-counted pointer
-  --> $DIR/unnecessary_clone.rs:61:33
+  --> $DIR/unnecessary_clone.rs:36:33
    |
 LL |     let _: Arc<dyn SomeTrait> = x.clone();
    |                                 ^^^^^^^^^ help: try this: `Arc::<SomeImpl>::clone(&x)`
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:65:5
+  --> $DIR/unnecessary_clone.rs:40:5
    |
 LL |     t.clone();
    |     ^^^^^^^^^ help: try removing the `clone` call: `t`
+   |
+   = note: `-D clippy::clone-on-copy` implied by `-D warnings`
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:67:5
+  --> $DIR/unnecessary_clone.rs:42:5
    |
 LL |     Some(t).clone();
    |     ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)`
 
 error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
-  --> $DIR/unnecessary_clone.rs:73:22
+  --> $DIR/unnecessary_clone.rs:48:22
    |
 LL |     let z: &Vec<_> = y.clone();
    |                      ^^^^^^^^^
@@ -91,13 +61,13 @@ LL |     let z: &Vec<_> = <&std::vec::Vec<i32>>::clone(y);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using `clone` on a `Copy` type
-  --> $DIR/unnecessary_clone.rs:109:20
+  --> $DIR/unnecessary_clone.rs:84:20
    |
 LL |         let _: E = a.clone();
    |                    ^^^^^^^^^ help: try dereferencing it: `*****a`
 
 error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
-  --> $DIR/unnecessary_clone.rs:114:22
+  --> $DIR/unnecessary_clone.rs:89:22
    |
 LL |         let _ = &mut encoded.clone();
    |                      ^^^^^^^^^^^^^^^
@@ -112,7 +82,7 @@ LL |         let _ = &mut <&[u8]>::clone(encoded);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: using `clone` on a double-reference; this will copy the reference instead of cloning the inner type
-  --> $DIR/unnecessary_clone.rs:115:18
+  --> $DIR/unnecessary_clone.rs:90:18
    |
 LL |         let _ = &encoded.clone();
    |                  ^^^^^^^^^^^^^^^
@@ -126,5 +96,5 @@ help: or try being explicit if you are sure, that you want to clone a reference
 LL |         let _ = &<&[u8]>::clone(encoded);
    |                  ^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 16 previous errors
+error: aborting due to 11 previous errors
 
diff --git a/tests/ui/unnested_or_patterns3.rs b/tests/ui/unnested_or_patterns3.rs
new file mode 100644
index 00000000000..6bd35057bfa
--- /dev/null
+++ b/tests/ui/unnested_or_patterns3.rs
@@ -0,0 +1,6 @@
+#![warn(clippy::unnested_or_patterns)]
+
+// Test that `unnested_or_patterns` does not trigger without enabling `or_patterns`
+fn main() {
+    if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {}
+}
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 -- "$@"