about summary refs log tree commit diff
diff options
context:
space:
mode:
authorflip1995 <philipp.krones@embecosm.com>2021-06-17 10:21:47 +0200
committerflip1995 <philipp.krones@embecosm.com>2021-06-17 10:21:47 +0200
commite3eede7b905aec5c1bd23fe48444411f012d823a (patch)
treef4582226b013b7b4c577b18477005316762b65f8
parent611b74e1fe48410c534c5d5a6a0832b810d8ccda (diff)
parent7c9da3c1e4f22504efbc198d5428ea2ac963b924 (diff)
downloadrust-e3eede7b905aec5c1bd23fe48444411f012d823a.tar.gz
rust-e3eede7b905aec5c1bd23fe48444411f012d823a.zip
Merge remote-tracking branch 'upstream/master' into rustup
-rw-r--r--.github/workflows/clippy_bors.yml5
-rw-r--r--CHANGELOG.md2
-rw-r--r--clippy_lints/src/bytecount.rs70
-rw-r--r--clippy_lints/src/collapsible_match.rs20
-rw-r--r--clippy_lints/src/default.rs3
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs4
-rw-r--r--clippy_lints/src/disallowed_method.rs29
-rw-r--r--clippy_lints/src/disallowed_type.rs126
-rw-r--r--clippy_lints/src/lib.rs16
-rw-r--r--clippy_lints/src/loops/manual_memcpy.rs7
-rw-r--r--clippy_lints/src/loops/needless_collect.rs97
-rw-r--r--clippy_lints/src/loops/while_let_on_iterator.rs11
-rw-r--r--clippy_lints/src/manual_map.rs20
-rw-r--r--clippy_lints/src/map_identity.rs126
-rw-r--r--clippy_lints/src/methods/append_instead_of_extend.rs41
-rw-r--r--clippy_lints/src/methods/filter_map_identity.rs40
-rw-r--r--clippy_lints/src/methods/flat_map_identity.rs44
-rw-r--r--clippy_lints/src/methods/map_identity.rs38
-rw-r--r--clippy_lints/src/methods/mod.rs59
-rw-r--r--clippy_lints/src/missing_doc.rs19
-rw-r--r--clippy_lints/src/mutable_debug_assertion.rs4
-rw-r--r--clippy_lints/src/non_expressive_names.rs3
-rw-r--r--clippy_lints/src/redundant_clone.rs4
-rw-r--r--clippy_lints/src/semicolon_if_nothing_returned.rs2
-rw-r--r--clippy_lints/src/unnested_or_patterns.rs5
-rw-r--r--clippy_lints/src/use_self.rs180
-rw-r--r--clippy_lints/src/utils/conf.rs4
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs37
-rw-r--r--clippy_utils/src/ast_utils.rs13
-rw-r--r--clippy_utils/src/consts.rs10
-rw-r--r--clippy_utils/src/lib.rs94
-rw-r--r--clippy_utils/src/ptr.rs32
-rw-r--r--doc/common_tools_writing_lints.md2
-rw-r--r--doc/release.md15
-rw-r--r--tests/ui-toml/toml_disallowed_method/clippy.toml6
-rw-r--r--tests/ui-toml/toml_disallowed_type/clippy.toml9
-rw-r--r--tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs35
-rw-r--r--tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr88
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--tests/ui/append_instead_of_extend.fixed55
-rw-r--r--tests/ui/append_instead_of_extend.rs55
-rw-r--r--tests/ui/append_instead_of_extend.stderr22
-rw-r--r--tests/ui/assertions_on_constants.rs3
-rw-r--r--tests/ui/auxiliary/macro_rules.rs7
-rw-r--r--tests/ui/default_numeric_fallback.rs23
-rw-r--r--tests/ui/default_numeric_fallback.stderr61
-rw-r--r--tests/ui/doc.rs2
-rw-r--r--tests/ui/field_reassign_with_default.rs20
-rw-r--r--tests/ui/field_reassign_with_default.stderr36
-rw-r--r--tests/ui/filter_map_identity.fixed5
-rw-r--r--tests/ui/filter_map_identity.rs5
-rw-r--r--tests/ui/filter_map_identity.stderr14
-rw-r--r--tests/ui/flat_map_identity.fixed5
-rw-r--r--tests/ui/flat_map_identity.rs5
-rw-r--r--tests/ui/flat_map_identity.stderr12
-rw-r--r--tests/ui/semicolon_if_nothing_returned.rs44
-rw-r--r--tests/ui/semicolon_if_nothing_returned.stderr14
-rw-r--r--tests/ui/temporary_assignment.rs1
-rw-r--r--tests/ui/temporary_assignment.stderr8
-rw-r--r--tests/ui/use_self.fixed23
-rw-r--r--tests/ui/use_self.rs25
-rw-r--r--tests/ui/use_self.stderr4
-rw-r--r--tests/ui/while_let_on_iterator.fixed14
-rw-r--r--tests/ui/while_let_on_iterator.rs14
-rw-r--r--tests/ui/while_let_on_iterator.stderr10
65 files changed, 1182 insertions, 627 deletions
diff --git a/.github/workflows/clippy_bors.yml b/.github/workflows/clippy_bors.yml
index f27fee87dc1..ae6f1aa1b30 100644
--- a/.github/workflows/clippy_bors.yml
+++ b/.github/workflows/clippy_bors.yml
@@ -90,11 +90,6 @@ jobs:
     - name: Checkout
       uses: actions/checkout@v2.3.3
 
-    # FIXME: should not be necessary once 1.24.2 is the default version on the windows runner
-    - name: Update rustup
-      run: rustup self update
-      if: runner.os == 'Windows'
-
     - name: Install toolchain
       run: rustup show active-toolchain
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 41af8e190dd..52d0e8c7cde 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2295,6 +2295,7 @@ Released 2018-09-13
 <!-- begin autogenerated links to lint list -->
 [`absurd_extreme_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
 [`almost_swapped`]: https://rust-lang.github.io/rust-clippy/master/index.html#almost_swapped
+[`append_instead_of_extend`]: https://rust-lang.github.io/rust-clippy/master/index.html#append_instead_of_extend
 [`approx_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#approx_constant
 [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
 [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
@@ -2358,6 +2359,7 @@ Released 2018-09-13
 [`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
 [`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
 [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
+[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs
index 877ae002d36..4f7ffdcdfb4 100644
--- a/clippy_lints/src/bytecount.rs
+++ b/clippy_lints/src/bytecount.rs
@@ -1,15 +1,15 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::match_type;
-use clippy_utils::{contains_name, get_pat_name, paths, single_segment_path};
+use clippy_utils::visitors::LocalUsedVisitor;
+use clippy_utils::{path_to_local_id, paths, peel_ref_operators, remove_blocks, strip_pat_refs};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp};
+use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, UintTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
-use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for naive byte counts
@@ -38,42 +38,43 @@ declare_lint_pass!(ByteCount => [NAIVE_BYTECOUNT]);
 impl<'tcx> LateLintPass<'tcx> for ByteCount {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(count, _, count_args, _) = expr.kind;
+            if let ExprKind::MethodCall(count, _, [count_recv], _) = expr.kind;
             if count.ident.name == sym!(count);
-            if count_args.len() == 1;
-            if let ExprKind::MethodCall(filter, _, filter_args, _) = count_args[0].kind;
+            if let ExprKind::MethodCall(filter, _, [filter_recv, filter_arg], _) = count_recv.kind;
             if filter.ident.name == sym!(filter);
-            if filter_args.len() == 2;
-            if let ExprKind::Closure(_, _, body_id, _, _) = filter_args[1].kind;
+            if let ExprKind::Closure(_, _, body_id, _, _) = filter_arg.kind;
             let body = cx.tcx.hir().body(body_id);
-            if body.params.len() == 1;
-            if let Some(argname) = get_pat_name(body.params[0].pat);
+            if let [param] = body.params;
+            if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
             if let ExprKind::Binary(ref op, l, r) = body.value.kind;
             if op.node == BinOpKind::Eq;
             if match_type(cx,
-                       cx.typeck_results().expr_ty(&filter_args[0]).peel_refs(),
+                       cx.typeck_results().expr_ty(filter_recv).peel_refs(),
                        &paths::SLICE_ITER);
+            let operand_is_arg = |expr| {
+                let expr = peel_ref_operators(cx, remove_blocks(expr));
+                path_to_local_id(expr, arg_id)
+            };
+            let needle = if operand_is_arg(l) {
+                r
+            } else if operand_is_arg(r) {
+                l
+            } else {
+                return;
+            };
+            if ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(needle).peel_refs().kind();
+            if !LocalUsedVisitor::new(cx, arg_id).check_expr(needle);
             then {
-                let needle = match get_path_name(l) {
-                    Some(name) if check_arg(name, argname, r) => r,
-                    _ => match get_path_name(r) {
-                        Some(name) if check_arg(name, argname, l) => l,
-                        _ => { return; }
-                    }
-                };
-                if ty::Uint(UintTy::U8) != *cx.typeck_results().expr_ty(needle).peel_refs().kind() {
-                    return;
-                }
                 let haystack = if let ExprKind::MethodCall(path, _, args, _) =
-                        filter_args[0].kind {
+                        filter_recv.kind {
                     let p = path.ident.name;
                     if (p == sym::iter || p == sym!(iter_mut)) && args.len() == 1 {
                         &args[0]
                     } else {
-                        &filter_args[0]
+                        &filter_recv
                     }
                 } else {
-                    &filter_args[0]
+                    &filter_recv
                 };
                 let mut applicability = Applicability::MaybeIncorrect;
                 span_lint_and_sugg(
@@ -91,24 +92,3 @@ impl<'tcx> LateLintPass<'tcx> for ByteCount {
         };
     }
 }
-
-fn check_arg(name: Symbol, arg: Symbol, needle: &Expr<'_>) -> bool {
-    name == arg && !contains_name(name, needle)
-}
-
-fn get_path_name(expr: &Expr<'_>) -> Option<Symbol> {
-    match expr.kind {
-        ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) | ExprKind::Unary(UnOp::Deref, e) => {
-            get_path_name(e)
-        },
-        ExprKind::Block(b, _) => {
-            if b.stmts.is_empty() {
-                b.expr.as_ref().and_then(|p| get_path_name(p))
-            } else {
-                None
-            }
-        },
-        ExprKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
-        _ => None,
-    }
-}
diff --git a/clippy_lints/src/collapsible_match.rs b/clippy_lints/src/collapsible_match.rs
index ab22578abd6..a6c3a5b0e83 100644
--- a/clippy_lints/src/collapsible_match.rs
+++ b/clippy_lints/src/collapsible_match.rs
@@ -1,11 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::visitors::LocalUsedVisitor;
-use clippy_utils::{is_lang_ctor, path_to_local, SpanlessEq};
+use clippy_utils::{is_lang_ctor, path_to_local, peel_ref_operators, SpanlessEq};
 use if_chain::if_chain;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind, UnOp};
+use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::TypeckResults;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{MultiSpan, Span};
 
@@ -73,7 +72,7 @@ fn check_arm<'tcx>(arm: &Arm<'tcx>, wild_outer_arm: &Arm<'tcx>, cx: &LateContext
         if arms_inner.iter().all(|arm| arm.guard.is_none());
         // match expression must be a local binding
         // match <local> { .. }
-        if let Some(binding_id) = path_to_local(strip_ref_operators(expr_in, cx.typeck_results()));
+        if let Some(binding_id) = path_to_local(peel_ref_operators(cx, expr_in));
         // one of the branches must be "wild-like"
         if let Some(wild_inner_arm_idx) = arms_inner.iter().rposition(|arm_inner| arm_is_wild_like(cx, arm_inner));
         let (wild_inner_arm, non_wild_inner_arm) =
@@ -163,16 +162,3 @@ fn pat_contains_or(pat: &Pat<'_>) -> bool {
     });
     result
 }
-
-/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
-/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
-fn strip_ref_operators<'hir>(mut expr: &'hir Expr<'hir>, typeck_results: &TypeckResults<'_>) -> &'hir Expr<'hir> {
-    loop {
-        match expr.kind {
-            ExprKind::AddrOf(_, _, e) => expr = e,
-            ExprKind::Unary(UnOp::Deref, e) if typeck_results.expr_ty(e).is_ref() => expr = e,
-            _ => break,
-        }
-    }
-    expr
-}
diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs
index 7a53d390bb4..947479db8f5 100644
--- a/clippy_lints/src/default.rs
+++ b/clippy_lints/src/default.rs
@@ -7,7 +7,6 @@ use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{Ident, Symbol};
@@ -122,7 +121,7 @@ impl LateLintPass<'_> for Default {
                 if let StmtKind::Local(local) = stmt.kind;
                 if let Some(expr) = local.init;
                 if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
-                if !in_external_macro(cx.tcx.sess, expr.span);
+                if !in_macro(expr.span);
                 // only take bindings to identifiers
                 if let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind;
                 // only when assigning `... = Default::default()`
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index 759f7d4062d..a125376bffa 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -7,9 +7,10 @@ use rustc_hir::{
     intravisit::{walk_expr, walk_stmt, NestedVisitorMap, Visitor},
     Body, Expr, ExprKind, HirId, Lit, Stmt, StmtKind,
 };
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::{
     hir::map::Map,
+    lint::in_external_macro,
     ty::{self, FloatTy, IntTy, PolyFnSig, Ty},
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -73,6 +74,7 @@ impl<'a, 'tcx> NumericFallbackVisitor<'a, 'tcx> {
     /// Check whether a passed literal has potential to cause fallback or not.
     fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>) {
         if_chain! {
+                if !in_external_macro(self.cx.sess(), lit.span);
                 if let Some(ty_bound) = self.ty_bounds.last();
                 if matches!(lit.node,
                             LitKind::Int(_, LitIntType::Unsuffixed) | LitKind::Float(_, LitFloatType::Unsuffixed));
diff --git a/clippy_lints/src/disallowed_method.rs b/clippy_lints/src/disallowed_method.rs
index ded0a0fff54..aa1a609afed 100644
--- a/clippy_lints/src/disallowed_method.rs
+++ b/clippy_lints/src/disallowed_method.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
 use clippy_utils::fn_def_id;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::Expr;
+use rustc_hir::{def::Res, def_id::DefId, Crate, Expr};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Symbol;
@@ -13,21 +13,14 @@ declare_clippy_lint! {
     /// **Why is this bad?** Some methods are undesirable in certain contexts,
     /// and it's beneficial to lint for them as needed.
     ///
-    /// **Known problems:** Currently, you must write each function as a
-    /// fully-qualified path. This lint doesn't support aliases or reexported
-    /// names; be aware that many types in `std` are actually reexports.
-    ///
-    /// For example, if you want to disallow `Duration::as_secs`, your clippy.toml
-    /// configuration would look like
-    /// `disallowed-methods = ["core::time::Duration::as_secs"]` and not
-    /// `disallowed-methods = ["std::time::Duration::as_secs"]` as you might expect.
+    /// **Known problems:** None.
     ///
     /// **Example:**
     ///
     /// An example clippy.toml configuration:
     /// ```toml
     /// # clippy.toml
-    /// disallowed-methods = ["alloc::vec::Vec::leak", "std::time::Instant::now"]
+    /// disallowed-methods = ["std::vec::Vec::leak", "std::time::Instant::now"]
     /// ```
     ///
     /// ```rust,ignore
@@ -52,6 +45,7 @@ declare_clippy_lint! {
 #[derive(Clone, Debug)]
 pub struct DisallowedMethod {
     disallowed: FxHashSet<Vec<Symbol>>,
+    def_ids: FxHashSet<(DefId, Vec<Symbol>)>,
 }
 
 impl DisallowedMethod {
@@ -61,6 +55,7 @@ impl DisallowedMethod {
                 .iter()
                 .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
                 .collect(),
+            def_ids: FxHashSet::default(),
         }
     }
 }
@@ -68,10 +63,20 @@ impl DisallowedMethod {
 impl_lint_pass!(DisallowedMethod => [DISALLOWED_METHOD]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedMethod {
+    fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
+        for path in &self.disallowed {
+            let segs = path.iter().map(ToString::to_string).collect::<Vec<_>>();
+            if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::<Vec<_>>())
+            {
+                self.def_ids.insert((id, path.clone()));
+            }
+        }
+    }
+
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let Some(def_id) = fn_def_id(cx, expr) {
-            let func_path = cx.get_def_path(def_id);
-            if self.disallowed.contains(&func_path) {
+            if self.def_ids.iter().any(|(id, _)| def_id == *id) {
+                let func_path = cx.get_def_path(def_id);
                 let func_path_string = func_path
                     .into_iter()
                     .map(Symbol::to_ident_string)
diff --git a/clippy_lints/src/disallowed_type.rs b/clippy_lints/src/disallowed_type.rs
new file mode 100644
index 00000000000..e4a88c6324e
--- /dev/null
+++ b/clippy_lints/src/disallowed_type.rs
@@ -0,0 +1,126 @@
+use clippy_utils::diagnostics::span_lint;
+
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::{
+    def::Res, def_id::DefId, Crate, Item, ItemKind, PolyTraitRef, TraitBoundModifier, Ty, TyKind, UseKind,
+};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::{Span, Symbol};
+
+declare_clippy_lint! {
+    /// **What it does:** Denies the configured types in clippy.toml.
+    ///
+    /// **Why is this bad?** Some types are undesirable in certain contexts.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// N.B. There is no way to ban primitive types.
+    ///
+    /// **Example:**
+    ///
+    /// An example clippy.toml configuration:
+    /// ```toml
+    /// # clippy.toml
+    /// disallowed-methods = ["std::collections::BTreeMap"]
+    /// ```
+    ///
+    /// ```rust,ignore
+    /// use std::collections::BTreeMap;
+    /// // or its use
+    /// let x = std::collections::BTreeMap::new();
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// // A similar type that is allowed by the config
+    /// use std::collections::HashMap;
+    /// ```
+    pub DISALLOWED_TYPE,
+    nursery,
+    "use of a disallowed type"
+}
+#[derive(Clone, Debug)]
+pub struct DisallowedType {
+    disallowed: FxHashSet<Vec<Symbol>>,
+    def_ids: FxHashSet<(DefId, Vec<Symbol>)>,
+}
+
+impl DisallowedType {
+    pub fn new(disallowed: &FxHashSet<String>) -> Self {
+        Self {
+            disallowed: disallowed
+                .iter()
+                .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
+                .collect(),
+            def_ids: FxHashSet::default(),
+        }
+    }
+}
+
+impl_lint_pass!(DisallowedType => [DISALLOWED_TYPE]);
+
+impl<'tcx> LateLintPass<'tcx> for DisallowedType {
+    fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
+        for path in &self.disallowed {
+            let segs = path.iter().map(ToString::to_string).collect::<Vec<_>>();
+            if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::<Vec<_>>())
+            {
+                self.def_ids.insert((id, path.clone()));
+            }
+        }
+    }
+
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if_chain! {
+            if let ItemKind::Use(path, UseKind::Single) = &item.kind;
+            if let Res::Def(_, did) = path.res;
+            if let Some((_, name)) = self.def_ids.iter().find(|(id, _)| *id == did);
+            then {
+                emit(cx, name, item.span,);
+            }
+        }
+    }
+
+    fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
+        if_chain! {
+            if let TyKind::Path(path) = &ty.kind;
+            if let Some(did) = cx.qpath_res(path, ty.hir_id).opt_def_id();
+            if let Some((_, name)) = self.def_ids.iter().find(|(id, _)| *id == did);
+            then {
+                emit(cx, name, path.span());
+            }
+        }
+    }
+
+    fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>, _: TraitBoundModifier) {
+        if_chain! {
+            if let Res::Def(_, did) = poly.trait_ref.path.res;
+            if let Some((_, name)) = self.def_ids.iter().find(|(id, _)| *id == did);
+            then {
+                emit(cx, name, poly.trait_ref.path.span);
+            }
+        }
+    }
+
+    // TODO: if non primitive const generics are a thing
+    // fn check_generic_arg(&mut self, cx: &LateContext<'tcx>, arg: &'tcx GenericArg<'tcx>) {
+    //     match arg {
+    //         GenericArg::Const(c) => {},
+    //     }
+    // }
+    // fn check_generic_param(&mut self, cx: &LateContext<'tcx>, param: &'tcx GenericParam<'tcx>) {
+    //     match param.kind {
+    //         GenericParamKind::Const { .. } => {},
+    //     }
+    // }
+}
+
+fn emit(cx: &LateContext<'_>, name: &[Symbol], span: Span) {
+    let name = name.iter().map(|s| s.to_ident_string()).collect::<Vec<_>>().join("::");
+    span_lint(
+        cx,
+        DISALLOWED_TYPE,
+        span,
+        &format!("`{}` is not allowed according to config", name),
+    );
+}
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index e7dd3952b3a..5ab333f8aa1 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -187,6 +187,7 @@ mod default_numeric_fallback;
 mod dereference;
 mod derive;
 mod disallowed_method;
+mod disallowed_type;
 mod doc;
 mod double_comparison;
 mod double_parens;
@@ -254,7 +255,6 @@ mod manual_strip;
 mod manual_unwrap_or;
 mod map_clone;
 mod map_err_ignore;
-mod map_identity;
 mod map_unit_fn;
 mod match_on_vec_items;
 mod matches;
@@ -583,6 +583,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         derive::EXPL_IMPL_CLONE_ON_COPY,
         derive::UNSAFE_DERIVE_DESERIALIZE,
         disallowed_method::DISALLOWED_METHOD,
+        disallowed_type::DISALLOWED_TYPE,
         doc::DOC_MARKDOWN,
         doc::MISSING_ERRORS_DOC,
         doc::MISSING_PANICS_DOC,
@@ -705,7 +706,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         manual_unwrap_or::MANUAL_UNWRAP_OR,
         map_clone::MAP_CLONE,
         map_err_ignore::MAP_ERR_IGNORE,
-        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,
@@ -730,6 +730,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         mem_replace::MEM_REPLACE_OPTION_WITH_NONE,
         mem_replace::MEM_REPLACE_WITH_DEFAULT,
         mem_replace::MEM_REPLACE_WITH_UNINIT,
+        methods::APPEND_INSTEAD_OF_EXTEND,
         methods::BIND_INSTEAD_OF_MAP,
         methods::BYTES_NTH,
         methods::CHARS_LAST_CMP,
@@ -765,6 +766,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         methods::MANUAL_STR_REPEAT,
         methods::MAP_COLLECT_RESULT_UNIT,
         methods::MAP_FLATTEN,
+        methods::MAP_IDENTITY,
         methods::MAP_UNWRAP_OR,
         methods::NEW_RET_NO_SELF,
         methods::OK_EXPECT,
@@ -1260,7 +1262,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(manual_strip::MANUAL_STRIP),
         LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
         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),
@@ -1276,6 +1277,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
         LintId::of(mem_replace::MEM_REPLACE_WITH_DEFAULT),
         LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT),
+        LintId::of(methods::APPEND_INSTEAD_OF_EXTEND),
         LintId::of(methods::BIND_INSTEAD_OF_MAP),
         LintId::of(methods::BYTES_NTH),
         LintId::of(methods::CHARS_LAST_CMP),
@@ -1301,6 +1303,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
         LintId::of(methods::MANUAL_STR_REPEAT),
         LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
+        LintId::of(methods::MAP_IDENTITY),
         LintId::of(methods::NEW_RET_NO_SELF),
         LintId::of(methods::OK_EXPECT),
         LintId::of(methods::OPTION_AS_REF_DEREF),
@@ -1586,7 +1589,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(loops::WHILE_LET_LOOP),
         LintId::of(manual_strip::MANUAL_STRIP),
         LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
-        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),
@@ -1601,6 +1603,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(methods::ITER_COUNT),
         LintId::of(methods::MANUAL_FILTER_MAP),
         LintId::of(methods::MANUAL_FIND_MAP),
+        LintId::of(methods::MAP_IDENTITY),
         LintId::of(methods::OPTION_AS_REF_DEREF),
         LintId::of(methods::OPTION_FILTER_MAP),
         LintId::of(methods::SEARCH_IS_SOME),
@@ -1735,6 +1738,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(large_enum_variant::LARGE_ENUM_VARIANT),
         LintId::of(loops::MANUAL_MEMCPY),
         LintId::of(loops::NEEDLESS_COLLECT),
+        LintId::of(methods::APPEND_INSTEAD_OF_EXTEND),
         LintId::of(methods::EXPECT_FUN_CALL),
         LintId::of(methods::ITER_NTH),
         LintId::of(methods::MANUAL_STR_REPEAT),
@@ -1761,6 +1765,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
         LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
         LintId::of(disallowed_method::DISALLOWED_METHOD),
+        LintId::of(disallowed_type::DISALLOWED_TYPE),
         LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
         LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
         LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
@@ -2039,7 +2044,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         single_char_binding_names_threshold,
     });
     store.register_late_pass(|| box macro_use::MacroUseImports::default());
-    store.register_late_pass(|| box map_identity::MapIdentity);
     store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
     store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
     store.register_late_pass(|| box repeat_once::RepeatOnce);
@@ -2066,6 +2070,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
     store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
     store.register_late_pass(|| box unused_async::UnusedAsync);
+    let disallowed_types = conf.disallowed_types.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || box disallowed_type::DisallowedType::new(&disallowed_types));
 
 }
 
diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs
index c91fe88757e..47005aba388 100644
--- a/clippy_lints/src/loops/manual_memcpy.rs
+++ b/clippy_lints/src/loops/manual_memcpy.rs
@@ -204,11 +204,8 @@ struct MinifyingSugg<'a>(Sugg<'a>);
 
 impl<'a> MinifyingSugg<'a> {
     fn as_str(&self) -> &str {
-        // HACK: Don't sync to Clippy! Required because something with the `or_patterns` feature
-        // changed and this would now require parentheses.
-        match &self.0 {
-            Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s) => s.as_ref(),
-        }
+        let (Sugg::NonParen(s) | Sugg::MaybeParen(s) | Sugg::BinOp(_, s)) = &self.0;
+        s.as_ref()
     }
 
     fn into_sugg(self) -> Sugg<'a> {
diff --git a/clippy_lints/src/loops/needless_collect.rs b/clippy_lints/src/loops/needless_collect.rs
index eb82c9c27c3..51d7def137e 100644
--- a/clippy_lints/src/loops/needless_collect.rs
+++ b/clippy_lints/src/loops/needless_collect.rs
@@ -7,10 +7,10 @@ use clippy_utils::{is_trait_method, path_to_local_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty};
+use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, StmtKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-use rustc_span::symbol::{sym, Ident};
+use rustc_span::sym;
 use rustc_span::{MultiSpan, Span};
 
 const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
@@ -24,10 +24,8 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
         if let ExprKind::MethodCall(method, _, args, _) = expr.kind;
         if let ExprKind::MethodCall(chain_method, method0_span, _, _) = args[0].kind;
         if chain_method.ident.name == sym!(collect) && is_trait_method(cx, &args[0], sym::Iterator);
-        if let Some(generic_args) = chain_method.args;
-        if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0);
-        if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id);
         then {
+            let ty = cx.typeck_results().expr_ty(&args[0]);
             let mut applicability = Applicability::MachineApplicable;
             let is_empty_sugg = "next().is_none()".to_string();
             let method_name = &*method.ident.name.as_str();
@@ -72,40 +70,25 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont
 }
 
 fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateContext<'tcx>) {
-    fn get_hir_id<'tcx>(ty: Option<&Ty<'tcx>>, method_args: Option<&GenericArgs<'tcx>>) -> Option<HirId> {
-        if let Some(ty) = ty {
-            return Some(ty.hir_id);
-        }
-
-        if let Some(generic_args) = method_args {
-            if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0) {
-                return Some(ty.hir_id);
-            }
-        }
-
-        None
-    }
     if let ExprKind::Block(block, _) = expr.kind {
         for stmt in block.stmts {
             if_chain! {
-                if let StmtKind::Local(
-                    Local { pat: Pat { hir_id: pat_id, kind: PatKind::Binding(_, _, ident, .. ), .. },
-                    init: Some(init_expr), ty, .. }
-                ) = stmt.kind;
+                if let StmtKind::Local(local) = stmt.kind;
+                if let PatKind::Binding(_, id, ..) = local.pat.kind;
+                if let Some(init_expr) = local.init;
                 if let ExprKind::MethodCall(method_name, collect_span, &[ref iter_source], ..) = init_expr.kind;
                 if method_name.ident.name == sym!(collect) && is_trait_method(cx, init_expr, sym::Iterator);
-                if let Some(hir_id) = get_hir_id(*ty, method_name.args);
-                if let Some(ty) = cx.typeck_results().node_type_opt(hir_id);
+                let ty = cx.typeck_results().expr_ty(init_expr);
                 if is_type_diagnostic_item(cx, ty, sym::vec_type) ||
                     is_type_diagnostic_item(cx, ty, sym::vecdeque_type) ||
                     is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
                     is_type_diagnostic_item(cx, ty, sym::LinkedList);
-                if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident);
+                if let Some(iter_calls) = detect_iter_and_into_iters(block, id);
                 if let [iter_call] = &*iter_calls;
                 then {
                     let mut used_count_visitor = UsedCountVisitor {
                         cx,
-                        id: *pat_id,
+                        id,
                         count: 0,
                     };
                     walk_block(&mut used_count_visitor, block);
@@ -187,48 +170,40 @@ enum IterFunctionKind {
 struct IterFunctionVisitor {
     uses: Vec<IterFunction>,
     seen_other: bool,
-    target: Ident,
+    target: HirId,
 }
 impl<'tcx> Visitor<'tcx> for IterFunctionVisitor {
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         // Check function calls on our collection
-        if_chain! {
-            if let ExprKind::MethodCall(method_name, _, args, _) = &expr.kind;
-            if let Some(Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. }) = args.get(0);
-            if let &[name] = &path.segments;
-            if name.ident == self.target;
-            then {
-                let len = sym!(len);
-                let is_empty = sym!(is_empty);
-                let contains = sym!(contains);
-                match method_name.ident.name {
-                    sym::into_iter => self.uses.push(
-                        IterFunction { func: IterFunctionKind::IntoIter, span: expr.span }
-                    ),
-                    name if name == len => self.uses.push(
-                        IterFunction { func: IterFunctionKind::Len, span: expr.span }
-                    ),
-                    name if name == is_empty => self.uses.push(
-                        IterFunction { func: IterFunctionKind::IsEmpty, span: expr.span }
-                    ),
-                    name if name == contains => self.uses.push(
-                        IterFunction { func: IterFunctionKind::Contains(args[1].span), span: expr.span }
-                    ),
+        if let ExprKind::MethodCall(method_name, _, [recv, args @ ..], _) = &expr.kind {
+            if path_to_local_id(recv, self.target) {
+                match &*method_name.ident.name.as_str() {
+                    "into_iter" => self.uses.push(IterFunction {
+                        func: IterFunctionKind::IntoIter,
+                        span: expr.span,
+                    }),
+                    "len" => self.uses.push(IterFunction {
+                        func: IterFunctionKind::Len,
+                        span: expr.span,
+                    }),
+                    "is_empty" => self.uses.push(IterFunction {
+                        func: IterFunctionKind::IsEmpty,
+                        span: expr.span,
+                    }),
+                    "contains" => self.uses.push(IterFunction {
+                        func: IterFunctionKind::Contains(args[0].span),
+                        span: expr.span,
+                    }),
                     _ => self.seen_other = true,
                 }
-                return
+                return;
             }
         }
         // Check if the collection is used for anything else
-        if_chain! {
-            if let Expr { kind: ExprKind::Path(QPath::Resolved(_, path)), .. } = expr;
-            if let &[name] = &path.segments;
-            if name.ident == self.target;
-            then {
-                self.seen_other = true;
-            } else {
-                walk_expr(self, expr);
-            }
+        if path_to_local_id(expr, self.target) {
+            self.seen_other = true;
+        } else {
+            walk_expr(self, expr);
         }
     }
 
@@ -262,10 +237,10 @@ impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
 
 /// 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>> {
+fn detect_iter_and_into_iters<'tcx>(block: &'tcx Block<'tcx>, id: HirId) -> Option<Vec<IterFunction>> {
     let mut visitor = IterFunctionVisitor {
         uses: Vec::new(),
-        target: identifier,
+        target: id,
         seen_other: false,
     };
     visitor.visit_block(block);
diff --git a/clippy_lints/src/loops/while_let_on_iterator.rs b/clippy_lints/src/loops/while_let_on_iterator.rs
index 63560047578..d57588716a5 100644
--- a/clippy_lints/src/loops/while_let_on_iterator.rs
+++ b/clippy_lints/src/loops/while_let_on_iterator.rs
@@ -1,7 +1,9 @@
 use super::WHILE_LET_ON_ITERATOR;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{get_enclosing_loop, is_refutable, is_trait_method, match_def_path, paths, visitors::is_res_used};
+use clippy_utils::{
+    get_enclosing_loop_or_closure, is_refutable, is_trait_method, match_def_path, paths, visitors::is_res_used,
+};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
@@ -315,9 +317,10 @@ fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr:
         }
     }
 
-    if let Some(e) = get_enclosing_loop(cx.tcx, loop_expr) {
-        // The iterator expression will be used on the next iteration unless it is declared within the outer
-        // loop.
+    if let Some(e) = get_enclosing_loop_or_closure(cx.tcx, loop_expr) {
+        // The iterator expression will be used on the next iteration (for loops), or on the next call (for
+        // closures) unless it is declared within the enclosing expression. TODO: Check for closures
+        // used where an `FnOnce` type is expected.
         let local_id = match iter_expr.path {
             Res::Local(id) => id,
             _ => return true,
diff --git a/clippy_lints/src/manual_map.rs b/clippy_lints/src/manual_map.rs
index 0b873534f2c..97e4a983f32 100644
--- a/clippy_lints/src/manual_map.rs
+++ b/clippy_lints/src/manual_map.rs
@@ -3,19 +3,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
 use clippy_utils::{
-    can_move_expr_to_closure, in_constant, is_allowed, is_else_clause, is_lang_ctor, match_var, peel_hir_expr_refs,
+    can_move_expr_to_closure, in_constant, is_allowed, is_else_clause, is_lang_ctor, path_to_local_id,
+    peel_hir_expr_refs,
 };
 use rustc_ast::util::parser::PREC_POSTFIX;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind};
+use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, HirId, MatchSource, Mutability, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{
-    symbol::{sym, Ident},
-    SyntaxContext,
-};
+use rustc_span::{sym, SyntaxContext};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usages of `match` which could be implemented using `map`
@@ -141,13 +139,13 @@ impl LateLintPass<'_> for ManualMap {
                     scrutinee_str.into()
                 };
 
-            let body_str = if let PatKind::Binding(annotation, _, some_binding, None) = some_pat.kind {
-                match can_pass_as_func(cx, some_binding, some_expr) {
+            let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind {
+                match can_pass_as_func(cx, id, some_expr) {
                     Some(func) if func.span.ctxt() == some_expr.span.ctxt() => {
                         snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
                     },
                     _ => {
-                        if match_var(some_expr, some_binding.name)
+                        if path_to_local_id(some_expr, id)
                             && !is_allowed(cx, MATCH_AS_REF, expr.hir_id)
                             && binding_ref.is_some()
                         {
@@ -199,10 +197,10 @@ impl LateLintPass<'_> for ManualMap {
 
 // Checks whether the expression could be passed as a function, or whether a closure is needed.
 // Returns the function to be passed to `map` if it exists.
-fn can_pass_as_func(cx: &LateContext<'tcx>, binding: Ident, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     match expr.kind {
         ExprKind::Call(func, [arg])
-            if match_var(arg, binding.name) && cx.typeck_results().expr_adjustments(arg).is_empty() =>
+            if path_to_local_id(arg, binding) && cx.typeck_results().expr_adjustments(arg).is_empty() =>
         {
             Some(func)
         },
diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs
deleted file mode 100644
index 41cda23510e..00000000000
--- a/clippy_lints/src/map_identity.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_adjusted, is_qpath_def_path, is_trait_method, match_var, paths, remove_blocks};
-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};
-use rustc_span::sym;
-
-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(method, _, args, _) = expr.kind;
-        if args.len() == 2 && method.ident.name == sym::map;
-        let caller_ty = cx.typeck_results().expr_ty(&args[0]);
-        if is_trait_method(cx, expr, sym::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(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::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(ret_val)) => match_expr_param(cx, ret_val, params[0].pat),
-        ExprKind::Block(block, _) => {
-            if_chain! {
-                if block.stmts.len() == 1;
-                if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = block.stmts[0].kind;
-                if let ExprKind::Ret(Some(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.typeck_results().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr))
-    } else {
-        false
-    }
-}
diff --git a/clippy_lints/src/methods/append_instead_of_extend.rs b/clippy_lints/src/methods/append_instead_of_extend.rs
new file mode 100644
index 00000000000..e39a5a1efd1
--- /dev/null
+++ b/clippy_lints/src/methods/append_instead_of_extend.rs
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem};
+use rustc_lint::LateContext;
+use rustc_span::symbol::sym;
+
+use super::APPEND_INSTEAD_OF_EXTEND;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
+    let ty = cx.typeck_results().expr_ty(recv).peel_refs();
+    if_chain! {
+        if is_type_diagnostic_item(cx, ty, sym::vec_type);
+        //check source object
+        if let ExprKind::MethodCall(src_method, _, [drain_vec, drain_arg], _) = &arg.kind;
+        if src_method.ident.as_str() == "drain";
+        if let src_ty = cx.typeck_results().expr_ty(drain_vec).peel_refs();
+        if is_type_diagnostic_item(cx, src_ty, sym::vec_type);
+        //check drain range
+        if let src_ty_range = cx.typeck_results().expr_ty(drain_arg).peel_refs();
+        if is_type_lang_item(cx, src_ty_range, LangItem::RangeFull);
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                APPEND_INSTEAD_OF_EXTEND,
+                expr.span,
+                "use of `extend` instead of `append` for adding the full range of a second vector",
+                "try this",
+                format!(
+                    "{}.append(&mut {})",
+                    snippet_with_applicability(cx, recv.span, "..", &mut applicability),
+                    snippet_with_applicability(cx, drain_vec.span, "..", &mut applicability)
+                ),
+                applicability,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/filter_map_identity.rs b/clippy_lints/src/methods/filter_map_identity.rs
index 403fe8d3546..d1b5e945dfd 100644
--- a/clippy_lints/src/methods/filter_map_identity.rs
+++ b/clippy_lints/src/methods/filter_map_identity.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_path_def_path, is_trait_method, path_to_local_id, paths};
-use if_chain::if_chain;
+use clippy_utils::{is_expr_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -9,32 +8,15 @@ use rustc_span::{source_map::Span, sym};
 use super::FILTER_MAP_IDENTITY;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
-    if is_trait_method(cx, expr, sym::Iterator) {
-        let apply_lint = |message: &str| {
-            span_lint_and_sugg(
-                cx,
-                FILTER_MAP_IDENTITY,
-                filter_map_span.with_hi(expr.span.hi()),
-                message,
-                "try",
-                "flatten()".to_string(),
-                Applicability::MachineApplicable,
-            );
-        };
-
-        if_chain! {
-            if let hir::ExprKind::Closure(_, _, body_id, _, _) = filter_map_arg.kind;
-            let body = cx.tcx.hir().body(body_id);
-
-            if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind;
-            if path_to_local_id(&body.value, binding_id);
-            then {
-                apply_lint("called `filter_map(|x| x)` on an `Iterator`");
-            }
-        }
-
-        if is_expr_path_def_path(cx, filter_map_arg, &paths::CONVERT_IDENTITY) {
-            apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`");
-        }
+    if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) {
+        span_lint_and_sugg(
+            cx,
+            FILTER_MAP_IDENTITY,
+            filter_map_span.with_hi(expr.span.hi()),
+            "use of `filter_map` with an identity function",
+            "try",
+            "flatten()".to_string(),
+            Applicability::MachineApplicable,
+        );
     }
 }
diff --git a/clippy_lints/src/methods/flat_map_identity.rs b/clippy_lints/src/methods/flat_map_identity.rs
index 25f8434cb94..6f911d79d0b 100644
--- a/clippy_lints/src/methods/flat_map_identity.rs
+++ b/clippy_lints/src/methods/flat_map_identity.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_path_def_path, is_trait_method, paths};
-use if_chain::if_chain;
+use clippy_utils::{is_expr_identity_function, is_trait_method};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -15,36 +14,15 @@ pub(super) fn check<'tcx>(
     flat_map_arg: &'tcx hir::Expr<'_>,
     flat_map_span: Span,
 ) {
-    if is_trait_method(cx, expr, sym::Iterator) {
-        let apply_lint = |message: &str| {
-            span_lint_and_sugg(
-                cx,
-                FLAT_MAP_IDENTITY,
-                flat_map_span.with_hi(expr.span.hi()),
-                message,
-                "try",
-                "flatten()".to_string(),
-                Applicability::MachineApplicable,
-            );
-        };
-
-        if_chain! {
-            if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_arg.kind;
-            let body = cx.tcx.hir().body(body_id);
-
-            if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind;
-            if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind;
-
-            if path.segments.len() == 1;
-            if path.segments[0].ident.name == binding_ident.name;
-
-            then {
-                apply_lint("called `flat_map(|x| x)` on an `Iterator`");
-            }
-        }
-
-        if is_expr_path_def_path(cx, flat_map_arg, &paths::CONVERT_IDENTITY) {
-            apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
-        }
+    if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) {
+        span_lint_and_sugg(
+            cx,
+            FLAT_MAP_IDENTITY,
+            flat_map_span.with_hi(expr.span.hi()),
+            "use of `flat_map` with an identity function",
+            "try",
+            "flatten()".to_string(),
+            Applicability::MachineApplicable,
+        );
     }
 }
diff --git a/clippy_lints/src/methods/map_identity.rs b/clippy_lints/src/methods/map_identity.rs
new file mode 100644
index 00000000000..538a12566e3
--- /dev/null
+++ b/clippy_lints/src/methods/map_identity.rs
@@ -0,0 +1,38 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_expr_identity_function, is_trait_method};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_span::{source_map::Span, sym};
+
+use super::MAP_IDENTITY;
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    caller: &hir::Expr<'_>,
+    map_arg: &hir::Expr<'_>,
+    _map_span: Span,
+) {
+    let caller_ty = cx.typeck_results().expr_ty(caller);
+
+    if_chain! {
+        if is_trait_method(cx, expr, sym::Iterator)
+            || is_type_diagnostic_item(cx, caller_ty, sym::result_type)
+            || is_type_diagnostic_item(cx, caller_ty, sym::option_type);
+        if is_expr_identity_function(cx, map_arg);
+        if let Some(sugg_span) = expr.span.trim_start(caller.span);
+        then {
+            span_lint_and_sugg(
+                cx,
+                MAP_IDENTITY,
+                sugg_span,
+                "unnecessary map of the identity function",
+                "remove the call to `map`",
+                String::new(),
+                Applicability::MachineApplicable,
+            )
+        }
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index c8ae972f18c..b556dcb4dfe 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -1,3 +1,4 @@
+mod append_instead_of_extend;
 mod bind_instead_of_map;
 mod bytes_nth;
 mod chars_cmp;
@@ -35,6 +36,7 @@ mod manual_saturating_arithmetic;
 mod manual_str_repeat;
 mod map_collect_result_unit;
 mod map_flatten;
+mod map_identity;
 mod map_unwrap_or;
 mod ok_expect;
 mod option_as_ref_deref;
@@ -1032,6 +1034,30 @@ declare_clippy_lint! {
 }
 
 declare_clippy_lint! {
+    /// **What it does:** Checks for occurrences where one vector gets extended instead of append
+    ///
+    /// **Why is this bad?** Using `append` instead of `extend` is more concise and faster
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// let mut a = vec![1, 2, 3];
+    /// let mut b = vec![4, 5, 6];
+    ///
+    /// // Bad
+    /// a.extend(b.drain(..));
+    ///
+    /// // Good
+    /// a.append(&mut b);
+    /// ```
+    pub APPEND_INSTEAD_OF_EXTEND,
+    perf,
+    "using vec.append(&mut vec) to move the full range of a vecor to another"
+}
+
+declare_clippy_lint! {
     /// **What it does:** Checks for the use of `.extend(s.chars())` where s is a
     /// `&str` or `String`.
     ///
@@ -1562,6 +1588,29 @@ declare_clippy_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_clippy_lint! {
     /// **What it does:** Checks for the use of `.bytes().nth()`.
     ///
     /// **Why is this bad?** `.as_bytes().get()` is more efficient and more
@@ -1728,6 +1777,7 @@ impl_lint_pass!(Methods => [
     FILTER_NEXT,
     SKIP_WHILE_NEXT,
     FILTER_MAP_IDENTITY,
+    MAP_IDENTITY,
     MANUAL_FILTER_MAP,
     MANUAL_FIND_MAP,
     OPTION_FILTER_MAP,
@@ -1760,7 +1810,8 @@ impl_lint_pass!(Methods => [
     INSPECT_FOR_EACH,
     IMPLICIT_CLONE,
     SUSPICIOUS_SPLITN,
-    MANUAL_STR_REPEAT
+    MANUAL_STR_REPEAT,
+    APPEND_INSTEAD_OF_EXTEND
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -2022,7 +2073,10 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
                 _ => expect_used::check(cx, expr, recv),
             },
-            ("extend", [arg]) => string_extend_chars::check(cx, expr, recv, arg),
+            ("extend", [arg]) => {
+                string_extend_chars::check(cx, expr, recv, arg);
+                append_instead_of_extend::check(cx, expr, recv, arg);
+            },
             ("filter_map", [arg]) => {
                 unnecessary_filter_map::check(cx, expr, arg);
                 filter_map_identity::check(cx, expr, arg, span);
@@ -2058,6 +2112,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                         _ => {},
                     }
                 }
+                map_identity::check(cx, expr, recv, m_arg, span);
             },
             ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
             ("next", []) => {
diff --git a/clippy_lints/src/missing_doc.rs b/clippy_lints/src/missing_doc.rs
index a46a7407df0..ec1572c26c2 100644
--- a/clippy_lints/src/missing_doc.rs
+++ b/clippy_lints/src/missing_doc.rs
@@ -7,7 +7,8 @@
 
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast;
+use if_chain::if_chain;
+use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
@@ -55,6 +56,20 @@ impl MissingDoc {
         *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
     }
 
+    fn has_include(meta: Option<MetaItem>) -> bool {
+        if_chain! {
+            if let Some(meta) = meta;
+            if let MetaItemKind::List(list) = meta.kind;
+            if let Some(meta) = list.get(0);
+            if let Some(name) = meta.ident();
+            then {
+                name.name == sym::include
+            } else {
+                false
+            }
+        }
+    }
+
     fn check_missing_docs_attrs(
         &self,
         cx: &LateContext<'_>,
@@ -80,7 +95,7 @@ impl MissingDoc {
 
         let has_doc = attrs
             .iter()
-            .any(|a| a.doc_str().is_some());
+            .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
         if !has_doc {
             span_lint(
                 cx,
diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs
index 25645a0e7a2..81bf853300f 100644
--- a/clippy_lints/src/mutable_debug_assertion.rs
+++ b/clippy_lints/src/mutable_debug_assertion.rs
@@ -87,10 +87,6 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
                 self.found = true;
                 return;
             },
-            ExprKind::If(..) => {
-                self.found = true;
-                return;
-            },
             ExprKind::Path(_) => {
                 if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
                     if adj
diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs
index 1a23e6afe28..b81f8d24a33 100644
--- a/clippy_lints/src/non_expressive_names.rs
+++ b/clippy_lints/src/non_expressive_names.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use rustc_ast::ast::{
-    Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat,
-    PatKind,
+    Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, FnKind, Item, ItemKind, Local, Pat, PatKind,
 };
 use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
 use rustc_lint::{EarlyContext, EarlyLintPass};
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index 7dafce60d5e..380557c81a1 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -132,7 +132,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
                 }
             }
 
-            // `{ cloned = &arg; clone(move cloned); }` or `{ cloned = &arg; to_path_buf(cloned); }`
+            // `{ arg = &cloned; clone(move arg); }` or `{ arg = &cloned; to_path_buf(arg); }`
             let (cloned, cannot_move_out) = unwrap_or_continue!(find_stmt_assigns_to(cx, mir, arg, from_borrow, bb));
 
             let loc = mir::Location {
@@ -628,7 +628,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
         BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
             visit_op(lhs);
             visit_op(rhs);
-        }
+        },
         _ => (),
     }
 }
diff --git a/clippy_lints/src/semicolon_if_nothing_returned.rs b/clippy_lints/src/semicolon_if_nothing_returned.rs
index 16e4d73851f..da3e30af35c 100644
--- a/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -1,3 +1,4 @@
+use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_macro_callsite;
 use clippy_utils::{in_macro, sugg};
@@ -45,6 +46,7 @@ impl LateLintPass<'_> for SemicolonIfNothingReturned {
             if t_expr.is_unit();
             if let snippet = snippet_with_macro_callsite(cx, expr.span, "}");
             if !snippet.ends_with('}');
+            if cx.sess().source_map().is_multiline(block.span);
             then {
                 // filter out the desugared `for` loop
                 if let ExprKind::DropTemps(..) = &expr.kind {
diff --git a/clippy_lints/src/unnested_or_patterns.rs b/clippy_lints/src/unnested_or_patterns.rs
index 1b3c457b01a..07a4e294049 100644
--- a/clippy_lints/src/unnested_or_patterns.rs
+++ b/clippy_lints/src/unnested_or_patterns.rs
@@ -1,6 +1,6 @@
 #![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
 
-use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_pat, eq_path, eq_maybe_qself};
+use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::{meets_msrv, msrvs, over};
 use rustc_ast::mut_visit::*;
@@ -277,7 +277,8 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
             ps1, start, alternatives,
             |k, ps1, idx| matches!(
                 k,
-                TupleStruct(qself2, path2, ps2) if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
+                TupleStruct(qself2, path2, ps2)
+                    if eq_maybe_qself(qself1, qself2) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx)
             ),
             |k| always_pat!(k, TupleStruct(_, _, ps) => ps),
         ),
diff --git a/clippy_lints/src/use_self.rs b/clippy_lints/src/use_self.rs
index 254b104bdef..f71dfd02499 100644
--- a/clippy_lints/src/use_self.rs
+++ b/clippy_lints/src/use_self.rs
@@ -1,23 +1,21 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::same_type_and_consts;
 use clippy_utils::{in_macro, meets_msrv, msrvs};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{
     self as hir,
-    def::{self, DefKind},
+    def::{CtorOf, DefKind, Res},
     def_id::LocalDefId,
     intravisit::{walk_ty, NestedVisitorMap, Visitor},
-    Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, PathSegment,
-    QPath, TyKind,
+    Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, QPath, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::{AssocKind, Ty};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{BytePos, Span};
+use rustc_span::Span;
 use rustc_typeck::hir_ty_to_ty;
 
 declare_clippy_lint! {
@@ -234,111 +232,58 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
     }
 
     fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
-        if in_macro(hir_ty.span)
-            || in_impl(cx, hir_ty)
-            || !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS)
-        {
-            return;
-        }
-
-        let lint_dependend_on_expr_kind = if let Some(StackItem::Check {
-            hir_id,
-            types_to_lint,
-            types_to_skip,
-            ..
-        }) = self.stack.last()
-        {
-            if types_to_skip.contains(&hir_ty.hir_id) {
-                false
-            } else if types_to_lint.contains(&hir_ty.hir_id) {
-                true
-            } else {
-                let self_ty = ty_from_hir_id(cx, *hir_id);
-                should_lint_ty(hir_ty, hir_ty_to_ty(cx.tcx, hir_ty), self_ty)
-            }
-        } else {
-            false
-        };
-
-        if lint_dependend_on_expr_kind {
-            // FIXME: this span manipulation should not be necessary
-            // @flip1995 found an ast lowering issue in
-            // https://github.com/rust-lang/rust/blob/master/src/librustc_ast_lowering/path.rs#l142-l162
+        if_chain! {
+            if !in_macro(hir_ty.span) && !in_impl(cx, hir_ty);
+            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+            if let Some(StackItem::Check {
+                hir_id,
+                types_to_lint,
+                types_to_skip,
+                ..
+            }) = self.stack.last();
+            if !types_to_skip.contains(&hir_ty.hir_id);
+            if types_to_lint.contains(&hir_ty.hir_id)
+                || {
+                    let self_ty = ty_from_hir_id(cx, *hir_id);
+                    should_lint_ty(hir_ty, hir_ty_to_ty(cx.tcx, hir_ty), self_ty)
+                };
             let hir = cx.tcx.hir();
             let id = hir.get_parent_node(hir_ty.hir_id);
-
-            if !hir.opt_span(id).map_or(false, in_macro) {
-                match hir.find(id) {
-                    Some(Node::Expr(Expr {
-                        kind: ExprKind::Path(QPath::TypeRelative(_, segment)),
-                        ..
-                    })) => span_lint_until_last_segment(cx, hir_ty.span, segment),
-                    _ => span_lint(cx, hir_ty.span),
-                }
+            if !hir.opt_span(id).map_or(false, in_macro);
+            then {
+                span_lint(cx, hir_ty.span);
             }
         }
     }
 
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        fn expr_ty_matches(cx: &LateContext<'_>, expr: &Expr<'_>, self_ty: Ty<'_>) -> bool {
-            let def_id = expr.hir_id.owner;
-            if cx.tcx.has_typeck_results(def_id) {
-                cx.tcx.typeck(def_id).expr_ty_opt(expr) == Some(self_ty)
-            } else {
-                false
-            }
-        }
-
-        if in_macro(expr.span) || !meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS) {
-            return;
+        if_chain! {
+            if !in_macro(expr.span);
+            if meets_msrv(self.msrv.as_ref(), &msrvs::TYPE_ALIAS_ENUM_VARIANTS);
+            if let Some(StackItem::Check { hir_id, .. }) = self.stack.last();
+            if cx.typeck_results().expr_ty(expr) == ty_from_hir_id(cx, *hir_id);
+            then {} else { return; }
         }
-
-        if let Some(StackItem::Check { hir_id, .. }) = self.stack.last() {
-            let self_ty = ty_from_hir_id(cx, *hir_id);
-
-            match &expr.kind {
-                ExprKind::Struct(QPath::Resolved(_, path), ..) => {
-                    if expr_ty_matches(cx, expr, self_ty) {
-                        match path.res {
-                            def::Res::SelfTy(..) => (),
-                            def::Res::Def(DefKind::Variant, _) => span_lint_on_path_until_last_segment(cx, path),
-                            _ => {
-                                span_lint(cx, path.span);
-                            },
-                        }
-                    }
-                },
-                // tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
-                ExprKind::Call(fun, _) => {
-                    if let Expr {
-                        kind: ExprKind::Path(ref qpath),
-                        ..
-                    } = fun
-                    {
-                        if expr_ty_matches(cx, expr, self_ty) {
-                            let res = cx.qpath_res(qpath, fun.hir_id);
-
-                            if let def::Res::Def(DefKind::Ctor(ctor_of, _), ..) = res {
-                                match ctor_of {
-                                    def::CtorOf::Variant => {
-                                        span_lint_on_qpath_resolved(cx, qpath, true);
-                                    },
-                                    def::CtorOf::Struct => {
-                                        span_lint_on_qpath_resolved(cx, qpath, false);
-                                    },
-                                }
-                            }
+        match expr.kind {
+            ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
+                Res::SelfTy(..) => (),
+                Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
+                _ => span_lint(cx, path.span),
+            },
+            // tuple struct instantiation (`Foo(arg)` or `Enum::Foo(arg)`)
+            ExprKind::Call(fun, _) => {
+                if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind {
+                    if let Res::Def(DefKind::Ctor(ctor_of, _), ..) = path.res {
+                        match ctor_of {
+                            CtorOf::Variant => lint_path_to_variant(cx, path),
+                            CtorOf::Struct => span_lint(cx, path.span),
                         }
                     }
-                },
-                // unit enum variants (`Enum::A`)
-                ExprKind::Path(qpath) => {
-                    if expr_ty_matches(cx, expr, self_ty) {
-                        span_lint_on_qpath_resolved(cx, qpath, true);
-                    }
-                },
-                _ => (),
-            }
+                }
+            },
+            // unit enum variants (`Enum::A`)
+            ExprKind::Path(QPath::Resolved(_, path)) => lint_path_to_variant(cx, path),
+            _ => (),
         }
     }
 
@@ -405,33 +350,12 @@ fn span_lint(cx: &LateContext<'_>, span: Span) {
     );
 }
 
-#[allow(clippy::cast_possible_truncation)]
-fn span_lint_until_last_segment(cx: &LateContext<'_>, span: Span, segment: &PathSegment<'_>) {
-    let sp = span.with_hi(segment.ident.span.lo());
-    // remove the trailing ::
-    let span_without_last_segment = match snippet_opt(cx, sp) {
-        Some(snippet) => match snippet.rfind("::") {
-            Some(bidx) => sp.with_hi(sp.lo() + BytePos(bidx as u32)),
-            None => sp,
-        },
-        None => sp,
-    };
-    span_lint(cx, span_without_last_segment);
-}
-
-fn span_lint_on_path_until_last_segment(cx: &LateContext<'_>, path: &Path<'_>) {
-    if path.segments.len() > 1 {
-        span_lint_until_last_segment(cx, path.span, path.segments.last().unwrap());
-    }
-}
-
-fn span_lint_on_qpath_resolved(cx: &LateContext<'_>, qpath: &QPath<'_>, until_last_segment: bool) {
-    if let QPath::Resolved(_, path) = qpath {
-        if until_last_segment {
-            span_lint_on_path_until_last_segment(cx, path);
-        } else {
-            span_lint(cx, path.span);
-        }
+fn lint_path_to_variant(cx: &LateContext<'_>, path: &Path<'_>) {
+    if let [.., self_seg, _variant] = path.segments {
+        let span = path
+            .span
+            .with_hi(self_seg.args().span_ext().unwrap_or(self_seg.ident.span).hi());
+        span_lint(cx, span);
     }
 }
 
@@ -462,7 +386,7 @@ fn should_lint_ty(hir_ty: &hir::Ty<'_>, ty: Ty<'_>, self_ty: Ty<'_>) -> bool {
         if same_type_and_consts(ty, self_ty);
         if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
         then {
-            !matches!(path.res, def::Res::SelfTy(..))
+            !matches!(path.res, Res::SelfTy(..) | Res::Def(DefKind::TyParam, _))
         } else {
             false
         }
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 0e33ae740d9..ad2cb27650e 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -149,7 +149,7 @@ define_Conf! {
         "WebGL",
         "TensorFlow",
         "TrueType",
-        "iOS", "macOS",
+        "iOS", "macOS", "FreeBSD",
         "TeX", "LaTeX", "BibTeX", "BibLaTeX",
         "MinGW",
         "CamelCase",
@@ -190,6 +190,8 @@ define_Conf! {
     (warn_on_all_wildcard_imports: bool = false),
     /// Lint: DISALLOWED_METHOD. The list of disallowed methods, written as fully qualified paths.
     (disallowed_methods: Vec<String> = Vec::new()),
+    /// Lint: DISALLOWED_TYPE. The list of disallowed types, written as fully qualified paths.
+    (disallowed_types: Vec<String> = Vec::new()),
     /// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators.
     (unreadable_literal_lint_fractions: bool = true),
     /// Lint: UPPER_CASE_ACRONYMS. Enables verbose mode. Triggers if there is more than one uppercase char next to each other
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 46af03663b8..c980a0246fd 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -9,6 +9,7 @@
 //! a simple mistake)
 
 use if_chain::if_chain;
+use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{
     self as hir, def::DefKind, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath,
@@ -485,16 +486,32 @@ fn extract_attr_docs_or_lint(cx: &LateContext<'_>, item: &Item<'_>) -> Option<St
 ///
 /// Would result in `Hello world!\n=^.^=\n`
 fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> {
-    cx.tcx
-        .hir()
-        .attrs(item.hir_id())
-        .iter()
-        .filter_map(|x| x.doc_str().map(|sym| sym.as_str().to_string()))
-        .reduce(|mut acc, sym| {
-            acc.push_str(&sym);
-            acc.push('\n');
-            acc
-        })
+    let attrs = cx.tcx.hir().attrs(item.hir_id());
+    let mut lines = attrs.iter().filter_map(ast::Attribute::doc_str);
+    let mut docs = String::from(&*lines.next()?.as_str());
+    let mut in_code_block = false;
+    for line in lines {
+        docs.push('\n');
+        let line = line.as_str();
+        let line = &*line;
+        if let Some(info) = line.trim_start().strip_prefix("```") {
+            in_code_block = !in_code_block;
+            if in_code_block {
+                let lang = info
+                    .trim()
+                    .split(',')
+                    // remove rustdoc directives
+                    .find(|&s| !matches!(s, "" | "ignore" | "no_run" | "should_panic"))
+                    // if no language is present, fill in "rust"
+                    .unwrap_or("rust");
+                docs.push_str("```");
+                docs.push_str(lang);
+                continue;
+            }
+        }
+        docs.push_str(line);
+    }
+    Some(docs)
 }
 
 fn get_lint_group_and_level_or_lint(
diff --git a/clippy_utils/src/ast_utils.rs b/clippy_utils/src/ast_utils.rs
index e6d84bc7560..30c2260d15c 100644
--- a/clippy_utils/src/ast_utils.rs
+++ b/clippy_utils/src/ast_utils.rs
@@ -47,9 +47,14 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool {
         | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r),
         (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)),
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
-        (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)),
+        (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => {
+            eq_maybe_qself(lqself, rqself) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r))
+        },
         (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => {
-            lr == rr && eq_maybe_qself(lqself, rqself) &&eq_path(lp, rp) && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
+            lr == rr
+                && eq_maybe_qself(lqself, rqself)
+                && eq_path(lp, rp)
+                && unordered_over(lfs, rfs, |lf, rf| eq_field_pat(lf, rf))
         },
         (Or(ls), Or(rs)) => unordered_over(ls, rs, |l, r| eq_pat(l, r)),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
@@ -82,7 +87,7 @@ pub fn eq_maybe_qself(l: &Option<QSelf>, r: &Option<QSelf>) -> bool {
     match (l, r) {
         (Some(l), Some(r)) => eq_qself(l, r),
         (None, None) => true,
-        _ => false
+        _ => false,
     }
 }
 
@@ -178,7 +183,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Path(lq, lp), Path(rq, rp)) => both(lq, rq, |l, r| eq_qself(l, r)) && eq_path(lp, rp),
         (MacCall(l), MacCall(r)) => eq_mac_call(l, r),
         (Struct(lse), Struct(rse)) => {
-            eq_maybe_qself(&lse.qself, &rse.qself) 
+            eq_maybe_qself(&lse.qself, &rse.qself)
                 && eq_path(&lse.path, &rse.path)
                 && eq_struct_rest(&lse.rest, &rse.rest)
                 && unordered_over(&lse.fields, &rse.fields, |l, r| eq_field(l, r))
diff --git a/clippy_utils/src/consts.rs b/clippy_utils/src/consts.rs
index 0d7fdeeb920..15c27d1a996 100644
--- a/clippy_utils/src/consts.rs
+++ b/clippy_utils/src/consts.rs
@@ -1,6 +1,6 @@
 #![allow(clippy::float_cmp)]
 
-use crate::{clip, sext, unsext};
+use crate::{clip, is_direct_expn_of, sext, unsext};
 use if_chain::if_chain;
 use rustc_ast::ast::{self, LitFloatType, LitKind};
 use rustc_data_structures::sync::Lrc;
@@ -230,7 +230,13 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
         match e.kind {
             ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
             ExprKind::Block(block, _) => self.block(block),
-            ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))),
+            ExprKind::Lit(ref lit) => {
+                if is_direct_expn_of(e.span, "cfg").is_some() {
+                    None
+                } else {
+                    Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
+                }
+            },
             ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),
             ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple),
             ExprKind::Repeat(value, _) => {
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 769836aaf18..66e75b0c206 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -72,7 +72,7 @@ use rustc_hir::LangItem::{ResultErr, ResultOk};
 use rustc_hir::{
     def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl,
     ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Node, Param, Pat, PatKind, Path,
-    PathSegment, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
+    PathSegment, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::exports::Export;
@@ -326,16 +326,6 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
         .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
 }
 
-/// Checks if an expression references a variable of the given name.
-pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
-    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
-        if let [p] = path.segments {
-            return p.ident.name == var;
-        }
-    }
-    false
-}
-
 pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     match *path {
         QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
@@ -707,16 +697,6 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     }
 }
 
-/// Gets the name of a `Pat`, if any.
-pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
-    match pat.kind {
-        PatKind::Binding(.., ref spname, _) => Some(spname.name),
-        PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
-        PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p),
-        _ => None,
-    }
-}
-
 pub struct ContainsName {
     pub name: Symbol,
     pub result: bool,
@@ -861,14 +841,16 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
     })
 }
 
-/// Gets the loop enclosing the given expression, if any.
-pub fn get_enclosing_loop(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+/// Gets the loop or closure enclosing the given expression, if any.
+pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     let map = tcx.hir();
     for (_, node) in map.parent_iter(expr.hir_id) {
         match node {
             Node::Expr(
-                e @ Expr {
-                    kind: ExprKind::Loop(..),
+                e
+                @
+                Expr {
+                    kind: ExprKind::Loop(..) | ExprKind::Closure(..),
                     ..
                 },
             ) => return Some(e),
@@ -1399,6 +1381,55 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
 }
 
+/// Checks if an expression represents the identity function
+/// Only examines closures and `std::convert::identity`
+pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    /// Checks if a function's body represents the identity function. Looks for bodies of the form:
+    /// * `|x| x`
+    /// * `|x| return x`
+    /// * `|x| { return x }`
+    /// * `|x| { return x; }`
+    fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
+        let id = if_chain! {
+            if let [param] = func.params;
+            if let PatKind::Binding(_, id, _, _) = param.pat.kind;
+            then {
+                id
+            } else {
+                return false;
+            }
+        };
+
+        let mut expr = &func.value;
+        loop {
+            match expr.kind {
+                #[rustfmt::skip]
+                ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
+                | ExprKind::Ret(Some(e)) => expr = e,
+                #[rustfmt::skip]
+                ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
+                    if_chain! {
+                        if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
+                        if let ExprKind::Ret(Some(ret_val)) = e.kind;
+                        then {
+                            expr = ret_val;
+                        } else {
+                            return false;
+                        }
+                    }
+                },
+                _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
+            }
+        }
+    }
+
+    match expr.kind {
+        ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
+        ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
+        _ => false,
+    }
+}
+
 /// Gets the node where an expression is either used, or it's type is unified with another branch.
 pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
     let map = tcx.hir();
@@ -1654,6 +1685,19 @@ pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
     (e, count)
 }
 
+/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
+/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
+pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
+    loop {
+        match expr.kind {
+            ExprKind::AddrOf(_, _, e) => expr = e,
+            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
+            _ => break,
+        }
+    }
+    expr
+}
+
 #[macro_export]
 macro_rules! unwrap_cargo_metadata {
     ($cx: ident, $lint: ident, $deps: expr) => {{
diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs
index 791688cd194..8adb6915952 100644
--- a/clippy_utils/src/ptr.rs
+++ b/clippy_utils/src/ptr.rs
@@ -1,10 +1,10 @@
 use crate::source::snippet;
-use crate::{get_pat_name, match_var};
+use crate::{path_to_local_id, strip_pat_refs};
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
+use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 use std::borrow::Cow;
 
 pub fn get_spans(
@@ -14,10 +14,11 @@ pub fn get_spans(
     replacements: &[(&'static str, &'static str)],
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
-        get_binding_name(&body.params[idx]).map_or_else(
-            || Some(vec![]),
-            |name| extract_clone_suggestions(cx, name, replacements, body),
-        )
+        if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind {
+            extract_clone_suggestions(cx, binding_id, replacements, body)
+        } else {
+            Some(vec![])
+        }
     } else {
         Some(vec![])
     }
@@ -25,13 +26,13 @@ pub fn get_spans(
 
 fn extract_clone_suggestions<'tcx>(
     cx: &LateContext<'tcx>,
-    name: Symbol,
+    id: HirId,
     replace: &[(&'static str, &'static str)],
     body: &'tcx Body<'_>,
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     let mut visitor = PtrCloneVisitor {
         cx,
-        name,
+        id,
         replace,
         spans: vec![],
         abort: false,
@@ -42,7 +43,7 @@ fn extract_clone_suggestions<'tcx>(
 
 struct PtrCloneVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    name: Symbol,
+    id: HirId,
     replace: &'a [(&'static str, &'static str)],
     spans: Vec<(Span, Cow<'static, str>)>,
     abort: bool,
@@ -55,16 +56,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
         if self.abort {
             return;
         }
-        if let ExprKind::MethodCall(seg, _, args, _) = expr.kind {
-            if args.len() == 1 && match_var(&args[0], self.name) {
+        if let ExprKind::MethodCall(seg, _, [recv], _) = expr.kind {
+            if path_to_local_id(recv, self.id) {
                 if seg.ident.name.as_str() == "capacity" {
                     self.abort = true;
                     return;
                 }
                 for &(fn_name, suffix) in self.replace {
                     if seg.ident.name.as_str() == fn_name {
-                        self.spans
-                            .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
+                        self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix));
                         return;
                     }
                 }
@@ -77,7 +77,3 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
         NestedVisitorMap::None
     }
 }
-
-fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
-    get_pat_name(arg.pat)
-}
diff --git a/doc/common_tools_writing_lints.md b/doc/common_tools_writing_lints.md
index abac1227b4f..0a85f650011 100644
--- a/doc/common_tools_writing_lints.md
+++ b/doc/common_tools_writing_lints.md
@@ -6,7 +6,7 @@ You may need following tooltips to catch up with common operations.
   - [Retrieving the type of an expression](#retrieving-the-type-of-an-expression)
   - [Checking if an expression is calling a specific method](#checking-if-an-expr-is-calling-a-specific-method)
   - [Checking if a type implements a specific trait](#checking-if-a-type-implements-a-specific-trait)
-  - [Checking if a type defines a method](#checking-if-a-type-defines-a-method)
+  - [Checking if a type defines a specific method](#checking-if-a-type-defines-a-specific-method)
   - [Dealing with macros](#dealing-with-macros)
 
 Useful Rustc dev guide links:
diff --git a/doc/release.md b/doc/release.md
index e0af9bf0625..afe3033c288 100644
--- a/doc/release.md
+++ b/doc/release.md
@@ -101,6 +101,21 @@ After this, the release should be available on the Clippy [release page].
 
 [release page]: https://github.com/rust-lang/rust-clippy/releases
 
+## Update the `stable` branch
+
+At this step you should have already checked out the commit of the `rust-1.XX.0`
+tag. Updating the stable branch from here is as easy as:
+
+```bash
+# Assuming the current directory corresponds to the Clippy repository and the
+# commit of the just created rust-1.XX.0 tag is checked out.
+$ git push upstream rust-1.XX.0:stable  # `upstream` is the `rust-lang/rust-clippy` remote
+```
+
+_NOTE: Usually there are no stable backports for Clippy, so this update should
+be possible without force pushing or anything like this. If there should have
+happened a stable backport, make sure to re-merge those changes just as with the
+`beta` branch._
 
 ## Update `CHANGELOG.md`
 
diff --git a/tests/ui-toml/toml_disallowed_method/clippy.toml b/tests/ui-toml/toml_disallowed_method/clippy.toml
index c0df3b6e8af..a3245da6825 100644
--- a/tests/ui-toml/toml_disallowed_method/clippy.toml
+++ b/tests/ui-toml/toml_disallowed_method/clippy.toml
@@ -1 +1,5 @@
-disallowed-methods = ["core::iter::traits::iterator::Iterator::sum", "regex::re_unicode::Regex::is_match", "regex::re_unicode::Regex::new"]
+disallowed-methods = [
+    "std::iter::Iterator::sum",
+    "regex::Regex::is_match",
+    "regex::Regex::new"
+]
diff --git a/tests/ui-toml/toml_disallowed_type/clippy.toml b/tests/ui-toml/toml_disallowed_type/clippy.toml
new file mode 100644
index 00000000000..2eff854c22c
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_type/clippy.toml
@@ -0,0 +1,9 @@
+disallowed-types = [
+    "std::collections::HashMap",
+    "std::sync::atomic::AtomicU32",
+    "syn::TypePath",
+    "proc_macro2::Ident",
+    "std::thread::Thread",
+    "std::time::Instant",
+    "std::io::Read",
+]
diff --git a/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs b/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs
new file mode 100644
index 00000000000..567afb5aec1
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.rs
@@ -0,0 +1,35 @@
+#![warn(clippy::disallowed_type)]
+
+extern crate quote;
+extern crate syn;
+
+use std::sync as foo;
+use std::sync::atomic::AtomicU32;
+use std::time::Instant as Sneaky;
+
+struct HashMap;
+
+fn bad_return_type() -> fn() -> Sneaky {
+    todo!()
+}
+
+fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {
+    todo!()
+}
+
+fn trait_obj(_: &dyn std::io::Read) {
+    todo!()
+}
+
+static BAD: foo::atomic::AtomicPtr<()> = foo::atomic::AtomicPtr::new(std::ptr::null_mut());
+
+#[allow(clippy::diverging_sub_expression)]
+fn main() {
+    let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
+    let _ = Sneaky::now();
+    let _ = foo::atomic::AtomicU32::new(0);
+    static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
+    let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default();
+    let _ = syn::Ident::new("", todo!());
+    let _ = HashMap;
+}
diff --git a/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr b/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr
new file mode 100644
index 00000000000..4e6fd91fba1
--- /dev/null
+++ b/tests/ui-toml/toml_disallowed_type/conf_disallowed_type.stderr
@@ -0,0 +1,88 @@
+error: `std::sync::atomic::AtomicU32` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:7:1
+   |
+LL | use std::sync::atomic::AtomicU32;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::disallowed-type` implied by `-D warnings`
+
+error: `std::time::Instant` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:8:1
+   |
+LL | use std::time::Instant as Sneaky;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `std::time::Instant` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:12:33
+   |
+LL | fn bad_return_type() -> fn() -> Sneaky {
+   |                                 ^^^^^^
+
+error: `std::time::Instant` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:16:28
+   |
+LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {
+   |                            ^^^^^^
+
+error: `std::sync::atomic::AtomicU32` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:16:39
+   |
+LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {
+   |                                       ^^^^^^^^^^^^^^^^^^^^^^
+
+error: `std::io::Read` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:20:22
+   |
+LL | fn trait_obj(_: &dyn std::io::Read) {
+   |                      ^^^^^^^^^^^^^
+
+error: `std::collections::HashMap` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:28:48
+   |
+LL |     let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
+   |                                                ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `std::collections::HashMap` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:28:12
+   |
+LL |     let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `std::time::Instant` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:29:13
+   |
+LL |     let _ = Sneaky::now();
+   |             ^^^^^^
+
+error: `std::sync::atomic::AtomicU32` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:30:13
+   |
+LL |     let _ = foo::atomic::AtomicU32::new(0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^
+
+error: `std::sync::atomic::AtomicU32` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:31:17
+   |
+LL |     static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `std::sync::atomic::AtomicU32` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:31:48
+   |
+LL |     static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
+   |                                                ^^^^^^^^^^^^^^^^^^^^^^
+
+error: `syn::TypePath` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:32:43
+   |
+LL |     let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default();
+   |                                           ^^^^^^^^^^^^^
+
+error: `proc_macro2::Ident` is not allowed according to config
+  --> $DIR/conf_disallowed_type.rs:33:13
+   |
+LL |     let _ = syn::Ident::new("", todo!());
+   |             ^^^^^^^^^^
+
+error: aborting due to 14 previous errors
+
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 a7be00426c4..06d70b66fda 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 `avoid-breaking-exported-api`, `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`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `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`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/tests/ui/append_instead_of_extend.fixed b/tests/ui/append_instead_of_extend.fixed
new file mode 100644
index 00000000000..283358333cd
--- /dev/null
+++ b/tests/ui/append_instead_of_extend.fixed
@@ -0,0 +1,55 @@
+// run-rustfix
+#![warn(clippy::append_instead_of_extend)]
+use std::collections::BinaryHeap;
+fn main() {
+    //gets linted
+    let mut vec1 = vec![0u8; 1024];
+    let mut vec2: std::vec::Vec<u8> = Vec::new();
+
+    vec2.append(&mut vec1);
+
+    let mut vec3 = vec![0u8; 1024];
+    let mut vec4: std::vec::Vec<u8> = Vec::new();
+
+    vec4.append(&mut vec3);
+
+    let mut vec11: std::vec::Vec<u8> = Vec::new();
+
+    vec11.append(&mut return_vector());
+
+    //won't get linted it dosen't move the entire content of a vec into another
+    let mut test1 = vec![0u8, 10];
+    let mut test2: std::vec::Vec<u8> = Vec::new();
+
+    test2.extend(test1.drain(4..10));
+
+    let mut vec3 = vec![0u8; 104];
+    let mut vec7: std::vec::Vec<u8> = Vec::new();
+
+    vec3.append(&mut vec7);
+
+    let mut vec5 = vec![0u8; 1024];
+    let mut vec6: std::vec::Vec<u8> = Vec::new();
+
+    vec5.extend(vec6.drain(..4));
+
+    let mut vec9: std::vec::Vec<u8> = Vec::new();
+
+    return_vector().append(&mut vec9);
+
+    //won't get linted because it is not a vec
+
+    let mut heap = BinaryHeap::from(vec![1, 3]);
+    let mut heap2 = BinaryHeap::from(vec![]);
+    heap2.extend(heap.drain())
+}
+
+fn return_vector() -> Vec<u8> {
+    let mut new_vector = vec![];
+
+    for i in 1..10 {
+        new_vector.push(i)
+    }
+
+    new_vector
+}
diff --git a/tests/ui/append_instead_of_extend.rs b/tests/ui/append_instead_of_extend.rs
new file mode 100644
index 00000000000..abde5cdac5c
--- /dev/null
+++ b/tests/ui/append_instead_of_extend.rs
@@ -0,0 +1,55 @@
+// run-rustfix
+#![warn(clippy::append_instead_of_extend)]
+use std::collections::BinaryHeap;
+fn main() {
+    //gets linted
+    let mut vec1 = vec![0u8; 1024];
+    let mut vec2: std::vec::Vec<u8> = Vec::new();
+
+    vec2.extend(vec1.drain(..));
+
+    let mut vec3 = vec![0u8; 1024];
+    let mut vec4: std::vec::Vec<u8> = Vec::new();
+
+    vec4.extend(vec3.drain(..));
+
+    let mut vec11: std::vec::Vec<u8> = Vec::new();
+
+    vec11.extend(return_vector().drain(..));
+
+    //won't get linted it dosen't move the entire content of a vec into another
+    let mut test1 = vec![0u8, 10];
+    let mut test2: std::vec::Vec<u8> = Vec::new();
+
+    test2.extend(test1.drain(4..10));
+
+    let mut vec3 = vec![0u8; 104];
+    let mut vec7: std::vec::Vec<u8> = Vec::new();
+
+    vec3.append(&mut vec7);
+
+    let mut vec5 = vec![0u8; 1024];
+    let mut vec6: std::vec::Vec<u8> = Vec::new();
+
+    vec5.extend(vec6.drain(..4));
+
+    let mut vec9: std::vec::Vec<u8> = Vec::new();
+
+    return_vector().append(&mut vec9);
+
+    //won't get linted because it is not a vec
+
+    let mut heap = BinaryHeap::from(vec![1, 3]);
+    let mut heap2 = BinaryHeap::from(vec![]);
+    heap2.extend(heap.drain())
+}
+
+fn return_vector() -> Vec<u8> {
+    let mut new_vector = vec![];
+
+    for i in 1..10 {
+        new_vector.push(i)
+    }
+
+    new_vector
+}
diff --git a/tests/ui/append_instead_of_extend.stderr b/tests/ui/append_instead_of_extend.stderr
new file mode 100644
index 00000000000..9d309d981de
--- /dev/null
+++ b/tests/ui/append_instead_of_extend.stderr
@@ -0,0 +1,22 @@
+error: use of `extend` instead of `append` for adding the full range of a second vector
+  --> $DIR/append_instead_of_extend.rs:9:5
+   |
+LL |     vec2.extend(vec1.drain(..));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec2.append(&mut vec1)`
+   |
+   = note: `-D clippy::append-instead-of-extend` implied by `-D warnings`
+
+error: use of `extend` instead of `append` for adding the full range of a second vector
+  --> $DIR/append_instead_of_extend.rs:14:5
+   |
+LL |     vec4.extend(vec3.drain(..));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec4.append(&mut vec3)`
+
+error: use of `extend` instead of `append` for adding the full range of a second vector
+  --> $DIR/append_instead_of_extend.rs:18:5
+   |
+LL |     vec11.extend(return_vector().drain(..));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec11.append(&mut return_vector())`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/assertions_on_constants.rs b/tests/ui/assertions_on_constants.rs
index e989de65404..6617ca183a8 100644
--- a/tests/ui/assertions_on_constants.rs
+++ b/tests/ui/assertions_on_constants.rs
@@ -28,4 +28,7 @@ fn main() {
     debug_assert!(false); // #3948
     assert_const!(3);
     assert_const!(-1);
+
+    // Don't lint on this:
+    assert!(cfg!(feature = "hey") || cfg!(not(feature = "asdf")));
 }
diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs
index d4470d3f407..170955e726c 100644
--- a/tests/ui/auxiliary/macro_rules.rs
+++ b/tests/ui/auxiliary/macro_rules.rs
@@ -106,3 +106,10 @@ macro_rules! field_reassign_with_default {
         }
     };
 }
+
+#[macro_export]
+macro_rules! default_numeric_fallback {
+    () => {
+        let x = 22;
+    };
+}
diff --git a/tests/ui/default_numeric_fallback.rs b/tests/ui/default_numeric_fallback.rs
index 43468872db0..c0625fd1b75 100644
--- a/tests/ui/default_numeric_fallback.rs
+++ b/tests/ui/default_numeric_fallback.rs
@@ -1,3 +1,5 @@
+// aux-build:macro_rules.rs
+
 #![warn(clippy::default_numeric_fallback)]
 #![allow(unused)]
 #![allow(clippy::never_loop)]
@@ -5,6 +7,9 @@
 #![allow(clippy::unnecessary_operation)]
 #![allow(clippy::branches_sharing_code)]
 
+#[macro_use]
+extern crate macro_rules;
+
 mod basic_expr {
     fn test() {
         // Should lint unsuffixed literals typed `i32`.
@@ -133,4 +138,22 @@ mod method_calls {
     }
 }
 
+mod in_macro {
+    macro_rules! internal_macro {
+        () => {
+            let x = 22;
+        };
+    }
+
+    // Should lint in internal macro.
+    fn internal() {
+        internal_macro!();
+    }
+
+    // Should NOT lint in external macro.
+    fn external() {
+        default_numeric_fallback!();
+    }
+}
+
 fn main() {}
diff --git a/tests/ui/default_numeric_fallback.stderr b/tests/ui/default_numeric_fallback.stderr
index d1c4c8203dd..5862cd936ac 100644
--- a/tests/ui/default_numeric_fallback.stderr
+++ b/tests/ui/default_numeric_fallback.stderr
@@ -1,5 +1,5 @@
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:11:17
+  --> $DIR/default_numeric_fallback.rs:16:17
    |
 LL |         let x = 22;
    |                 ^^ help: consider adding suffix: `22_i32`
@@ -7,142 +7,153 @@ LL |         let x = 22;
    = note: `-D clippy::default-numeric-fallback` implied by `-D warnings`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:12:18
+  --> $DIR/default_numeric_fallback.rs:17:18
    |
 LL |         let x = [1, 2, 3];
    |                  ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:12:21
+  --> $DIR/default_numeric_fallback.rs:17:21
    |
 LL |         let x = [1, 2, 3];
    |                     ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:12:24
+  --> $DIR/default_numeric_fallback.rs:17:24
    |
 LL |         let x = [1, 2, 3];
    |                        ^ help: consider adding suffix: `3_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:13:28
+  --> $DIR/default_numeric_fallback.rs:18:28
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                            ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:13:31
+  --> $DIR/default_numeric_fallback.rs:18:31
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                               ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:13:44
+  --> $DIR/default_numeric_fallback.rs:18:44
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                                            ^ help: consider adding suffix: `3_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:13:47
+  --> $DIR/default_numeric_fallback.rs:18:47
    |
 LL |         let x = if true { (1, 2) } else { (3, 4) };
    |                                               ^ help: consider adding suffix: `4_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:14:23
+  --> $DIR/default_numeric_fallback.rs:19:23
    |
 LL |         let x = match 1 {
    |                       ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:15:13
+  --> $DIR/default_numeric_fallback.rs:20:13
    |
 LL |             1 => 1,
    |             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:15:18
+  --> $DIR/default_numeric_fallback.rs:20:18
    |
 LL |             1 => 1,
    |                  ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:16:18
+  --> $DIR/default_numeric_fallback.rs:21:18
    |
 LL |             _ => 2,
    |                  ^ help: consider adding suffix: `2_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:20:17
+  --> $DIR/default_numeric_fallback.rs:25:17
    |
 LL |         let x = 0.12;
    |                 ^^^^ help: consider adding suffix: `0.12_f64`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:38:21
+  --> $DIR/default_numeric_fallback.rs:43:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:46:21
+  --> $DIR/default_numeric_fallback.rs:51:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:52:21
+  --> $DIR/default_numeric_fallback.rs:57:21
    |
 LL |             let y = 1;
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:64:9
+  --> $DIR/default_numeric_fallback.rs:69:9
    |
 LL |         1
    |         ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:70:27
+  --> $DIR/default_numeric_fallback.rs:75:27
    |
 LL |         let f = || -> _ { 1 };
    |                           ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:74:29
+  --> $DIR/default_numeric_fallback.rs:79:29
    |
 LL |         let f = || -> i32 { 1 };
    |                             ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:88:21
+  --> $DIR/default_numeric_fallback.rs:93:21
    |
 LL |         generic_arg(1);
    |                     ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:91:32
+  --> $DIR/default_numeric_fallback.rs:96:32
    |
 LL |         let x: _ = generic_arg(1);
    |                                ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:109:28
+  --> $DIR/default_numeric_fallback.rs:114:28
    |
 LL |         GenericStruct { x: 1 };
    |                            ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:112:36
+  --> $DIR/default_numeric_fallback.rs:117:36
    |
 LL |         let _ = GenericStruct { x: 1 };
    |                                    ^ help: consider adding suffix: `1_i32`
 
 error: default numeric fallback might occur
-  --> $DIR/default_numeric_fallback.rs:132:23
+  --> $DIR/default_numeric_fallback.rs:137:23
    |
 LL |         s.generic_arg(1);
    |                       ^ help: consider adding suffix: `1_i32`
 
-error: aborting due to 24 previous errors
+error: default numeric fallback might occur
+  --> $DIR/default_numeric_fallback.rs:144:21
+   |
+LL |             let x = 22;
+   |                     ^^ help: consider adding suffix: `22_i32`
+...
+LL |         internal_macro!();
+   |         ------------------ in this macro invocation
+   |
+   = note: this error originates in the macro `internal_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 25 previous errors
 
diff --git a/tests/ui/doc.rs b/tests/ui/doc.rs
index c946a047f1b..8afef6b23d4 100644
--- a/tests/ui/doc.rs
+++ b/tests/ui/doc.rs
@@ -64,7 +64,7 @@ fn test_units() {
 /// WebGL
 /// TensorFlow
 /// TrueType
-/// iOS macOS
+/// iOS macOS FreeBSD
 /// TeX LaTeX BibTeX BibLaTeX
 /// MinGW
 /// CamelCase (see also #2395)
diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs
index 1368c5d7984..787053fb000 100644
--- a/tests/ui/field_reassign_with_default.rs
+++ b/tests/ui/field_reassign_with_default.rs
@@ -29,6 +29,21 @@ struct C {
     i: Vec<i32>,
     j: i64,
 }
+
+#[derive(Default)]
+struct D {
+    a: Option<i32>,
+    b: Option<i32>,
+}
+
+macro_rules! m {
+    ($key:ident: $value:tt) => {{
+        let mut data = $crate::D::default();
+        data.$key = Some($value);
+        data
+    }};
+}
+
 /// Implements .next() that returns a different number each time.
 struct SideEffect(i32);
 
@@ -143,6 +158,11 @@ fn main() {
 
     let mut a: WrapperMulti<i32, i64> = Default::default();
     a.i = 42;
+
+    // Don't lint in macros
+    m! {
+        a: 42
+    };
 }
 
 mod m {
diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr
index dd7c0360bb1..b56db08ec8a 100644
--- a/tests/ui/field_reassign_with_default.stderr
+++ b/tests/ui/field_reassign_with_default.stderr
@@ -1,108 +1,108 @@
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:48:5
+  --> $DIR/field_reassign_with_default.rs:63:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
    = note: `-D clippy::field-reassign-with-default` implied by `-D warnings`
 note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:47:5
+  --> $DIR/field_reassign_with_default.rs:62:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:88:5
+  --> $DIR/field_reassign_with_default.rs:103:5
    |
 LL |     a.j = 43;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:87:5
+  --> $DIR/field_reassign_with_default.rs:102:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:93:5
+  --> $DIR/field_reassign_with_default.rs:108:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:92:5
+  --> $DIR/field_reassign_with_default.rs:107:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:99:5
+  --> $DIR/field_reassign_with_default.rs:114:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:98:5
+  --> $DIR/field_reassign_with_default.rs:113:5
    |
 LL |     let mut a = A::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:109:5
+  --> $DIR/field_reassign_with_default.rs:124:5
    |
 LL |     a.i = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:108:5
+  --> $DIR/field_reassign_with_default.rs:123:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:113:5
+  --> $DIR/field_reassign_with_default.rs:128:5
    |
 LL |     a.i = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:112:5
+  --> $DIR/field_reassign_with_default.rs:127:5
    |
 LL |     let mut a: A = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:135:5
+  --> $DIR/field_reassign_with_default.rs:150:5
    |
 LL |     a.i = vec![1];
    |     ^^^^^^^^^^^^^^
    |
 note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:134:5
+  --> $DIR/field_reassign_with_default.rs:149:5
    |
 LL |     let mut a: C = C::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:142:5
+  --> $DIR/field_reassign_with_default.rs:157:5
    |
 LL |     a.i = true;
    |     ^^^^^^^^^^^
    |
 note: consider initializing the variable with `Wrapper::<bool> { i: true }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:141:5
+  --> $DIR/field_reassign_with_default.rs:156:5
    |
 LL |     let mut a: Wrapper<bool> = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: field assignment outside of initializer for an instance created with Default::default()
-  --> $DIR/field_reassign_with_default.rs:145:5
+  --> $DIR/field_reassign_with_default.rs:160:5
    |
 LL |     a.i = 42;
    |     ^^^^^^^^^
    |
 note: consider initializing the variable with `WrapperMulti::<i32, i64> { i: 42, ..Default::default() }` and removing relevant reassignments
-  --> $DIR/field_reassign_with_default.rs:144:5
+  --> $DIR/field_reassign_with_default.rs:159:5
    |
 LL |     let mut a: WrapperMulti<i32, i64> = Default::default();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/filter_map_identity.fixed b/tests/ui/filter_map_identity.fixed
index 23ce28d8e9b..a5860aa49b3 100644
--- a/tests/ui/filter_map_identity.fixed
+++ b/tests/ui/filter_map_identity.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_imports)]
+#![allow(unused_imports, clippy::needless_return)]
 #![warn(clippy::filter_map_identity)]
 
 fn main() {
@@ -13,4 +13,7 @@ fn main() {
     use std::convert::identity;
     let iterator = vec![Some(1), None, Some(2)].into_iter();
     let _ = iterator.flatten();
+
+    let iterator = vec![Some(1), None, Some(2)].into_iter();
+    let _ = iterator.flatten();
 }
diff --git a/tests/ui/filter_map_identity.rs b/tests/ui/filter_map_identity.rs
index e698df13eea..7e998b9cdf7 100644
--- a/tests/ui/filter_map_identity.rs
+++ b/tests/ui/filter_map_identity.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_imports)]
+#![allow(unused_imports, clippy::needless_return)]
 #![warn(clippy::filter_map_identity)]
 
 fn main() {
@@ -13,4 +13,7 @@ fn main() {
     use std::convert::identity;
     let iterator = vec![Some(1), None, Some(2)].into_iter();
     let _ = iterator.filter_map(identity);
+
+    let iterator = vec![Some(1), None, Some(2)].into_iter();
+    let _ = iterator.filter_map(|x| return x);
 }
diff --git a/tests/ui/filter_map_identity.stderr b/tests/ui/filter_map_identity.stderr
index 596a6320608..43c9fdca4fb 100644
--- a/tests/ui/filter_map_identity.stderr
+++ b/tests/ui/filter_map_identity.stderr
@@ -1,4 +1,4 @@
-error: called `filter_map(|x| x)` on an `Iterator`
+error: use of `filter_map` with an identity function
   --> $DIR/filter_map_identity.rs:8:22
    |
 LL |     let _ = iterator.filter_map(|x| x);
@@ -6,17 +6,23 @@ LL |     let _ = iterator.filter_map(|x| x);
    |
    = note: `-D clippy::filter-map-identity` implied by `-D warnings`
 
-error: called `filter_map(std::convert::identity)` on an `Iterator`
+error: use of `filter_map` with an identity function
   --> $DIR/filter_map_identity.rs:11:22
    |
 LL |     let _ = iterator.filter_map(std::convert::identity);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
 
-error: called `filter_map(std::convert::identity)` on an `Iterator`
+error: use of `filter_map` with an identity function
   --> $DIR/filter_map_identity.rs:15:22
    |
 LL |     let _ = iterator.filter_map(identity);
    |                      ^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
 
-error: aborting due to 3 previous errors
+error: use of `filter_map` with an identity function
+  --> $DIR/filter_map_identity.rs:18:22
+   |
+LL |     let _ = iterator.filter_map(|x| return x);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/flat_map_identity.fixed b/tests/ui/flat_map_identity.fixed
index dfe3bd47e13..1f4b880ef5b 100644
--- a/tests/ui/flat_map_identity.fixed
+++ b/tests/ui/flat_map_identity.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_imports)]
+#![allow(unused_imports, clippy::needless_return)]
 #![warn(clippy::flat_map_identity)]
 
 use std::convert;
@@ -11,4 +11,7 @@ fn main() {
 
     let iterator = [[0, 1], [2, 3], [4, 5]].iter();
     let _ = iterator.flatten();
+
+    let iterator = [[0, 1], [2, 3], [4, 5]].iter();
+    let _ = iterator.flatten();
 }
diff --git a/tests/ui/flat_map_identity.rs b/tests/ui/flat_map_identity.rs
index 393b9569255..de14a06d4e6 100644
--- a/tests/ui/flat_map_identity.rs
+++ b/tests/ui/flat_map_identity.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_imports)]
+#![allow(unused_imports, clippy::needless_return)]
 #![warn(clippy::flat_map_identity)]
 
 use std::convert;
@@ -11,4 +11,7 @@ fn main() {
 
     let iterator = [[0, 1], [2, 3], [4, 5]].iter();
     let _ = iterator.flat_map(convert::identity);
+
+    let iterator = [[0, 1], [2, 3], [4, 5]].iter();
+    let _ = iterator.flat_map(|x| return x);
 }
diff --git a/tests/ui/flat_map_identity.stderr b/tests/ui/flat_map_identity.stderr
index e4686ae5a54..e776c9fdf51 100644
--- a/tests/ui/flat_map_identity.stderr
+++ b/tests/ui/flat_map_identity.stderr
@@ -1,4 +1,4 @@
-error: called `flat_map(|x| x)` on an `Iterator`
+error: use of `flat_map` with an identity function
   --> $DIR/flat_map_identity.rs:10:22
    |
 LL |     let _ = iterator.flat_map(|x| x);
@@ -6,11 +6,17 @@ LL |     let _ = iterator.flat_map(|x| x);
    |
    = note: `-D clippy::flat-map-identity` implied by `-D warnings`
 
-error: called `flat_map(std::convert::identity)` on an `Iterator`
+error: use of `flat_map` with an identity function
   --> $DIR/flat_map_identity.rs:13:22
    |
 LL |     let _ = iterator.flat_map(convert::identity);
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
 
-error: aborting due to 2 previous errors
+error: use of `flat_map` with an identity function
+  --> $DIR/flat_map_identity.rs:16:22
+   |
+LL |     let _ = iterator.flat_map(|x| return x);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()`
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/semicolon_if_nothing_returned.rs b/tests/ui/semicolon_if_nothing_returned.rs
index 0abe2cca267..79ba7402f1f 100644
--- a/tests/ui/semicolon_if_nothing_returned.rs
+++ b/tests/ui/semicolon_if_nothing_returned.rs
@@ -17,6 +17,24 @@ fn basic101(x: i32) {
     y = x + 1
 }
 
+#[rustfmt::skip]
+fn closure_error() {
+    let _d = || {
+        hello()
+    };
+}
+
+#[rustfmt::skip]
+fn unsafe_checks_error() {
+    use std::mem::MaybeUninit;
+    use std::ptr;
+
+    let mut s = MaybeUninit::<String>::uninit();
+    let _d = || unsafe { 
+        ptr::drop_in_place(s.as_mut_ptr()) 
+    };
+}
+
 // this is fine
 fn print_sum(a: i32, b: i32) {
     println!("{}", a + b);
@@ -53,3 +71,29 @@ fn loop_test(x: i32) {
         println!("{}", ext);
     }
 }
+
+fn closure() {
+    let _d = || hello();
+}
+
+#[rustfmt::skip]
+fn closure_block() {
+    let _d = || { hello() };
+}
+
+unsafe fn some_unsafe_op() {}
+unsafe fn some_other_unsafe_fn() {}
+
+fn do_something() {
+    unsafe { some_unsafe_op() };
+
+    unsafe { some_other_unsafe_fn() };
+}
+
+fn unsafe_checks() {
+    use std::mem::MaybeUninit;
+    use std::ptr;
+
+    let mut s = MaybeUninit::<String>::uninit();
+    let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) };
+}
diff --git a/tests/ui/semicolon_if_nothing_returned.stderr b/tests/ui/semicolon_if_nothing_returned.stderr
index b73f8967538..e88ebe2ad35 100644
--- a/tests/ui/semicolon_if_nothing_returned.stderr
+++ b/tests/ui/semicolon_if_nothing_returned.stderr
@@ -18,5 +18,17 @@ error: consider adding a `;` to the last statement for consistent formatting
 LL |     y = x + 1
    |     ^^^^^^^^^ help: add a `;` here: `y = x + 1;`
 
-error: aborting due to 3 previous errors
+error: consider adding a `;` to the last statement for consistent formatting
+  --> $DIR/semicolon_if_nothing_returned.rs:23:9
+   |
+LL |         hello()
+   |         ^^^^^^^ help: add a `;` here: `hello();`
+
+error: consider adding a `;` to the last statement for consistent formatting
+  --> $DIR/semicolon_if_nothing_returned.rs:34:9
+   |
+LL |         ptr::drop_in_place(s.as_mut_ptr()) 
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());`
+
+error: aborting due to 5 previous errors
 
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/use_self.fixed b/tests/ui/use_self.fixed
index 631da6fe066..e2c28542efc 100644
--- a/tests/ui/use_self.fixed
+++ b/tests/ui/use_self.fixed
@@ -492,3 +492,26 @@ mod issue7206 {
         }
     }
 }
+
+mod self_is_ty_param {
+    trait Trait {
+        type Type;
+        type Hi;
+
+        fn test();
+    }
+
+    impl<I> Trait for I
+    where
+        I: Iterator,
+        I::Item: Trait, // changing this to Self would require <Self as Iterator>
+    {
+        type Type = I;
+        type Hi = I::Item;
+
+        fn test() {
+            let _: I::Item;
+            let _: I; // this could lint, but is questionable
+        }
+    }
+}
diff --git a/tests/ui/use_self.rs b/tests/ui/use_self.rs
index 7a10d755faa..3cd99b9f5cd 100644
--- a/tests/ui/use_self.rs
+++ b/tests/ui/use_self.rs
@@ -279,7 +279,7 @@ mod generics {
     impl<T> Foo<T> {
         // `Self` is applicable here
         fn foo(value: T) -> Foo<T> {
-            Foo { value }
+            Foo::<T> { value }
         }
 
         // `Cannot` use `Self` as a return type as the generic types are different
@@ -492,3 +492,26 @@ mod issue7206 {
         }
     }
 }
+
+mod self_is_ty_param {
+    trait Trait {
+        type Type;
+        type Hi;
+
+        fn test();
+    }
+
+    impl<I> Trait for I
+    where
+        I: Iterator,
+        I::Item: Trait, // changing this to Self would require <Self as Iterator>
+    {
+        type Type = I;
+        type Hi = I::Item;
+
+        fn test() {
+            let _: I::Item;
+            let _: I; // this could lint, but is questionable
+        }
+    }
+}
diff --git a/tests/ui/use_self.stderr b/tests/ui/use_self.stderr
index cf6222c9b45..6ac26c9e5a9 100644
--- a/tests/ui/use_self.stderr
+++ b/tests/ui/use_self.stderr
@@ -153,8 +153,8 @@ LL |         fn foo(value: T) -> Foo<T> {
 error: unnecessary structure name repetition
   --> $DIR/use_self.rs:282:13
    |
-LL |             Foo { value }
-   |             ^^^ help: use the applicable keyword: `Self`
+LL |             Foo::<T> { value }
+   |             ^^^^^^^^ help: use the applicable keyword: `Self`
 
 error: unnecessary structure name repetition
   --> $DIR/use_self.rs:454:13
diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed
index c3e2cf0c4a4..52e80ceee83 100644
--- a/tests/ui/while_let_on_iterator.fixed
+++ b/tests/ui/while_let_on_iterator.fixed
@@ -320,6 +320,20 @@ fn issue1924() {
     println!("iterator field {}", it.1);
 }
 
+fn issue7249() {
+    let mut it = 0..10;
+    let mut x = || {
+        // Needs &mut, the closure can be called multiple times
+        for x in &mut it {
+            if x % 2 == 0 {
+                break;
+            }
+        }
+    };
+    x();
+    x();
+}
+
 fn main() {
     let mut it = 0..20;
     for _ in it {
diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs
index 1717006a449..5078a3c9028 100644
--- a/tests/ui/while_let_on_iterator.rs
+++ b/tests/ui/while_let_on_iterator.rs
@@ -320,6 +320,20 @@ fn issue1924() {
     println!("iterator field {}", it.1);
 }
 
+fn issue7249() {
+    let mut it = 0..10;
+    let mut x = || {
+        // Needs &mut, the closure can be called multiple times
+        while let Some(x) = it.next() {
+            if x % 2 == 0 {
+                break;
+            }
+        }
+    };
+    x();
+    x();
+}
+
 fn main() {
     let mut it = 0..20;
     while let Some(..) = it.next() {
diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr
index eff559bef7e..cb0afeae15e 100644
--- a/tests/ui/while_let_on_iterator.stderr
+++ b/tests/ui/while_let_on_iterator.stderr
@@ -105,10 +105,16 @@ LL |     while let Some(n) = it.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in &mut it`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:325:5
+  --> $DIR/while_let_on_iterator.rs:327:9
+   |
+LL |         while let Some(x) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in &mut it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:339:5
    |
 LL |     while let Some(..) = it.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
 
-error: aborting due to 18 previous errors
+error: aborting due to 19 previous errors