From 41fe5c1ca73589fe9f63f2191fd0c869e5de34d0 Mon Sep 17 00:00:00 2001
From: Dylan MacKenzie <ecstaticmorse@gmail.com>
Date: Sun, 3 May 2020 11:41:03 -0700
Subject: [PATCH 1/9] Update clippy lint

---
 clippy_lints/src/redundant_clone.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index d5cace0c6474..d563eb886ae7 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -591,7 +591,7 @@ struct PossibleBorrowerMap<'a, 'tcx> {
 impl PossibleBorrowerMap<'_, '_> {
     /// Returns true if the set of borrowers of `borrowed` living at `at` matches with `borrowers`.
     fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at: mir::Location) -> bool {
-        self.maybe_live.seek_after(at);
+        self.maybe_live.seek_after_primary_effect(at);
 
         self.bitset.0.clear();
         let maybe_live = &mut self.maybe_live;

From 0e2f5c9862bff6889c57a802844e75ea9e576606 Mon Sep 17 00:00:00 2001
From: Jack Huey <jack.huey@umassmed.edu>
Date: Thu, 7 May 2020 17:46:31 -0400
Subject: [PATCH 2/9] Fix nit and cargo.lock

---
 util/dev | 7 +++++++
 1 file changed, 7 insertions(+)
 create mode 100755 util/dev

diff --git a/util/dev b/util/dev
new file mode 100755
index 000000000000..319de217e0d9
--- /dev/null
+++ b/util/dev
@@ -0,0 +1,7 @@
+#!/bin/sh
+CARGO_TARGET_DIR=$(pwd)/target/
+export CARGO_TARGET_DIR
+
+echo 'Deprecated! `util/dev` usage is deprecated, please use `cargo dev` instead.'
+
+cd clippy_dev && cargo run -- "$@"

From 31c84e50772e1ebdd5ace0f4211d050e193e1e90 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Fri, 8 May 2020 13:57:01 +0200
Subject: [PATCH 3/9] Fix clippy.

---
 clippy_lints/src/bytecount.rs                |  7 ++++---
 clippy_lints/src/inline_fn_without_body.rs   |  5 +++--
 clippy_lints/src/len_zero.rs                 |  6 +++---
 clippy_lints/src/lib.rs                      |  2 +-
 clippy_lints/src/map_clone.rs                |  4 ++--
 clippy_lints/src/non_expressive_names.rs     |  4 ++--
 clippy_lints/src/unsafe_removed_from_name.rs |  4 ++--
 clippy_lints/src/utils/hir_utils.rs          |  4 ++--
 clippy_lints/src/utils/internal_lints.rs     | 10 +++++-----
 clippy_lints/src/utils/mod.rs                |  2 +-
 clippy_lints/src/utils/ptr.rs                |  9 ++++-----
 clippy_lints/src/utils/usage.rs              |  5 ++---
 12 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/clippy_lints/src/bytecount.rs b/clippy_lints/src/bytecount.rs
index 91d3e47d7870..278d043732f4 100644
--- a/clippy_lints/src/bytecount.rs
+++ b/clippy_lints/src/bytecount.rs
@@ -3,12 +3,13 @@ use crate::utils::{
     span_lint_and_sugg, walk_ptrs_ty,
 };
 use if_chain::if_chain;
-use rustc_ast::ast::{Name, UintTy};
+use rustc_ast::ast::{UintTy};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for naive byte counts
@@ -95,11 +96,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ByteCount {
     }
 }
 
-fn check_arg(name: Name, arg: Name, needle: &Expr<'_>) -> bool {
+fn check_arg(name: Symbol, arg: Symbol, needle: &Expr<'_>) -> bool {
     name == arg && !contains_name(name, needle)
 }
 
-fn get_path_name(expr: &Expr<'_>) -> Option<Name> {
+fn get_path_name(expr: &Expr<'_>) -> Option<Symbol> {
     match expr.kind {
         ExprKind::Box(ref e) | ExprKind::AddrOf(BorrowKind::Ref, _, ref e) | ExprKind::Unary(UnOp::UnDeref, ref e) => {
             get_path_name(e)
diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs
index 1ebfb3c8162a..475610dda475 100644
--- a/clippy_lints/src/inline_fn_without_body.rs
+++ b/clippy_lints/src/inline_fn_without_body.rs
@@ -2,11 +2,12 @@
 
 use crate::utils::span_lint_and_then;
 use crate::utils::sugg::DiagnosticBuilderExt;
-use rustc_ast::ast::{Attribute, Name};
+use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
 use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for `#[inline]` on trait methods without bodies
@@ -38,7 +39,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InlineFnWithoutBody {
     }
 }
 
-fn check_attrs(cx: &LateContext<'_, '_>, name: Name, attrs: &[Attribute]) {
+fn check_attrs(cx: &LateContext<'_, '_>, name: Symbol, attrs: &[Attribute]) {
     for attr in attrs {
         if !attr.check_name(sym!(inline)) {
             continue;
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 1d86ca9696f2..2ec0b5a8d6fb 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -1,5 +1,5 @@
 use crate::utils::{get_item_name, snippet_with_applicability, span_lint, span_lint_and_sugg, walk_ptrs_ty};
-use rustc_ast::ast::{LitKind, Name};
+use rustc_ast::ast::LitKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
@@ -7,7 +7,7 @@ use rustc_hir::{AssocItemKind, BinOpKind, Expr, ExprKind, ImplItemRef, Item, Ite
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::{Span, Spanned};
+use rustc_span::source_map::{Span, Spanned, Symbol};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for getting the length of something via `.len()`
@@ -226,7 +226,7 @@ fn check_cmp(cx: &LateContext<'_, '_>, span: Span, method: &Expr<'_>, lit: &Expr
 fn check_len(
     cx: &LateContext<'_, '_>,
     span: Span,
-    method_name: Name,
+    method_name: Symbol,
     args: &[Expr<'_>],
     lit: &LitKind,
     op: &str,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index c995be5edc25..1f135cba6e4e 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -333,7 +333,7 @@ mod zero_div_zero;
 pub use crate::utils::conf::Conf;
 
 mod reexport {
-    pub use rustc_ast::ast::Name;
+    pub use rustc_span::Symbol as Name;
 }
 
 /// Register all pre expansion lints
diff --git a/clippy_lints/src/map_clone.rs b/clippy_lints/src/map_clone.rs
index 0b346393ac38..0163b3f8dbc8 100644
--- a/clippy_lints/src/map_clone.rs
+++ b/clippy_lints/src/map_clone.rs
@@ -3,14 +3,14 @@ use crate::utils::{
     is_copy, is_type_diagnostic_item, match_trait_method, remove_blocks, snippet_with_applicability, span_lint_and_sugg,
 };
 use if_chain::if_chain;
-use rustc_ast::ast::Ident;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
+use rustc_span::symbol::Ident;
 
 declare_clippy_lint! {
     /// **What it does:** Checks for usage of `iterator.map(|x| x.clone())` and suggests
diff --git a/clippy_lints/src/non_expressive_names.rs b/clippy_lints/src/non_expressive_names.rs
index 45809b359866..2b51b7320758 100644
--- a/clippy_lints/src/non_expressive_names.rs
+++ b/clippy_lints/src/non_expressive_names.rs
@@ -1,13 +1,13 @@
 use crate::utils::{span_lint, span_lint_and_then};
 use rustc_ast::ast::{
-    Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Ident, Item, ItemKind, Local, MacCall, Pat, PatKind,
+    Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, MacCall, Pat, PatKind,
 };
 use rustc_ast::attr;
 use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::SymbolStr;
+use rustc_span::symbol::{Ident, SymbolStr};
 use std::cmp::Ordering;
 
 declare_clippy_lint! {
diff --git a/clippy_lints/src/unsafe_removed_from_name.rs b/clippy_lints/src/unsafe_removed_from_name.rs
index 86c469a4dccf..735800e7e741 100644
--- a/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/clippy_lints/src/unsafe_removed_from_name.rs
@@ -1,9 +1,9 @@
 use crate::utils::span_lint;
-use rustc_ast::ast::{Ident, Item, ItemKind, UseTree, UseTreeKind};
+use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind};
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::SymbolStr;
+use rustc_span::symbol::{Ident, SymbolStr};
 
 declare_clippy_lint! {
     /// **What it does:** Checks for imports that remove "unsafe" from an item's
diff --git a/clippy_lints/src/utils/hir_utils.rs b/clippy_lints/src/utils/hir_utils.rs
index 02b721fd378f..bd7da57c665d 100644
--- a/clippy_lints/src/utils/hir_utils.rs
+++ b/clippy_lints/src/utils/hir_utils.rs
@@ -1,6 +1,5 @@
 use crate::consts::{constant_context, constant_simple};
 use crate::utils::differing_macro_contexts;
-use rustc_ast::ast::Name;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir::{
     BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprKind, Field, FnRetTy, GenericArg,
@@ -10,6 +9,7 @@ use rustc_hir::{
 use rustc_lint::LateContext;
 use rustc_middle::ich::StableHashingContextProvider;
 use rustc_middle::ty::TypeckTables;
+use rustc_span::Symbol;
 use std::hash::Hash;
 
 /// Type used to check whether two ast are the same. This is different from the
@@ -544,7 +544,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
         }
     }
 
-    pub fn hash_name(&mut self, n: Name) {
+    pub fn hash_name(&mut self, n: Symbol) {
         n.as_str().hash(&mut self.s);
     }
 
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 5bf9acdc5f7c..8e1b047f6f80 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -4,7 +4,7 @@ use crate::utils::{
     span_lint_and_help, span_lint_and_sugg, walk_ptrs_ty,
 };
 use if_chain::if_chain;
-use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, Name, NodeId};
+use rustc_ast::ast::{Crate as AstCrate, ItemKind, LitKind, NodeId};
 use rustc_ast::visit::FnKind;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
@@ -17,7 +17,7 @@ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{Span, Spanned};
-use rustc_span::symbol::SymbolStr;
+use rustc_span::symbol::{Symbol, SymbolStr};
 
 use std::borrow::{Borrow, Cow};
 
@@ -245,8 +245,8 @@ impl EarlyLintPass for ClippyLintsInternal {
 
 #[derive(Clone, Debug, Default)]
 pub struct LintWithoutLintPass {
-    declared_lints: FxHashMap<Name, Span>,
-    registered_lints: FxHashSet<Name>,
+    declared_lints: FxHashMap<Symbol, Span>,
+    registered_lints: FxHashSet<Symbol>,
 }
 
 impl_lint_pass!(LintWithoutLintPass => [DEFAULT_LINT, LINT_WITHOUT_LINT_PASS]);
@@ -357,7 +357,7 @@ fn is_lint_ref_type<'tcx>(cx: &LateContext<'_, 'tcx>, ty: &Ty<'_>) -> bool {
 }
 
 struct LintCollector<'a, 'tcx> {
-    output: &'a mut FxHashSet<Name>,
+    output: &'a mut FxHashSet<Symbol>,
     cx: &'a LateContext<'a, 'tcx>,
 }
 
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index 04b4b4237619..2fd080e9ef0f 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -1069,7 +1069,7 @@ pub fn is_allowed(cx: &LateContext<'_, '_>, lint: &'static Lint, id: HirId) -> b
     cx.tcx.lint_level_at_node(lint, id).0 == Level::Allow
 }
 
-pub fn get_arg_name(pat: &Pat<'_>) -> Option<ast::Name> {
+pub fn get_arg_name(pat: &Pat<'_>) -> Option<Name> {
     match pat.kind {
         PatKind::Binding(.., ident, None) => Some(ident.name),
         PatKind::Ref(ref subpat, _) => get_arg_name(subpat),
diff --git a/clippy_lints/src/utils/ptr.rs b/clippy_lints/src/utils/ptr.rs
index 240bf2449cb5..fb6bd5e81585 100644
--- a/clippy_lints/src/utils/ptr.rs
+++ b/clippy_lints/src/utils/ptr.rs
@@ -1,10 +1,9 @@
 use crate::utils::{get_pat_name, match_var, snippet};
-use rustc_ast::ast::Name;
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-use rustc_span::source_map::Span;
+use rustc_span::{Span, Symbol};
 use std::borrow::Cow;
 
 pub fn get_spans(
@@ -25,7 +24,7 @@ pub fn get_spans(
 
 fn extract_clone_suggestions<'a, 'tcx>(
     cx: &LateContext<'a, 'tcx>,
-    name: Name,
+    name: Symbol,
     replace: &[(&'static str, &'static str)],
     body: &'tcx Body<'_>,
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
@@ -46,7 +45,7 @@ fn extract_clone_suggestions<'a, 'tcx>(
 
 struct PtrCloneVisitor<'a, 'tcx> {
     cx: &'a LateContext<'a, 'tcx>,
-    name: Name,
+    name: Symbol,
     replace: &'a [(&'static str, &'static str)],
     spans: Vec<(Span, Cow<'static, str>)>,
     abort: bool,
@@ -83,6 +82,6 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
     }
 }
 
-fn get_binding_name(arg: &Param<'_>) -> Option<Name> {
+fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
     get_pat_name(&arg.pat)
 }
diff --git a/clippy_lints/src/utils/usage.rs b/clippy_lints/src/utils/usage.rs
index c14da6aacea0..e85356779877 100644
--- a/clippy_lints/src/utils/usage.rs
+++ b/clippy_lints/src/utils/usage.rs
@@ -1,5 +1,4 @@
 use crate::utils::match_var;
-use rustc_ast::ast;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
@@ -8,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
-use rustc_span::symbol::Ident;
+use rustc_span::symbol::{Ident, Symbol};
 use rustc_typeck::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor, Place, PlaceBase};
 
 /// Returns a set of mutated local variable IDs, or `None` if mutations could not be determined.
@@ -78,7 +77,7 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate {
 }
 
 pub struct UsedVisitor {
-    pub var: ast::Name, // var to look for
+    pub var: Symbol,    // var to look for
     pub used: bool,     // has the var been used otherwise?
 }
 

From 30822733f080fdee42409a6e05c6b8c7adfbbe7f Mon Sep 17 00:00:00 2001
From: Ralf Jung <post@ralfj.de>
Date: Sun, 10 May 2020 23:36:41 +0200
Subject: [PATCH 4/9] rustc_driver: factor out computing the exit code

---
 src/driver.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/driver.rs b/src/driver.rs
index 2c699998ea90..1ce0300f2390 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -296,7 +296,7 @@ pub fn main() {
     rustc_driver::init_rustc_env_logger();
     lazy_static::initialize(&ICE_HOOK);
     exit(
-        rustc_driver::catch_fatal_errors(move || {
+        rustc_driver::catch_with_exit_code(move || {
             let mut orig_args: Vec<String> = env::args().collect();
 
             if orig_args.iter().any(|a| a == "--version" || a == "-V") {
@@ -411,7 +411,5 @@ pub fn main() {
                 if clippy_enabled { &mut clippy } else { &mut default };
             rustc_driver::run_compiler(&args, callbacks, None, None)
         })
-        .and_then(|result| result)
-        .is_err() as i32,
     )
 }

From d13d8987b070e04c05a6e138c5a0feee596bc4aa Mon Sep 17 00:00:00 2001
From: flip1995 <hello@philkrones.com>
Date: Mon, 11 May 2020 20:23:47 +0200
Subject: [PATCH 5/9] Merge commit '43a1777b89cf6791f9e20878b4e5e3ae907867a5'
 into clippyup

---
 CHANGELOG.md                                  |   2 +
 Cargo.toml                                    |   1 -
 clippy_lints/src/lib.rs                       |  16 +-
 clippy_lints/src/loops.rs                     | 361 +++++++++---------
 clippy_lints/src/manual_async_fn.rs           | 159 ++++++++
 clippy_lints/src/manual_non_exhaustive.rs     | 173 +++++++++
 clippy_lints/src/match_on_vec_items.rs        |  23 +-
 clippy_lints/src/misc_early.rs                |  21 +-
 clippy_lints/src/unwrap.rs                    |  21 +-
 clippy_lints/src/utils/conf.rs                |   2 +
 clippy_lints/src/utils/mod.rs                 |  34 +-
 clippy_lints/src/utils/paths.rs               |   3 +-
 clippy_lints/src/wildcard_imports.rs          |  74 +++-
 src/lintlist/mod.rs                           |  16 +-
 .../toml_unknown_key/conf_unknown_key.stderr  |   2 +-
 tests/ui/builtin-type-shadow.stderr           |   2 -
 .../ui/checked_unwrap/simple_conditionals.rs  |  27 ++
 .../checked_unwrap/simple_conditionals.stderr |  24 +-
 tests/ui/future_not_send.rs                   |   1 +
 tests/ui/future_not_send.stderr               |   6 +-
 tests/ui/manual_async_fn.fixed                |  67 ++++
 tests/ui/manual_async_fn.rs                   |  79 ++++
 tests/ui/manual_async_fn.stderr               |  98 +++++
 tests/ui/manual_memcpy.rs                     |  15 +
 tests/ui/manual_memcpy.stderr                 |  20 +-
 tests/ui/manual_non_exhaustive.rs             | 137 +++++++
 tests/ui/manual_non_exhaustive.stderr         | 103 +++++
 tests/ui/match_on_vec_items.rs                |  22 ++
 tests/ui/while_let_on_iterator.fixed          |  58 +++
 tests/ui/while_let_on_iterator.rs             |  58 +++
 tests/ui/while_let_on_iterator.stderr         |  28 +-
 tests/ui/wildcard_imports.fixed               |  73 ++++
 tests/ui/wildcard_imports.rs                  |  73 ++++
 tests/ui/wildcard_imports.stderr              |  32 +-
 34 files changed, 1574 insertions(+), 257 deletions(-)
 create mode 100644 clippy_lints/src/manual_async_fn.rs
 create mode 100644 clippy_lints/src/manual_non_exhaustive.rs
 create mode 100644 tests/ui/manual_async_fn.fixed
 create mode 100644 tests/ui/manual_async_fn.rs
 create mode 100644 tests/ui/manual_async_fn.stderr
 create mode 100644 tests/ui/manual_non_exhaustive.rs
 create mode 100644 tests/ui/manual_non_exhaustive.stderr

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 575773580c0b..8457d6ad05cf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1422,7 +1422,9 @@ Released 2018-09-13
 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
 [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
+[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
+[`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
 [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic
 [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap
 [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names
diff --git a/Cargo.toml b/Cargo.toml
index 63ce2cd8cad7..6999b6bd7404 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -31,7 +31,6 @@ path = "src/driver.rs"
 # begin automatic update
 clippy_lints = { version = "0.0.212", path = "clippy_lints" }
 # end automatic update
-regex = "1"
 semver = "0.9"
 rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util"}
 tempfile = { version = "3.1.0", optional = true }
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 1f135cba6e4e..51b5401da7d0 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -247,6 +247,8 @@ mod literal_representation;
 mod loops;
 mod macro_use;
 mod main_recursion;
+mod manual_async_fn;
+mod manual_non_exhaustive;
 mod map_clone;
 mod map_unit_fn;
 mod match_on_vec_items;
@@ -628,6 +630,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         &loops::WHILE_LET_ON_ITERATOR,
         &macro_use::MACRO_USE_IMPORTS,
         &main_recursion::MAIN_RECURSION,
+        &manual_async_fn::MANUAL_ASYNC_FN,
+        &manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
         &map_clone::MAP_CLONE,
         &map_unit_fn::OPTION_MAP_UNIT_FN,
         &map_unit_fn::RESULT_MAP_UNIT_FN,
@@ -1054,7 +1058,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let max_struct_bools = conf.max_struct_bools;
     store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools));
     store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap);
-    store.register_late_pass(|| box wildcard_imports::WildcardImports);
+    let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports;
+    store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports));
     store.register_early_pass(|| box macro_use::MacroUseImports);
     store.register_late_pass(|| box verbose_file_reads::VerboseFileReads);
     store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default());
@@ -1064,6 +1069,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls);
     store.register_late_pass(|| box if_let_mutex::IfLetMutex);
     store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems);
+    store.register_early_pass(|| box manual_non_exhaustive::ManualNonExhaustive);
+    store.register_late_pass(|| box manual_async_fn::ManualAsyncFn);
 
     store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
         LintId::of(&arithmetic::FLOAT_ARITHMETIC),
@@ -1138,6 +1145,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::EXPLICIT_INTO_ITER_LOOP),
         LintId::of(&loops::EXPLICIT_ITER_LOOP),
         LintId::of(&macro_use::MACRO_USE_IMPORTS),
+        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
         LintId::of(&matches::MATCH_BOOL),
         LintId::of(&matches::SINGLE_MATCH_ELSE),
         LintId::of(&methods::FILTER_MAP),
@@ -1280,10 +1288,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::WHILE_LET_LOOP),
         LintId::of(&loops::WHILE_LET_ON_ITERATOR),
         LintId::of(&main_recursion::MAIN_RECURSION),
+        LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
+        LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
         LintId::of(&map_clone::MAP_CLONE),
         LintId::of(&map_unit_fn::OPTION_MAP_UNIT_FN),
         LintId::of(&map_unit_fn::RESULT_MAP_UNIT_FN),
-        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
         LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
         LintId::of(&matches::MATCH_AS_REF),
         LintId::of(&matches::MATCH_OVERLAPPING_ARM),
@@ -1474,6 +1483,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::NEEDLESS_RANGE_LOOP),
         LintId::of(&loops::WHILE_LET_ON_ITERATOR),
         LintId::of(&main_recursion::MAIN_RECURSION),
+        LintId::of(&manual_async_fn::MANUAL_ASYNC_FN),
+        LintId::of(&manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
         LintId::of(&map_clone::MAP_CLONE),
         LintId::of(&matches::INFALLIBLE_DESTRUCTURING_MATCH),
         LintId::of(&matches::MATCH_OVERLAPPING_ARM),
@@ -1647,7 +1658,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         LintId::of(&loops::NEVER_LOOP),
         LintId::of(&loops::REVERSE_RANGE_LOOP),
         LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
-        LintId::of(&match_on_vec_items::MATCH_ON_VEC_ITEMS),
         LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
         LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
         LintId::of(&methods::CLONE_DOUBLE_REF),
diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs
index f7c7fd82d833..2bbf4dba614b 100644
--- a/clippy_lints/src/loops.rs
+++ b/clippy_lints/src/loops.rs
@@ -10,7 +10,6 @@ use crate::utils::{
 };
 use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg};
 use if_chain::if_chain;
-use itertools::Itertools;
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
@@ -772,40 +771,48 @@ fn check_for_loop<'a, 'tcx>(
 
 fn same_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, var: HirId) -> bool {
     if_chain! {
-        if let ExprKind::Path(ref qpath) = expr.kind;
-        if let QPath::Resolved(None, ref path) = *qpath;
+        if let ExprKind::Path(qpath) = &expr.kind;
+        if let QPath::Resolved(None, path) = qpath;
         if path.segments.len() == 1;
         if let Res::Local(local_id) = qpath_res(cx, qpath, expr.hir_id);
-        // our variable!
-        if local_id == var;
         then {
-            return true;
+            // our variable!
+            local_id == var
+        } else {
+            false
         }
     }
+}
 
-    false
+#[derive(Clone, Copy)]
+enum OffsetSign {
+    Positive,
+    Negative,
 }
 
 struct Offset {
     value: String,
-    negate: bool,
+    sign: OffsetSign,
 }
 
 impl Offset {
-    fn negative(s: String) -> Self {
-        Self { value: s, negate: true }
+    fn negative(value: String) -> Self {
+        Self {
+            value,
+            sign: OffsetSign::Negative,
+        }
     }
 
-    fn positive(s: String) -> Self {
+    fn positive(value: String) -> Self {
         Self {
-            value: s,
-            negate: false,
+            value,
+            sign: OffsetSign::Positive,
         }
     }
 }
 
-struct FixedOffsetVar {
-    var_name: String,
+struct FixedOffsetVar<'hir> {
+    var: &'hir Expr<'hir>,
     offset: Offset,
 }
 
@@ -819,10 +826,20 @@ fn is_slice_like<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, ty: Ty<'_>) -> bool {
     is_slice || is_type_diagnostic_item(cx, ty, sym!(vec_type)) || is_type_diagnostic_item(cx, ty, sym!(vecdeque_type))
 }
 
-fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, var: HirId) -> Option<FixedOffsetVar> {
+fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
+    if_chain! {
+        if let ExprKind::MethodCall(method, _, args) = expr.kind;
+        if method.ident.name == sym!(clone);
+        if args.len() == 1;
+        if let Some(arg) = args.get(0);
+        then { arg } else { expr }
+    }
+}
+
+fn get_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, idx: &Expr<'_>, var: HirId) -> Option<Offset> {
     fn extract_offset<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, e: &Expr<'_>, var: HirId) -> Option<String> {
-        match e.kind {
-            ExprKind::Lit(ref l) => match l.node {
+        match &e.kind {
+            ExprKind::Lit(l) => match l.node {
                 ast::LitKind::Int(x, _ty) => Some(x.to_string()),
                 _ => None,
             },
@@ -831,115 +848,139 @@ fn get_fixed_offset_var<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &Expr<'_>, v
         }
     }
 
-    if let ExprKind::Index(ref seqexpr, ref idx) = expr.kind {
-        let ty = cx.tables.expr_ty(seqexpr);
-        if !is_slice_like(cx, ty) {
-            return None;
-        }
-
-        let offset = match idx.kind {
-            ExprKind::Binary(op, ref lhs, ref rhs) => match op.node {
-                BinOpKind::Add => {
-                    let offset_opt = if same_var(cx, lhs, var) {
-                        extract_offset(cx, rhs, var)
-                    } else if same_var(cx, rhs, var) {
-                        extract_offset(cx, lhs, var)
-                    } else {
-                        None
-                    };
-
-                    offset_opt.map(Offset::positive)
-                },
-                BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
-                _ => None,
-            },
-            ExprKind::Path(..) => {
-                if same_var(cx, idx, var) {
-                    Some(Offset::positive("0".into()))
+    match idx.kind {
+        ExprKind::Binary(op, lhs, rhs) => match op.node {
+            BinOpKind::Add => {
+                let offset_opt = if same_var(cx, lhs, var) {
+                    extract_offset(cx, rhs, var)
+                } else if same_var(cx, rhs, var) {
+                    extract_offset(cx, lhs, var)
                 } else {
                     None
-                }
+                };
+
+                offset_opt.map(Offset::positive)
             },
+            BinOpKind::Sub if same_var(cx, lhs, var) => extract_offset(cx, rhs, var).map(Offset::negative),
             _ => None,
-        };
-
-        offset.map(|o| FixedOffsetVar {
-            var_name: snippet_opt(cx, seqexpr.span).unwrap_or_else(|| "???".into()),
-            offset: o,
-        })
-    } else {
-        None
-    }
-}
-
-fn fetch_cloned_fixed_offset_var<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    expr: &Expr<'_>,
-    var: HirId,
-) -> Option<FixedOffsetVar> {
-    if_chain! {
-        if let ExprKind::MethodCall(ref method, _, ref args) = expr.kind;
-        if method.ident.name == sym!(clone);
-        if args.len() == 1;
-        if let Some(arg) = args.get(0);
-        then {
-            return get_fixed_offset_var(cx, arg, var);
-        }
+        },
+        ExprKind::Path(..) if same_var(cx, idx, var) => Some(Offset::positive("0".into())),
+        _ => None,
     }
-
-    get_fixed_offset_var(cx, expr, var)
 }
 
-fn get_indexed_assignments<'a, 'tcx>(
-    cx: &LateContext<'a, 'tcx>,
-    body: &Expr<'_>,
-    var: HirId,
-) -> Vec<(FixedOffsetVar, FixedOffsetVar)> {
-    fn get_assignment<'a, 'tcx>(
-        cx: &LateContext<'a, 'tcx>,
-        e: &Expr<'_>,
-        var: HirId,
-    ) -> Option<(FixedOffsetVar, FixedOffsetVar)> {
-        if let ExprKind::Assign(ref lhs, ref rhs, _) = e.kind {
-            match (
-                get_fixed_offset_var(cx, lhs, var),
-                fetch_cloned_fixed_offset_var(cx, rhs, var),
-            ) {
-                (Some(offset_left), Some(offset_right)) => {
-                    // Source and destination must be different
-                    if offset_left.var_name == offset_right.var_name {
-                        None
-                    } else {
-                        Some((offset_left, offset_right))
-                    }
-                },
-                _ => None,
-            }
+fn get_assignments<'tcx>(body: &'tcx Expr<'tcx>) -> impl Iterator<Item = Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)>> {
+    fn get_assignment<'tcx>(e: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
+        if let ExprKind::Assign(lhs, rhs, _) = e.kind {
+            Some((lhs, rhs))
         } else {
             None
         }
     }
 
-    if let ExprKind::Block(ref b, _) = body.kind {
-        let Block {
-            ref stmts, ref expr, ..
-        } = **b;
+    // This is one of few ways to return different iterators
+    // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434
+    let mut iter_a = None;
+    let mut iter_b = None;
+
+    if let ExprKind::Block(b, _) = body.kind {
+        let Block { stmts, expr, .. } = *b;
 
-        stmts
+        iter_a = stmts
             .iter()
-            .map(|stmt| match stmt.kind {
+            .filter_map(|stmt| match stmt.kind {
                 StmtKind::Local(..) | StmtKind::Item(..) => None,
-                StmtKind::Expr(ref e) | StmtKind::Semi(ref e) => Some(get_assignment(cx, e, var)),
+                StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e),
             })
-            .chain(expr.as_ref().into_iter().map(|e| Some(get_assignment(cx, &*e, var))))
-            .filter_map(|op| op)
-            .collect::<Option<Vec<_>>>()
-            .unwrap_or_default()
+            .chain(expr.into_iter())
+            .map(get_assignment)
+            .into()
     } else {
-        get_assignment(cx, body, var).into_iter().collect()
+        iter_b = Some(get_assignment(body))
     }
+
+    iter_a.into_iter().flatten().chain(iter_b.into_iter())
 }
 
+fn build_manual_memcpy_suggestion<'a, 'tcx>(
+    cx: &LateContext<'a, 'tcx>,
+    start: &Expr<'_>,
+    end: &Expr<'_>,
+    limits: ast::RangeLimits,
+    dst_var: FixedOffsetVar<'_>,
+    src_var: FixedOffsetVar<'_>,
+) -> String {
+    fn print_sum(arg1: &str, arg2: &Offset) -> String {
+        match (arg1, &arg2.value[..], arg2.sign) {
+            ("0", "0", _) => "0".into(),
+            ("0", x, OffsetSign::Positive) | (x, "0", _) => x.into(),
+            ("0", x, OffsetSign::Negative) => format!("-{}", x),
+            (x, y, OffsetSign::Positive) => format!("({} + {})", x, y),
+            (x, y, OffsetSign::Negative) => {
+                if x == y {
+                    "0".into()
+                } else {
+                    format!("({} - {})", x, y)
+                }
+            },
+        }
+    }
+
+    fn print_offset(start_str: &str, inline_offset: &Offset) -> String {
+        let offset = print_sum(start_str, inline_offset);
+        if offset.as_str() == "0" {
+            "".into()
+        } else {
+            offset
+        }
+    }
+
+    let print_limit = |end: &Expr<'_>, offset: Offset, var: &Expr<'_>| {
+        if_chain! {
+            if let ExprKind::MethodCall(method, _, len_args) = end.kind;
+            if method.ident.name == sym!(len);
+            if len_args.len() == 1;
+            if let Some(arg) = len_args.get(0);
+            if var_def_id(cx, arg) == var_def_id(cx, var);
+            then {
+                match offset.sign {
+                    OffsetSign::Negative => format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value),
+                    OffsetSign::Positive => "".into(),
+                }
+            } else {
+                let end_str = match limits {
+                    ast::RangeLimits::Closed => {
+                        let end = sugg::Sugg::hir(cx, end, "<count>");
+                        format!("{}", end + sugg::ONE)
+                    },
+                    ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
+                };
+
+                print_sum(&end_str, &offset)
+            }
+        }
+    };
+
+    let start_str = snippet(cx, start.span, "").to_string();
+    let dst_offset = print_offset(&start_str, &dst_var.offset);
+    let dst_limit = print_limit(end, dst_var.offset, dst_var.var);
+    let src_offset = print_offset(&start_str, &src_var.offset);
+    let src_limit = print_limit(end, src_var.offset, src_var.var);
+
+    let dst_var_name = snippet_opt(cx, dst_var.var.span).unwrap_or_else(|| "???".into());
+    let src_var_name = snippet_opt(cx, src_var.var.span).unwrap_or_else(|| "???".into());
+
+    let dst = if dst_offset == "" && dst_limit == "" {
+        dst_var_name
+    } else {
+        format!("{}[{}..{}]", dst_var_name, dst_offset, dst_limit)
+    };
+
+    format!(
+        "{}.clone_from_slice(&{}[{}..{}])",
+        dst, src_var_name, src_offset, src_limit
+    )
+}
 /// Checks for for loops that sequentially copy items from one slice-like
 /// object to another.
 fn detect_manual_memcpy<'a, 'tcx>(
@@ -951,93 +992,43 @@ fn detect_manual_memcpy<'a, 'tcx>(
 ) {
     if let Some(higher::Range {
         start: Some(start),
-        ref end,
+        end: Some(end),
         limits,
     }) = higher::range(cx, arg)
     {
         // the var must be a single name
         if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
-            let print_sum = |arg1: &Offset, arg2: &Offset| -> String {
-                match (&arg1.value[..], arg1.negate, &arg2.value[..], arg2.negate) {
-                    ("0", _, "0", _) => "".into(),
-                    ("0", _, x, false) | (x, false, "0", false) => x.into(),
-                    ("0", _, x, true) | (x, false, "0", true) => format!("-{}", x),
-                    (x, false, y, false) => format!("({} + {})", x, y),
-                    (x, false, y, true) => {
-                        if x == y {
-                            "0".into()
-                        } else {
-                            format!("({} - {})", x, y)
-                        }
-                    },
-                    (x, true, y, false) => {
-                        if x == y {
-                            "0".into()
-                        } else {
-                            format!("({} - {})", y, x)
-                        }
-                    },
-                    (x, true, y, true) => format!("-({} + {})", x, y),
-                }
-            };
-
-            let print_limit = |end: &Option<&Expr<'_>>, offset: Offset, var_name: &str| {
-                if let Some(end) = *end {
-                    if_chain! {
-                        if let ExprKind::MethodCall(ref method, _, ref len_args) = end.kind;
-                        if method.ident.name == sym!(len);
-                        if len_args.len() == 1;
-                        if let Some(arg) = len_args.get(0);
-                        if snippet(cx, arg.span, "??") == var_name;
-                        then {
-                            return if offset.negate {
-                                format!("({} - {})", snippet(cx, end.span, "<src>.len()"), offset.value)
-                            } else {
-                                String::new()
-                            };
-                        }
-                    }
-
-                    let end_str = match limits {
-                        ast::RangeLimits::Closed => {
-                            let end = sugg::Sugg::hir(cx, end, "<count>");
-                            format!("{}", end + sugg::ONE)
-                        },
-                        ast::RangeLimits::HalfOpen => format!("{}", snippet(cx, end.span, "..")),
-                    };
-
-                    print_sum(&Offset::positive(end_str), &offset)
-                } else {
-                    "..".into()
-                }
-            };
-
             // The only statements in the for loops can be indexed assignments from
             // indexed retrievals.
-            let manual_copies = get_indexed_assignments(cx, body, canonical_id);
-
-            let big_sugg = manual_copies
-                .into_iter()
-                .map(|(dst_var, src_var)| {
-                    let start_str = Offset::positive(snippet(cx, start.span, "").to_string());
-                    let dst_offset = print_sum(&start_str, &dst_var.offset);
-                    let dst_limit = print_limit(end, dst_var.offset, &dst_var.var_name);
-                    let src_offset = print_sum(&start_str, &src_var.offset);
-                    let src_limit = print_limit(end, src_var.offset, &src_var.var_name);
-                    let dst = if dst_offset == "" && dst_limit == "" {
-                        dst_var.var_name
-                    } else {
-                        format!("{}[{}..{}]", dst_var.var_name, dst_offset, dst_limit)
-                    };
-
-                    format!(
-                        "{}.clone_from_slice(&{}[{}..{}])",
-                        dst, src_var.var_name, src_offset, src_limit
-                    )
+            let big_sugg = get_assignments(body)
+                .map(|o| {
+                    o.and_then(|(lhs, rhs)| {
+                        let rhs = fetch_cloned_expr(rhs);
+                        if_chain! {
+                            if let ExprKind::Index(seqexpr_left, idx_left) = lhs.kind;
+                            if let ExprKind::Index(seqexpr_right, idx_right) = rhs.kind;
+                            if is_slice_like(cx, cx.tables.expr_ty(seqexpr_left))
+                                && is_slice_like(cx, cx.tables.expr_ty(seqexpr_right));
+                            if let Some(offset_left) = get_offset(cx, &idx_left, canonical_id);
+                            if let Some(offset_right) = get_offset(cx, &idx_right, canonical_id);
+
+                            // Source and destination must be different
+                            if var_def_id(cx, seqexpr_left) != var_def_id(cx, seqexpr_right);
+                            then {
+                                Some((FixedOffsetVar { var: seqexpr_left, offset: offset_left },
+                                    FixedOffsetVar { var: seqexpr_right, offset: offset_right }))
+                            } else {
+                                None
+                            }
+                        }
+                    })
                 })
-                .join("\n    ");
+                .map(|o| o.map(|(dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, dst, src)))
+                .collect::<Option<Vec<_>>>()
+                .filter(|v| !v.is_empty())
+                .map(|v| v.join("\n    "));
 
-            if !big_sugg.is_empty() {
+            if let Some(big_sugg) = big_sugg {
                 span_lint_and_sugg(
                     cx,
                     MANUAL_MEMCPY,
diff --git a/clippy_lints/src/manual_async_fn.rs b/clippy_lints/src/manual_async_fn.rs
new file mode 100644
index 000000000000..cb72a2405823
--- /dev/null
+++ b/clippy_lints/src/manual_async_fn.rs
@@ -0,0 +1,159 @@
+use crate::utils::paths::FUTURE_FROM_GENERATOR;
+use crate::utils::{match_function_call, snippet_block, snippet_opt, span_lint_and_then};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{
+    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericBound, HirId, IsAsync,
+    ItemKind, TraitRef, Ty, TyKind, TypeBindingKind,
+};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** It checks for manual implementations of `async` functions.
+    ///
+    /// **Why is this bad?** It's more idiomatic to use the dedicated syntax.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// use std::future::Future;
+    ///
+    /// fn foo() -> impl Future<Output = i32> { async { 42 } }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::future::Future;
+    ///
+    /// async fn foo() -> i32 { 42 }
+    /// ```
+    pub MANUAL_ASYNC_FN,
+    style,
+    "manual implementations of `async` functions can be simplified using the dedicated syntax"
+}
+
+declare_lint_pass!(ManualAsyncFn => [MANUAL_ASYNC_FN]);
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ManualAsyncFn {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'a, 'tcx>,
+        kind: FnKind<'tcx>,
+        decl: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
+        span: Span,
+        _: HirId,
+    ) {
+        if_chain! {
+            if let Some(header) = kind.header();
+            if let IsAsync::NotAsync = header.asyncness;
+            // Check that this function returns `impl Future`
+            if let FnRetTy::Return(ret_ty) = decl.output;
+            if let Some(trait_ref) = future_trait_ref(cx, ret_ty);
+            if let Some(output) = future_output_ty(trait_ref);
+            // Check that the body of the function consists of one async block
+            if let ExprKind::Block(block, _) = body.value.kind;
+            if block.stmts.is_empty();
+            if let Some(closure_body) = desugared_async_block(cx, block);
+            then {
+                let header_span = span.with_hi(ret_ty.span.hi());
+
+                span_lint_and_then(
+                    cx,
+                    MANUAL_ASYNC_FN,
+                    header_span,
+                    "this function can be simplified using the `async fn` syntax",
+                    |diag| {
+                        if_chain! {
+                            if let Some(header_snip) = snippet_opt(cx, header_span);
+                            if let Some(ret_pos) = header_snip.rfind("->");
+                            if let Some((ret_sugg, ret_snip)) = suggested_ret(cx, output);
+                            then {
+                                let help = format!("make the function `async` and {}", ret_sugg);
+                                diag.span_suggestion(
+                                    header_span,
+                                    &help,
+                                    format!("async {}{}", &header_snip[..ret_pos], ret_snip),
+                                    Applicability::MachineApplicable
+                                );
+
+                                let body_snip = snippet_block(cx, closure_body.value.span, "..", Some(block.span));
+                                diag.span_suggestion(
+                                    block.span,
+                                    "move the body of the async block to the enclosing function",
+                                    body_snip.to_string(),
+                                    Applicability::MachineApplicable
+                                );
+                            }
+                        }
+                    },
+                );
+            }
+        }
+    }
+}
+
+fn future_trait_ref<'tcx>(cx: &LateContext<'_, 'tcx>, ty: &'tcx Ty<'tcx>) -> Option<&'tcx TraitRef<'tcx>> {
+    if_chain! {
+        if let TyKind::Def(item_id, _) = ty.kind;
+        let item = cx.tcx.hir().item(item_id.id);
+        if let ItemKind::OpaqueTy(opaque) = &item.kind;
+        if opaque.bounds.len() == 1;
+        if let GenericBound::Trait(poly, _) = &opaque.bounds[0];
+        if poly.trait_ref.trait_def_id() == cx.tcx.lang_items().future_trait();
+        then {
+            return Some(&poly.trait_ref);
+        }
+    }
+
+    None
+}
+
+fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'tcx>> {
+    if_chain! {
+        if let Some(segment) = trait_ref.path.segments.last();
+        if let Some(args) = segment.args;
+        if args.bindings.len() == 1;
+        let binding = &args.bindings[0];
+        if binding.ident.as_str() == "Output";
+        if let TypeBindingKind::Equality{ty: output} = binding.kind;
+        then {
+            return Some(output)
+        }
+    }
+
+    None
+}
+
+fn desugared_async_block<'tcx>(cx: &LateContext<'_, 'tcx>, block: &'tcx Block<'tcx>) -> Option<&'tcx Body<'tcx>> {
+    if_chain! {
+        if let Some(block_expr) = block.expr;
+        if let Some(args) = match_function_call(cx, block_expr, &FUTURE_FROM_GENERATOR);
+        if args.len() == 1;
+        if let Expr{kind: ExprKind::Closure(_, _, body_id, ..), ..} = args[0];
+        let closure_body = cx.tcx.hir().body(body_id);
+        if let Some(GeneratorKind::Async(AsyncGeneratorKind::Block)) = closure_body.generator_kind;
+        then {
+            return Some(closure_body);
+        }
+    }
+
+    None
+}
+
+fn suggested_ret(cx: &LateContext<'_, '_>, output: &Ty<'_>) -> Option<(&'static str, String)> {
+    match output.kind {
+        TyKind::Tup(tys) if tys.is_empty() => {
+            let sugg = "remove the return type";
+            Some((sugg, "".into()))
+        },
+        _ => {
+            let sugg = "return the output of the future directly";
+            snippet_opt(cx, output.span).map(|snip| (sugg, format!("-> {}", snip)))
+        },
+    }
+}
diff --git a/clippy_lints/src/manual_non_exhaustive.rs b/clippy_lints/src/manual_non_exhaustive.rs
new file mode 100644
index 000000000000..f3b8902e26f6
--- /dev/null
+++ b/clippy_lints/src/manual_non_exhaustive.rs
@@ -0,0 +1,173 @@
+use crate::utils::{snippet_opt, span_lint_and_then};
+use if_chain::if_chain;
+use rustc_ast::ast::{Attribute, Item, ItemKind, StructField, Variant, VariantData, VisibilityKind};
+use rustc_attr as attr;
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// **What it does:** Checks for manual implementations of the non-exhaustive pattern.
+    ///
+    /// **Why is this bad?** Using the #[non_exhaustive] attribute expresses better the intent
+    /// and allows possible optimizations when applied to enums.
+    ///
+    /// **Known problems:** None.
+    ///
+    /// **Example:**
+    ///
+    /// ```rust
+    /// struct S {
+    ///     pub a: i32,
+    ///     pub b: i32,
+    ///     _c: (),
+    /// }
+    ///
+    /// enum E {
+    ///     A,
+    ///     B,
+    ///     #[doc(hidden)]
+    ///     _C,
+    /// }
+    ///
+    /// struct T(pub i32, pub i32, ());
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// #[non_exhaustive]
+    /// struct S {
+    ///     pub a: i32,
+    ///     pub b: i32,
+    /// }
+    ///
+    /// #[non_exhaustive]
+    /// enum E {
+    ///     A,
+    ///     B,
+    /// }
+    ///
+    /// #[non_exhaustive]
+    /// struct T(pub i32, pub i32);
+    /// ```
+    pub MANUAL_NON_EXHAUSTIVE,
+    style,
+    "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]"
+}
+
+declare_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]);
+
+impl EarlyLintPass for ManualNonExhaustive {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        match &item.kind {
+            ItemKind::Enum(def, _) => {
+                check_manual_non_exhaustive_enum(cx, item, &def.variants);
+            },
+            ItemKind::Struct(variant_data, _) => {
+                if let VariantData::Unit(..) = variant_data {
+                    return;
+                }
+
+                check_manual_non_exhaustive_struct(cx, item, variant_data);
+            },
+            _ => {},
+        }
+    }
+}
+
+fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants: &[Variant]) {
+    fn is_non_exhaustive_marker(variant: &Variant) -> bool {
+        matches!(variant.data, VariantData::Unit(_))
+            && variant.ident.as_str().starts_with('_')
+            && variant.attrs.iter().any(|a| is_doc_hidden(a))
+    }
+
+    fn is_doc_hidden(attr: &Attribute) -> bool {
+        attr.check_name(sym!(doc))
+            && match attr.meta_item_list() {
+                Some(l) => attr::list_contains_name(&l, sym!(hidden)),
+                None => false,
+            }
+    }
+
+    if_chain! {
+        let mut markers = variants.iter().filter(|v| is_non_exhaustive_marker(v));
+        if let Some(marker) = markers.next();
+        if markers.count() == 0 && variants.len() > 1;
+        then {
+            span_lint_and_then(
+                cx,
+                MANUAL_NON_EXHAUSTIVE,
+                item.span,
+                "this seems like a manual implementation of the non-exhaustive pattern",
+                |diag| {
+                    if_chain! {
+                        if !attr::contains_name(&item.attrs, sym!(non_exhaustive));
+                        let header_span = cx.sess.source_map().span_until_char(item.span, '{');
+                        if let Some(snippet) = snippet_opt(cx, header_span);
+                        then {
+                            diag.span_suggestion(
+                                header_span,
+                                "add the attribute",
+                                format!("#[non_exhaustive] {}", snippet),
+                                Applicability::Unspecified,
+                            );
+                        }
+                    }
+                    diag.span_help(marker.span, "remove this variant");
+                });
+        }
+    }
+}
+
+fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) {
+    fn is_private(field: &StructField) -> bool {
+        matches!(field.vis.node, VisibilityKind::Inherited)
+    }
+
+    fn is_non_exhaustive_marker(field: &StructField) -> bool {
+        is_private(field) && field.ty.kind.is_unit() && field.ident.map_or(true, |n| n.as_str().starts_with('_'))
+    }
+
+    fn find_header_span(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) -> Span {
+        let delimiter = match data {
+            VariantData::Struct(..) => '{',
+            VariantData::Tuple(..) => '(',
+            VariantData::Unit(_) => unreachable!("`VariantData::Unit` is already handled above"),
+        };
+
+        cx.sess.source_map().span_until_char(item.span, delimiter)
+    }
+
+    let fields = data.fields();
+    let private_fields = fields.iter().filter(|f| is_private(f)).count();
+    let public_fields = fields.iter().filter(|f| f.vis.node.is_pub()).count();
+
+    if_chain! {
+        if private_fields == 1 && public_fields >= 1 && public_fields == fields.len() - 1;
+        if let Some(marker) = fields.iter().find(|f| is_non_exhaustive_marker(f));
+        then {
+            span_lint_and_then(
+                cx,
+                MANUAL_NON_EXHAUSTIVE,
+                item.span,
+                "this seems like a manual implementation of the non-exhaustive pattern",
+                |diag| {
+                    if_chain! {
+                        if !attr::contains_name(&item.attrs, sym!(non_exhaustive));
+                        let header_span = find_header_span(cx, item, data);
+                        if let Some(snippet) = snippet_opt(cx, header_span);
+                        then {
+                            diag.span_suggestion(
+                                header_span,
+                                "add the attribute",
+                                format!("#[non_exhaustive] {}", snippet),
+                                Applicability::Unspecified,
+                            );
+                        }
+                    }
+                    diag.span_help(marker.span, "remove this field");
+                });
+        }
+    }
+}
diff --git a/clippy_lints/src/match_on_vec_items.rs b/clippy_lints/src/match_on_vec_items.rs
index 4071406cc84c..ee69628e9f05 100644
--- a/clippy_lints/src/match_on_vec_items.rs
+++ b/clippy_lints/src/match_on_vec_items.rs
@@ -1,4 +1,4 @@
-use crate::utils::{is_type_diagnostic_item, snippet, span_lint_and_sugg, walk_ptrs_ty};
+use crate::utils::{self, is_type_diagnostic_item, match_type, snippet, span_lint_and_sugg, walk_ptrs_ty};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, MatchSource};
@@ -38,7 +38,7 @@ declare_clippy_lint! {
     /// }
     /// ```
     pub MATCH_ON_VEC_ITEMS,
-    correctness,
+    pedantic,
     "matching on vector elements can panic"
 }
 
@@ -75,10 +75,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MatchOnVecItems {
 
 fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
     if_chain! {
-        if let ExprKind::Index(ref array, _) = expr.kind;
-        let ty = cx.tables.expr_ty(array);
-        let ty = walk_ptrs_ty(ty);
-        if is_type_diagnostic_item(cx, ty, sym!(vec_type));
+        if let ExprKind::Index(ref array, ref index) = expr.kind;
+        if is_vector(cx, array);
+        if !is_full_range(cx, index);
 
         then {
             return Some(expr);
@@ -87,3 +86,15 @@ fn is_vec_indexing<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'tcx>)
 
     None
 }
+
+fn is_vector(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.tables.expr_ty(expr);
+    let ty = walk_ptrs_ty(ty);
+    is_type_diagnostic_item(cx, ty, sym!(vec_type))
+}
+
+fn is_full_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
+    let ty = cx.tables.expr_ty(expr);
+    let ty = walk_ptrs_ty(ty);
+    match_type(cx, ty, &utils::paths::RANGE_FULL)
+}
diff --git a/clippy_lints/src/misc_early.rs b/clippy_lints/src/misc_early.rs
index adfd8dfb1c18..62ee051624b4 100644
--- a/clippy_lints/src/misc_early.rs
+++ b/clippy_lints/src/misc_early.rs
@@ -24,8 +24,25 @@ declare_clippy_lint! {
     /// **Known problems:** None.
     ///
     /// **Example:**
-    /// ```ignore
-    /// let { a: _, b: ref b, c: _ } = ..
+    /// ```rust
+    /// # struct Foo {
+    /// #     a: i32,
+    /// #     b: i32,
+    /// #     c: i32,
+    /// # }
+    /// let f = Foo { a: 0, b: 0, c: 0 };
+    ///
+    /// // Bad
+    /// match f {
+    ///     Foo { a: _, b: 0, .. } => {},
+    ///     Foo { a: _, b: _, c: _ } => {},
+    /// }
+    ///
+    /// // Good
+    /// match f {
+    ///     Foo { b: 0, .. } => {},
+    ///     Foo { .. } => {},
+    /// }
     /// ```
     pub UNNEEDED_FIELD_PATTERN,
     restriction,
diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs
index 5235c98efab1..f3844c7d3b68 100644
--- a/clippy_lints/src/unwrap.rs
+++ b/clippy_lints/src/unwrap.rs
@@ -1,4 +1,7 @@
-use crate::utils::{higher::if_block, is_type_diagnostic_item, span_lint_and_then, usage::is_potentially_mutated};
+use crate::utils::{
+    differing_macro_contexts, higher::if_block, is_type_diagnostic_item, span_lint_and_then,
+    usage::is_potentially_mutated,
+};
 use if_chain::if_chain;
 use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Path, QPath, UnOp};
@@ -73,6 +76,8 @@ struct UnwrapInfo<'tcx> {
     ident: &'tcx Path<'tcx>,
     /// The check, like `x.is_ok()`
     check: &'tcx Expr<'tcx>,
+    /// The branch where the check takes place, like `if x.is_ok() { .. }`
+    branch: &'tcx Expr<'tcx>,
     /// Whether `is_some()` or `is_ok()` was called (as opposed to `is_err()` or `is_none()`).
     safe_to_unwrap: bool,
 }
@@ -82,19 +87,20 @@ struct UnwrapInfo<'tcx> {
 fn collect_unwrap_info<'a, 'tcx>(
     cx: &'a LateContext<'a, 'tcx>,
     expr: &'tcx Expr<'_>,
+    branch: &'tcx Expr<'_>,
     invert: bool,
 ) -> Vec<UnwrapInfo<'tcx>> {
     if let ExprKind::Binary(op, left, right) = &expr.kind {
         match (invert, op.node) {
             (false, BinOpKind::And) | (false, BinOpKind::BitAnd) | (true, BinOpKind::Or) | (true, BinOpKind::BitOr) => {
-                let mut unwrap_info = collect_unwrap_info(cx, left, invert);
-                unwrap_info.append(&mut collect_unwrap_info(cx, right, invert));
+                let mut unwrap_info = collect_unwrap_info(cx, left, branch, invert);
+                unwrap_info.append(&mut collect_unwrap_info(cx, right, branch, invert));
                 return unwrap_info;
             },
             _ => (),
         }
     } else if let ExprKind::Unary(UnOp::UnNot, expr) = &expr.kind {
-        return collect_unwrap_info(cx, expr, !invert);
+        return collect_unwrap_info(cx, expr, branch, !invert);
     } else {
         if_chain! {
             if let ExprKind::MethodCall(method_name, _, args) = &expr.kind;
@@ -111,7 +117,7 @@ fn collect_unwrap_info<'a, 'tcx>(
                     _ => unreachable!(),
                 };
                 let safe_to_unwrap = unwrappable != invert;
-                return vec![UnwrapInfo { ident: path, check: expr, safe_to_unwrap }];
+                return vec![UnwrapInfo { ident: path, check: expr, branch, safe_to_unwrap }];
             }
         }
     }
@@ -121,7 +127,7 @@ fn collect_unwrap_info<'a, 'tcx>(
 impl<'a, 'tcx> UnwrappableVariablesVisitor<'a, 'tcx> {
     fn visit_branch(&mut self, cond: &'tcx Expr<'_>, branch: &'tcx Expr<'_>, else_branch: bool) {
         let prev_len = self.unwrappables.len();
-        for unwrap_info in collect_unwrap_info(self.cx, cond, else_branch) {
+        for unwrap_info in collect_unwrap_info(self.cx, cond, branch, else_branch) {
             if is_potentially_mutated(unwrap_info.ident, cond, self.cx)
                 || is_potentially_mutated(unwrap_info.ident, branch, self.cx)
             {
@@ -158,6 +164,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
                 let call_to_unwrap = method_name.ident.name == sym!(unwrap);
                 if let Some(unwrappable) = self.unwrappables.iter()
                     .find(|u| u.ident.res == path.res);
+                // Span contexts should not differ with the conditional branch
+                if !differing_macro_contexts(unwrappable.branch.span, expr.span);
+                if !differing_macro_contexts(unwrappable.branch.span, unwrappable.check.span);
                 then {
                     if call_to_unwrap == unwrappable.safe_to_unwrap {
                         span_lint_and_then(
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 4b81ff33495c..57b9eafd14db 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -158,6 +158,8 @@ define_Conf! {
     (max_struct_bools, "max_struct_bools": u64, 3),
     /// Lint: FN_PARAMS_EXCESSIVE_BOOLS. The maximum number of bools function parameters can have
     (max_fn_params_bools, "max_fn_params_bools": u64, 3),
+    /// Lint: WILDCARD_IMPORTS. Whether to allow certain wildcard imports (prelude, super in tests).
+    (warn_on_all_wildcard_imports, "warn_on_all_wildcard_imports": bool, false),
 }
 
 impl Default for Conf {
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index 2fd080e9ef0f..3b8ef18bfab8 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -933,6 +933,7 @@ pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_, '_>, expr: &Exp
 }
 
 /// Returns `true` if a pattern is refutable.
+// TODO: should be implemented using rustc/mir_build/hair machinery
 pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat<'_>) -> bool {
     fn is_enum_variant(cx: &LateContext<'_, '_>, qpath: &QPath<'_>, id: HirId) -> bool {
         matches!(
@@ -946,27 +947,34 @@ pub fn is_refutable(cx: &LateContext<'_, '_>, pat: &Pat<'_>) -> bool {
     }
 
     match pat.kind {
-        PatKind::Binding(..) | PatKind::Wild => false,
+        PatKind::Wild => false,
+        PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
         PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat),
         PatKind::Lit(..) | PatKind::Range(..) => true,
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
-        PatKind::Or(ref pats) | PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
+        PatKind::Or(ref pats) => {
+            // TODO: should be the honest check, that pats is exhaustive set
+            are_refutable(cx, pats.iter().map(|pat| &**pat))
+        },
+        PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)),
         PatKind::Struct(ref qpath, ref fields, _) => {
-            if is_enum_variant(cx, qpath, pat.hir_id) {
-                true
-            } else {
-                are_refutable(cx, fields.iter().map(|field| &*field.pat))
-            }
+            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat))
         },
         PatKind::TupleStruct(ref qpath, ref pats, _) => {
-            if is_enum_variant(cx, qpath, pat.hir_id) {
-                true
-            } else {
-                are_refutable(cx, pats.iter().map(|pat| &**pat))
-            }
+            is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat))
         },
         PatKind::Slice(ref head, ref middle, ref tail) => {
-            are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat))
+            match &cx.tables.node_type(pat.hir_id).kind {
+                ty::Slice(..) => {
+                    // [..] is the only irrefutable slice pattern.
+                    !head.is_empty() || middle.is_none() || !tail.is_empty()
+                },
+                ty::Array(..) => are_refutable(cx, head.iter().chain(middle).chain(tail.iter()).map(|pat| &**pat)),
+                _ => {
+                    // unreachable!()
+                    true
+                },
+            }
         },
     }
 }
diff --git a/clippy_lints/src/utils/paths.rs b/clippy_lints/src/utils/paths.rs
index ca2c4ade1556..b3ad2ad9d998 100644
--- a/clippy_lints/src/utils/paths.rs
+++ b/clippy_lints/src/utils/paths.rs
@@ -42,6 +42,7 @@ pub const FMT_ARGUMENTS_NEW_V1_FORMATTED: [&str; 4] = ["core", "fmt", "Arguments
 pub const FMT_ARGUMENTV1_NEW: [&str; 4] = ["core", "fmt", "ArgumentV1", "new"];
 pub const FROM_FROM: [&str; 4] = ["core", "convert", "From", "from"];
 pub const FROM_TRAIT: [&str; 3] = ["core", "convert", "From"];
+pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
 pub const HASH: [&str; 2] = ["hash", "Hash"];
 pub const HASHMAP: [&str; 5] = ["std", "collections", "hash", "map", "HashMap"];
 pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
@@ -85,7 +86,7 @@ pub const RANGE: [&str; 3] = ["core", "ops", "Range"];
 pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
 pub const RANGE_FROM: [&str; 3] = ["core", "ops", "RangeFrom"];
 pub const RANGE_FROM_STD: [&str; 3] = ["std", "ops", "RangeFrom"];
-pub const RANGE_FULL: [&str; 3] = ["core", "ops", "RangeFull"];
+pub const RANGE_FULL: [&str; 4] = ["core", "ops", "range", "RangeFull"];
 pub const RANGE_FULL_STD: [&str; 3] = ["std", "ops", "RangeFull"];
 pub const RANGE_INCLUSIVE_NEW: [&str; 4] = ["core", "ops", "RangeInclusive", "new"];
 pub const RANGE_INCLUSIVE_STD_NEW: [&str; 4] = ["std", "ops", "RangeInclusive", "new"];
diff --git a/clippy_lints/src/wildcard_imports.rs b/clippy_lints/src/wildcard_imports.rs
index f3038861cee2..32d9a45c37d7 100644
--- a/clippy_lints/src/wildcard_imports.rs
+++ b/clippy_lints/src/wildcard_imports.rs
@@ -3,10 +3,10 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{
     def::{DefKind, Res},
-    Item, ItemKind, UseKind,
+    Item, ItemKind, PathSegment, UseKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::BytePos;
 
 declare_clippy_lint! {
@@ -43,9 +43,14 @@ declare_clippy_lint! {
     ///
     /// This can lead to confusing error messages at best and to unexpected behavior at worst.
     ///
-    /// Note that this will not warn about wildcard imports from modules named `prelude`; many
-    /// crates (including the standard library) provide modules named "prelude" specifically
-    /// designed for wildcard import.
+    /// **Exceptions:**
+    ///
+    /// Wildcard imports are allowed from modules named `prelude`. Many crates (including the standard library)
+    /// provide modules named "prelude" specifically designed for wildcard import.
+    ///
+    /// `use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
+    ///
+    /// These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag.
     ///
     /// **Known problems:** If macros are imported through the wildcard, this macro is not included
     /// by the suggestion and has to be added by hand.
@@ -73,18 +78,34 @@ declare_clippy_lint! {
     "lint `use _::*` statements"
 }
 
-declare_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
+#[derive(Default)]
+pub struct WildcardImports {
+    warn_on_all: bool,
+    test_modules_deep: u32,
+}
+
+impl WildcardImports {
+    pub fn new(warn_on_all: bool) -> Self {
+        Self {
+            warn_on_all,
+            test_modules_deep: 0,
+        }
+    }
+}
+
+impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]);
 
 impl LateLintPass<'_, '_> for WildcardImports {
     fn check_item(&mut self, cx: &LateContext<'_, '_>, item: &Item<'_>) {
+        if is_test_module_or_function(item) {
+            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
+        }
         if item.vis.node.is_pub() || item.vis.node.is_pub_restricted() {
             return;
         }
         if_chain! {
-            if !in_macro(item.span);
             if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
-            // don't lint prelude glob imports
-            if !use_path.segments.iter().last().map_or(false, |ps| ps.ident.as_str() == "prelude");
+            if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
             let used_imports = cx.tcx.names_imported_by_glob_use(item.hir_id.owner);
             if !used_imports.is_empty(); // Already handled by `unused_imports`
             then {
@@ -109,8 +130,7 @@ impl LateLintPass<'_, '_> for WildcardImports {
                         span = use_path.span.with_hi(item.span.hi() - BytePos(1));
                     }
                     (
-                        span,
-                        false,
+                        span, false,
                     )
                 };
 
@@ -153,4 +173,36 @@ impl LateLintPass<'_, '_> for WildcardImports {
             }
         }
     }
+
+    fn check_item_post(&mut self, _: &LateContext<'_, '_>, item: &Item<'_>) {
+        if is_test_module_or_function(item) {
+            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
+        }
+    }
+}
+
+impl WildcardImports {
+    fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
+        in_macro(item.span)
+            || is_prelude_import(segments)
+            || (is_super_only_import(segments) && self.test_modules_deep > 0)
+    }
+}
+
+// Allow "...prelude::*" imports.
+// Many crates have a prelude, and it is imported as a glob by design.
+fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool {
+    segments
+        .iter()
+        .last()
+        .map_or(false, |ps| ps.ident.as_str() == "prelude")
+}
+
+// Allow "super::*" imports in tests.
+fn is_super_only_import(segments: &[PathSegment<'_>]) -> bool {
+    segments.len() == 1 && segments[0].ident.as_str() == "super"
+}
+
+fn is_test_module_or_function(item: &Item<'_>) -> bool {
+    matches!(item.kind, ItemKind::Mod(..)) && item.ident.name.as_str().contains("test")
 }
diff --git a/src/lintlist/mod.rs b/src/lintlist/mod.rs
index 72675c25175c..51d1cb2216a9 100644
--- a/src/lintlist/mod.rs
+++ b/src/lintlist/mod.rs
@@ -1081,6 +1081,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         deprecation: None,
         module: "main_recursion",
     },
+    Lint {
+        name: "manual_async_fn",
+        group: "style",
+        desc: "manual implementations of `async` functions can be simplified using the dedicated syntax",
+        deprecation: None,
+        module: "manual_async_fn",
+    },
     Lint {
         name: "manual_memcpy",
         group: "perf",
@@ -1088,6 +1095,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
         deprecation: None,
         module: "loops",
     },
+    Lint {
+        name: "manual_non_exhaustive",
+        group: "style",
+        desc: "manual implementations of the non-exhaustive pattern can be simplified using #[non_exhaustive]",
+        deprecation: None,
+        module: "manual_non_exhaustive",
+    },
     Lint {
         name: "manual_saturating_arithmetic",
         group: "style",
@@ -1146,7 +1160,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
     },
     Lint {
         name: "match_on_vec_items",
-        group: "correctness",
+        group: "pedantic",
         desc: "matching on vector elements can panic",
         deprecation: None,
         module: "match_on_vec_items",
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 18f5d994ba8a..53970af41079 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-struct-bools`, `max-fn-params-bools`, `third-party` at line 5 column 1
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `third-party` at line 5 column 1
 
 error: aborting due to previous error
 
diff --git a/tests/ui/builtin-type-shadow.stderr b/tests/ui/builtin-type-shadow.stderr
index b6a4adde8488..bc785b075e02 100644
--- a/tests/ui/builtin-type-shadow.stderr
+++ b/tests/ui/builtin-type-shadow.stderr
@@ -18,8 +18,6 @@ LL |     42
    |
    = note: expected type parameter `u32`
                         found type `{integer}`
-   = help: type parameters must be constrained to match other types
-   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/checked_unwrap/simple_conditionals.rs b/tests/ui/checked_unwrap/simple_conditionals.rs
index b0fc26ff76de..3e7b4b390bad 100644
--- a/tests/ui/checked_unwrap/simple_conditionals.rs
+++ b/tests/ui/checked_unwrap/simple_conditionals.rs
@@ -9,6 +9,30 @@ macro_rules! m {
     };
 }
 
+macro_rules! checks_in_param {
+    ($a:expr, $b:expr) => {
+        if $a {
+            $b;
+        }
+    };
+}
+
+macro_rules! checks_unwrap {
+    ($a:expr, $b:expr) => {
+        if $a.is_some() {
+            $b;
+        }
+    };
+}
+
+macro_rules! checks_some {
+    ($a:expr, $b:expr) => {
+        if $a {
+            $b.unwrap();
+        }
+    };
+}
+
 fn main() {
     let x = Some(());
     if x.is_some() {
@@ -22,6 +46,9 @@ fn main() {
         x.unwrap(); // unnecessary
     }
     m!(x);
+    checks_in_param!(x.is_some(), x.unwrap()); // ok
+    checks_unwrap!(x, x.unwrap()); // ok
+    checks_some!(x.is_some(), x); // ok
     let mut x: Result<(), ()> = Ok(());
     if x.is_ok() {
         x.unwrap(); // unnecessary
diff --git a/tests/ui/checked_unwrap/simple_conditionals.stderr b/tests/ui/checked_unwrap/simple_conditionals.stderr
index e40542e2e4f9..4013d1ed667f 100644
--- a/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -1,5 +1,5 @@
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
-  --> $DIR/simple_conditionals.rs:15:9
+  --> $DIR/simple_conditionals.rs:39:9
    |
 LL |     if x.is_some() {
    |        ----------- the check is happening here
@@ -13,7 +13,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
-  --> $DIR/simple_conditionals.rs:17:9
+  --> $DIR/simple_conditionals.rs:41:9
    |
 LL |     if x.is_some() {
    |        ----------- because of this check
@@ -28,7 +28,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
-  --> $DIR/simple_conditionals.rs:20:9
+  --> $DIR/simple_conditionals.rs:44:9
    |
 LL |     if x.is_none() {
    |        ----------- because of this check
@@ -36,7 +36,7 @@ LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
-  --> $DIR/simple_conditionals.rs:22:9
+  --> $DIR/simple_conditionals.rs:46:9
    |
 LL |     if x.is_none() {
    |        ----------- the check is happening here
@@ -58,7 +58,7 @@ LL |     m!(x);
    = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
-  --> $DIR/simple_conditionals.rs:27:9
+  --> $DIR/simple_conditionals.rs:54:9
    |
 LL |     if x.is_ok() {
    |        --------- the check is happening here
@@ -66,7 +66,7 @@ LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
-  --> $DIR/simple_conditionals.rs:28:9
+  --> $DIR/simple_conditionals.rs:55:9
    |
 LL |     if x.is_ok() {
    |        --------- because of this check
@@ -75,7 +75,7 @@ LL |         x.unwrap_err(); // will panic
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
-  --> $DIR/simple_conditionals.rs:30:9
+  --> $DIR/simple_conditionals.rs:57:9
    |
 LL |     if x.is_ok() {
    |        --------- because of this check
@@ -84,7 +84,7 @@ LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
-  --> $DIR/simple_conditionals.rs:31:9
+  --> $DIR/simple_conditionals.rs:58:9
    |
 LL |     if x.is_ok() {
    |        --------- the check is happening here
@@ -93,7 +93,7 @@ LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: This call to `unwrap()` will always panic.
-  --> $DIR/simple_conditionals.rs:34:9
+  --> $DIR/simple_conditionals.rs:61:9
    |
 LL |     if x.is_err() {
    |        ---------- because of this check
@@ -101,7 +101,7 @@ LL |         x.unwrap(); // will panic
    |         ^^^^^^^^^^
 
 error: You checked before that `unwrap_err()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
-  --> $DIR/simple_conditionals.rs:35:9
+  --> $DIR/simple_conditionals.rs:62:9
    |
 LL |     if x.is_err() {
    |        ---------- the check is happening here
@@ -110,7 +110,7 @@ LL |         x.unwrap_err(); // unnecessary
    |         ^^^^^^^^^^^^^^
 
 error: You checked before that `unwrap()` cannot fail. Instead of checking and unwrapping, it's better to use `if let` or `match`.
-  --> $DIR/simple_conditionals.rs:37:9
+  --> $DIR/simple_conditionals.rs:64:9
    |
 LL |     if x.is_err() {
    |        ---------- the check is happening here
@@ -119,7 +119,7 @@ LL |         x.unwrap(); // unnecessary
    |         ^^^^^^^^^^
 
 error: This call to `unwrap_err()` will always panic.
-  --> $DIR/simple_conditionals.rs:38:9
+  --> $DIR/simple_conditionals.rs:65:9
    |
 LL |     if x.is_err() {
    |        ---------- because of this check
diff --git a/tests/ui/future_not_send.rs b/tests/ui/future_not_send.rs
index 6d09d71a630a..d3a920de4b6a 100644
--- a/tests/ui/future_not_send.rs
+++ b/tests/ui/future_not_send.rs
@@ -41,6 +41,7 @@ impl Dummy {
         self.private_future().await;
     }
 
+    #[allow(clippy::manual_async_fn)]
     pub fn public_send(&self) -> impl std::future::Future<Output = bool> {
         async { false }
     }
diff --git a/tests/ui/future_not_send.stderr b/tests/ui/future_not_send.stderr
index 3b4968ef0a63..d1863701bfe7 100644
--- a/tests/ui/future_not_send.stderr
+++ b/tests/ui/future_not_send.stderr
@@ -96,13 +96,13 @@ LL |     }
    = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:49:37
+  --> $DIR/future_not_send.rs:50:37
    |
 LL | async fn generic_future<T>(t: T) -> T
    |                                     ^ future returned by `generic_future` is not `Send`
    |
 note: future is not `Send` as this value is used across an await
-  --> $DIR/future_not_send.rs:54:5
+  --> $DIR/future_not_send.rs:55:5
    |
 LL |     let rt = &t;
    |         -- has type `&T` which is not `Send`
@@ -114,7 +114,7 @@ LL | }
    = note: `T` doesn't implement `std::marker::Sync`
 
 error: future cannot be sent between threads safely
-  --> $DIR/future_not_send.rs:65:34
+  --> $DIR/future_not_send.rs:66:34
    |
 LL | async fn unclear_future<T>(t: T) {}
    |                                  ^
diff --git a/tests/ui/manual_async_fn.fixed b/tests/ui/manual_async_fn.fixed
new file mode 100644
index 000000000000..6bb1032a1729
--- /dev/null
+++ b/tests/ui/manual_async_fn.fixed
@@ -0,0 +1,67 @@
+// run-rustfix
+// edition:2018
+#![warn(clippy::manual_async_fn)]
+#![allow(unused)]
+
+use std::future::Future;
+
+async fn fut() -> i32 { 42 }
+
+async fn empty_fut()  {}
+
+async fn core_fut() -> i32 { 42 }
+
+// should be ignored
+fn has_other_stmts() -> impl core::future::Future<Output = i32> {
+    let _ = 42;
+    async move { 42 }
+}
+
+// should be ignored
+fn not_fut() -> i32 {
+    42
+}
+
+// should be ignored
+async fn already_async() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+struct S {}
+impl S {
+    async fn inh_fut() -> i32 {
+        // NOTE: this code is here just to check that the identation is correct in the suggested fix
+        let a = 42;
+        let b = 21;
+        if a < b {
+            let c = 21;
+            let d = 42;
+            if c < d {
+                let _ = 42;
+            }
+        }
+        42
+    }
+
+    async fn meth_fut(&self) -> i32 { 42 }
+
+    async fn empty_fut(&self)  {}
+
+    // should be ignored
+    fn not_fut(&self) -> i32 {
+        42
+    }
+
+    // should be ignored
+    fn has_other_stmts() -> impl core::future::Future<Output = i32> {
+        let _ = 42;
+        async move { 42 }
+    }
+
+    // should be ignored
+    async fn already_async(&self) -> impl Future<Output = i32> {
+        async { 42 }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/manual_async_fn.rs b/tests/ui/manual_async_fn.rs
new file mode 100644
index 000000000000..d50c919188be
--- /dev/null
+++ b/tests/ui/manual_async_fn.rs
@@ -0,0 +1,79 @@
+// run-rustfix
+// edition:2018
+#![warn(clippy::manual_async_fn)]
+#![allow(unused)]
+
+use std::future::Future;
+
+fn fut() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+fn empty_fut() -> impl Future<Output = ()> {
+    async {}
+}
+
+fn core_fut() -> impl core::future::Future<Output = i32> {
+    async move { 42 }
+}
+
+// should be ignored
+fn has_other_stmts() -> impl core::future::Future<Output = i32> {
+    let _ = 42;
+    async move { 42 }
+}
+
+// should be ignored
+fn not_fut() -> i32 {
+    42
+}
+
+// should be ignored
+async fn already_async() -> impl Future<Output = i32> {
+    async { 42 }
+}
+
+struct S {}
+impl S {
+    fn inh_fut() -> impl Future<Output = i32> {
+        async {
+            // NOTE: this code is here just to check that the identation is correct in the suggested fix
+            let a = 42;
+            let b = 21;
+            if a < b {
+                let c = 21;
+                let d = 42;
+                if c < d {
+                    let _ = 42;
+                }
+            }
+            42
+        }
+    }
+
+    fn meth_fut(&self) -> impl Future<Output = i32> {
+        async { 42 }
+    }
+
+    fn empty_fut(&self) -> impl Future<Output = ()> {
+        async {}
+    }
+
+    // should be ignored
+    fn not_fut(&self) -> i32 {
+        42
+    }
+
+    // should be ignored
+    fn has_other_stmts() -> impl core::future::Future<Output = i32> {
+        let _ = 42;
+        async move { 42 }
+    }
+
+    // should be ignored
+    async fn already_async(&self) -> impl Future<Output = i32> {
+        async { 42 }
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/manual_async_fn.stderr b/tests/ui/manual_async_fn.stderr
new file mode 100644
index 000000000000..f278ee41aa33
--- /dev/null
+++ b/tests/ui/manual_async_fn.stderr
@@ -0,0 +1,98 @@
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:8:1
+   |
+LL | fn fut() -> impl Future<Output = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::manual-async-fn` implied by `-D warnings`
+help: make the function `async` and return the output of the future directly
+   |
+LL | async fn fut() -> i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL | fn fut() -> impl Future<Output = i32> { 42 }
+   |                                       ^^^^^^
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:12:1
+   |
+LL | fn empty_fut() -> impl Future<Output = ()> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and remove the return type
+   |
+LL | async fn empty_fut()  {
+   | ^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL | fn empty_fut() -> impl Future<Output = ()> {}
+   |                                            ^^
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:16:1
+   |
+LL | fn core_fut() -> impl core::future::Future<Output = i32> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL | async fn core_fut() -> i32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL | fn core_fut() -> impl core::future::Future<Output = i32> { 42 }
+   |                                                          ^^^^^^
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:38:5
+   |
+LL |     fn inh_fut() -> impl Future<Output = i32> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL |     async fn inh_fut() -> i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL |     fn inh_fut() -> impl Future<Output = i32> {
+LL |         // NOTE: this code is here just to check that the identation is correct in the suggested fix
+LL |         let a = 42;
+LL |         let b = 21;
+LL |         if a < b {
+LL |             let c = 21;
+ ...
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:54:5
+   |
+LL |     fn meth_fut(&self) -> impl Future<Output = i32> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and return the output of the future directly
+   |
+LL |     async fn meth_fut(&self) -> i32 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL |     fn meth_fut(&self) -> impl Future<Output = i32> { 42 }
+   |                                                     ^^^^^^
+
+error: this function can be simplified using the `async fn` syntax
+  --> $DIR/manual_async_fn.rs:58:5
+   |
+LL |     fn empty_fut(&self) -> impl Future<Output = ()> {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: make the function `async` and remove the return type
+   |
+LL |     async fn empty_fut(&self)  {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+help: move the body of the async block to the enclosing function
+   |
+LL |     fn empty_fut(&self) -> impl Future<Output = ()> {}
+   |                                                     ^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/manual_memcpy.rs b/tests/ui/manual_memcpy.rs
index aa347288875d..9c24d6d4db1f 100644
--- a/tests/ui/manual_memcpy.rs
+++ b/tests/ui/manual_memcpy.rs
@@ -98,6 +98,21 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) {
     for i in from..from + 3 {
         dst[i] = src[i - from];
     }
+
+    #[allow(clippy::identity_op)]
+    for i in 0..5 {
+        dst[i - 0] = src[i];
+    }
+
+    #[allow(clippy::reverse_range_loop)]
+    for i in 0..0 {
+        dst[i] = src[i];
+    }
+
+    // `RangeTo` `for` loop - don't trigger lint
+    for i in 0.. {
+        dst[i] = src[i];
+    }
 }
 
 #[warn(clippy::needless_range_loop, clippy::manual_memcpy)]
diff --git a/tests/ui/manual_memcpy.stderr b/tests/ui/manual_memcpy.stderr
index 3dbb2155d4de..bad84a589008 100644
--- a/tests/ui/manual_memcpy.stderr
+++ b/tests/ui/manual_memcpy.stderr
@@ -58,19 +58,31 @@ error: it looks like you're manually copying between slices
   --> $DIR/manual_memcpy.rs:94:14
    |
 LL |     for i in from..from + src.len() {
-   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[0..(from + src.len() - from)])`
+   |              ^^^^^^^^^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + src.len()].clone_from_slice(&src[..(from + src.len() - from)])`
 
 error: it looks like you're manually copying between slices
   --> $DIR/manual_memcpy.rs:98:14
    |
 LL |     for i in from..from + 3 {
-   |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[0..(from + 3 - from)])`
+   |              ^^^^^^^^^^^^^^ help: try replacing the loop by: `dst[from..from + 3].clone_from_slice(&src[..(from + 3 - from)])`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/manual_memcpy.rs:105:14
+  --> $DIR/manual_memcpy.rs:103:14
+   |
+LL |     for i in 0..5 {
+   |              ^^^^ help: try replacing the loop by: `dst[..5].clone_from_slice(&src[..5])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:108:14
+   |
+LL |     for i in 0..0 {
+   |              ^^^^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0])`
+
+error: it looks like you're manually copying between slices
+  --> $DIR/manual_memcpy.rs:120:14
    |
 LL |     for i in 0..src.len() {
    |              ^^^^^^^^^^^^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..])`
 
-error: aborting due to 11 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/manual_non_exhaustive.rs b/tests/ui/manual_non_exhaustive.rs
new file mode 100644
index 000000000000..7a788f485207
--- /dev/null
+++ b/tests/ui/manual_non_exhaustive.rs
@@ -0,0 +1,137 @@
+#![warn(clippy::manual_non_exhaustive)]
+#![allow(unused)]
+
+mod enums {
+    enum E {
+        A,
+        B,
+        #[doc(hidden)]
+        _C,
+    }
+
+    // user forgot to remove the marker
+    #[non_exhaustive]
+    enum Ep {
+        A,
+        B,
+        #[doc(hidden)]
+        _C,
+    }
+
+    // marker variant does not have doc hidden attribute, should be ignored
+    enum NoDocHidden {
+        A,
+        B,
+        _C,
+    }
+
+    // name of variant with doc hidden does not start with underscore, should be ignored
+    enum NoUnderscore {
+        A,
+        B,
+        #[doc(hidden)]
+        C,
+    }
+
+    // variant with doc hidden is not unit, should be ignored
+    enum NotUnit {
+        A,
+        B,
+        #[doc(hidden)]
+        _C(bool),
+    }
+
+    // variant with doc hidden is the only one, should be ignored
+    enum OnlyMarker {
+        #[doc(hidden)]
+        _A,
+    }
+
+    // variant with multiple markers, should be ignored
+    enum MultipleMarkers {
+        A,
+        #[doc(hidden)]
+        _B,
+        #[doc(hidden)]
+        _C,
+    }
+
+    // already non_exhaustive and no markers, should be ignored
+    #[non_exhaustive]
+    enum NonExhaustive {
+        A,
+        B,
+    }
+}
+
+mod structs {
+    struct S {
+        pub a: i32,
+        pub b: i32,
+        _c: (),
+    }
+
+    // user forgot to remove the private field
+    #[non_exhaustive]
+    struct Sp {
+        pub a: i32,
+        pub b: i32,
+        _c: (),
+    }
+
+    // some other fields are private, should be ignored
+    struct PrivateFields {
+        a: i32,
+        pub b: i32,
+        _c: (),
+    }
+
+    // private field name does not start with underscore, should be ignored
+    struct NoUnderscore {
+        pub a: i32,
+        pub b: i32,
+        c: (),
+    }
+
+    // private field is not unit type, should be ignored
+    struct NotUnit {
+        pub a: i32,
+        pub b: i32,
+        _c: i32,
+    }
+
+    // private field is the only field, should be ignored
+    struct OnlyMarker {
+        _a: (),
+    }
+
+    // already non exhaustive and no private fields, should be ignored
+    #[non_exhaustive]
+    struct NonExhaustive {
+        pub a: i32,
+        pub b: i32,
+    }
+}
+
+mod tuple_structs {
+    struct T(pub i32, pub i32, ());
+
+    // user forgot to remove the private field
+    #[non_exhaustive]
+    struct Tp(pub i32, pub i32, ());
+
+    // some other fields are private, should be ignored
+    struct PrivateFields(pub i32, i32, ());
+
+    // private field is not unit type, should be ignored
+    struct NotUnit(pub i32, pub i32, i32);
+
+    // private field is the only field, should be ignored
+    struct OnlyMarker(());
+
+    // already non exhaustive and no private fields, should be ignored
+    #[non_exhaustive]
+    struct NonExhaustive(pub i32, pub i32);
+}
+
+fn main() {}
diff --git a/tests/ui/manual_non_exhaustive.stderr b/tests/ui/manual_non_exhaustive.stderr
new file mode 100644
index 000000000000..613c5e8ca1d4
--- /dev/null
+++ b/tests/ui/manual_non_exhaustive.stderr
@@ -0,0 +1,103 @@
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:5:5
+   |
+LL |       enum E {
+   |       ^-----
+   |       |
+   |  _____help: add the attribute: `#[non_exhaustive] enum E`
+   | |
+LL | |         A,
+LL | |         B,
+LL | |         #[doc(hidden)]
+LL | |         _C,
+LL | |     }
+   | |_____^
+   |
+   = note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
+help: remove this variant
+  --> $DIR/manual_non_exhaustive.rs:9:9
+   |
+LL |         _C,
+   |         ^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:14:5
+   |
+LL | /     enum Ep {
+LL | |         A,
+LL | |         B,
+LL | |         #[doc(hidden)]
+LL | |         _C,
+LL | |     }
+   | |_____^
+   |
+help: remove this variant
+  --> $DIR/manual_non_exhaustive.rs:18:9
+   |
+LL |         _C,
+   |         ^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:68:5
+   |
+LL |       struct S {
+   |       ^-------
+   |       |
+   |  _____help: add the attribute: `#[non_exhaustive] struct S`
+   | |
+LL | |         pub a: i32,
+LL | |         pub b: i32,
+LL | |         _c: (),
+LL | |     }
+   | |_____^
+   |
+help: remove this field
+  --> $DIR/manual_non_exhaustive.rs:71:9
+   |
+LL |         _c: (),
+   |         ^^^^^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:76:5
+   |
+LL | /     struct Sp {
+LL | |         pub a: i32,
+LL | |         pub b: i32,
+LL | |         _c: (),
+LL | |     }
+   | |_____^
+   |
+help: remove this field
+  --> $DIR/manual_non_exhaustive.rs:79:9
+   |
+LL |         _c: (),
+   |         ^^^^^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:117:5
+   |
+LL |     struct T(pub i32, pub i32, ());
+   |     --------^^^^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     help: add the attribute: `#[non_exhaustive] struct T`
+   |
+help: remove this field
+  --> $DIR/manual_non_exhaustive.rs:117:32
+   |
+LL |     struct T(pub i32, pub i32, ());
+   |                                ^^
+
+error: this seems like a manual implementation of the non-exhaustive pattern
+  --> $DIR/manual_non_exhaustive.rs:121:5
+   |
+LL |     struct Tp(pub i32, pub i32, ());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove this field
+  --> $DIR/manual_non_exhaustive.rs:121:33
+   |
+LL |     struct Tp(pub i32, pub i32, ());
+   |                                 ^^
+
+error: aborting due to 6 previous errors
+
diff --git a/tests/ui/match_on_vec_items.rs b/tests/ui/match_on_vec_items.rs
index 0bb39d77e461..30415e3b94dc 100644
--- a/tests/ui/match_on_vec_items.rs
+++ b/tests/ui/match_on_vec_items.rs
@@ -120,6 +120,27 @@ fn match_with_array() {
     }
 }
 
+fn match_with_endless_range() {
+    let arr = vec![0, 1, 2, 3];
+    let range = ..;
+
+    // Ok
+    match arr[range] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        [0, 1, 2, 3] => println!("0, 1, 2, 3"),
+        _ => {},
+    }
+
+    // Ok
+    match arr[..] {
+        [0, 1] => println!("0 1"),
+        [1, 2] => println!("1 2"),
+        [0, 1, 2, 3] => println!("0, 1, 2, 3"),
+        _ => {},
+    }
+}
+
 fn main() {
     match_with_wildcard();
     match_without_wildcard();
@@ -127,4 +148,5 @@ fn main() {
     match_vec_ref();
     match_with_get();
     match_with_array();
+    match_with_endless_range();
 }
diff --git a/tests/ui/while_let_on_iterator.fixed b/tests/ui/while_let_on_iterator.fixed
index f5fcabf63fd3..e99c98ac79f2 100644
--- a/tests/ui/while_let_on_iterator.fixed
+++ b/tests/ui/while_let_on_iterator.fixed
@@ -2,6 +2,7 @@
 
 #![warn(clippy::while_let_on_iterator)]
 #![allow(clippy::never_loop, unreachable_code, unused_mut)]
+#![feature(or_patterns)]
 
 fn base() {
     let mut iter = 1..20;
@@ -77,6 +78,62 @@ fn refutable() {
     // */
 }
 
+fn refutable2() {
+    // Issue 3780
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.windows(2);
+        while let Some([x, y]) = it.next() {
+            println!("x: {}", x);
+            println!("y: {}", y);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([x, ..]) = it.next() {
+            println!("x: {}", x);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([.., y]) = it.next() {
+            println!("y: {}", y);
+        }
+
+        let mut it = v.windows(2);
+        for [..] in it {}
+
+        let v = vec![[1], [2], [3]];
+        let mut it = v.iter();
+        while let Some([1]) = it.next() {}
+
+        let mut it = v.iter();
+        for [_x] in it {}
+    }
+
+    // binding
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.iter();
+        while let Some(x @ 1) = it.next() {
+            println!("{}", x);
+        }
+
+        let v = vec![[1], [2], [3]];
+        let mut it = v.iter();
+        for x @ [_] in it {
+            println!("{:?}", x);
+        }
+    }
+
+    // false negative
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.iter().map(Some);
+        while let Some(Some(_) | None) = it.next() {
+            println!("1");
+        }
+    }
+}
+
 fn nested_loops() {
     let a = [42, 1337];
     let mut y = a.iter();
@@ -152,6 +209,7 @@ fn issue1654() {
 fn main() {
     base();
     refutable();
+    refutable2();
     nested_loops();
     issue1121();
     issue2965();
diff --git a/tests/ui/while_let_on_iterator.rs b/tests/ui/while_let_on_iterator.rs
index 04dce8a02898..ba13172428e1 100644
--- a/tests/ui/while_let_on_iterator.rs
+++ b/tests/ui/while_let_on_iterator.rs
@@ -2,6 +2,7 @@
 
 #![warn(clippy::while_let_on_iterator)]
 #![allow(clippy::never_loop, unreachable_code, unused_mut)]
+#![feature(or_patterns)]
 
 fn base() {
     let mut iter = 1..20;
@@ -77,6 +78,62 @@ fn refutable() {
     // */
 }
 
+fn refutable2() {
+    // Issue 3780
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.windows(2);
+        while let Some([x, y]) = it.next() {
+            println!("x: {}", x);
+            println!("y: {}", y);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([x, ..]) = it.next() {
+            println!("x: {}", x);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([.., y]) = it.next() {
+            println!("y: {}", y);
+        }
+
+        let mut it = v.windows(2);
+        while let Some([..]) = it.next() {}
+
+        let v = vec![[1], [2], [3]];
+        let mut it = v.iter();
+        while let Some([1]) = it.next() {}
+
+        let mut it = v.iter();
+        while let Some([_x]) = it.next() {}
+    }
+
+    // binding
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.iter();
+        while let Some(x @ 1) = it.next() {
+            println!("{}", x);
+        }
+
+        let v = vec![[1], [2], [3]];
+        let mut it = v.iter();
+        while let Some(x @ [_]) = it.next() {
+            println!("{:?}", x);
+        }
+    }
+
+    // false negative
+    {
+        let v = vec![1, 2, 3];
+        let mut it = v.iter().map(Some);
+        while let Some(Some(_) | None) = it.next() {
+            println!("1");
+        }
+    }
+}
+
 fn nested_loops() {
     let a = [42, 1337];
     let mut y = a.iter();
@@ -152,6 +209,7 @@ fn issue1654() {
 fn main() {
     base();
     refutable();
+    refutable2();
     nested_loops();
     issue1121();
     issue2965();
diff --git a/tests/ui/while_let_on_iterator.stderr b/tests/ui/while_let_on_iterator.stderr
index 6de138d7227b..aa980d9965c7 100644
--- a/tests/ui/while_let_on_iterator.stderr
+++ b/tests/ui/while_let_on_iterator.stderr
@@ -1,5 +1,5 @@
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:8:5
+  --> $DIR/while_let_on_iterator.rs:9:5
    |
 LL |     while let Option::Some(x) = iter.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
@@ -7,22 +7,40 @@ LL |     while let Option::Some(x) = iter.next() {
    = note: `-D clippy::while-let-on-iterator` implied by `-D warnings`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:13:5
+  --> $DIR/while_let_on_iterator.rs:14:5
    |
 LL |     while let Some(x) = iter.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:18:5
+  --> $DIR/while_let_on_iterator.rs:19:5
    |
 LL |     while let Some(_) = iter.next() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:97:9
+  --> $DIR/while_let_on_iterator.rs:102:9
+   |
+LL |         while let Some([..]) = it.next() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:109:9
+   |
+LL |         while let Some([_x]) = it.next() {}
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:122:9
+   |
+LL |         while let Some(x @ [_]) = it.next() {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:154:9
    |
 LL |         while let Some(_) = y.next() {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y`
 
-error: aborting due to 4 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/wildcard_imports.fixed b/tests/ui/wildcard_imports.fixed
index ed6cc00ef048..67423e6ec1d1 100644
--- a/tests/ui/wildcard_imports.fixed
+++ b/tests/ui/wildcard_imports.fixed
@@ -155,3 +155,76 @@ fn test_weird_formatting() {
     exported();
     foo();
 }
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::foofoo;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_futher_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::insidefoo;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use super_imports::foofoo;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::foofoo;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::foofoo;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/tests/ui/wildcard_imports.rs b/tests/ui/wildcard_imports.rs
index c6d6efaece81..3ad1a29aebad 100644
--- a/tests/ui/wildcard_imports.rs
+++ b/tests/ui/wildcard_imports.rs
@@ -156,3 +156,76 @@ fn test_weird_formatting() {
     exported();
     foo();
 }
+
+mod super_imports {
+    fn foofoo() {}
+
+    mod should_be_replaced {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass {
+        use super::*;
+
+        fn with_super() {
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_inside_function {
+        fn with_super_inside_function() {
+            use super::*;
+            let _ = foofoo();
+        }
+    }
+
+    mod test_should_pass_further_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod should_be_replaced_futher_inside {
+        fn insidefoo() {}
+        mod inner {
+            use super::*;
+            fn with_super() {
+                let _ = insidefoo();
+            }
+        }
+    }
+
+    mod use_explicit_should_be_replaced {
+        use super_imports::*;
+
+        fn with_explicit() {
+            let _ = foofoo();
+        }
+    }
+
+    mod use_double_super_should_be_replaced {
+        mod inner {
+            use super::super::*;
+
+            fn with_double_super() {
+                let _ = foofoo();
+            }
+        }
+    }
+
+    mod use_super_explicit_should_be_replaced {
+        use super::super::super_imports::*;
+
+        fn with_super_explicit() {
+            let _ = foofoo();
+        }
+    }
+}
diff --git a/tests/ui/wildcard_imports.stderr b/tests/ui/wildcard_imports.stderr
index 050e4c6304f0..fab43b738eb4 100644
--- a/tests/ui/wildcard_imports.stderr
+++ b/tests/ui/wildcard_imports.stderr
@@ -92,5 +92,35 @@ LL |       use crate:: fn_mod::
 LL | |         *;
    | |_________^ help: try: `crate:: fn_mod::foo`
 
-error: aborting due to 15 previous errors
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:164:13
+   |
+LL |         use super::*;
+   |             ^^^^^^^^ help: try: `super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:199:17
+   |
+LL |             use super::*;
+   |                 ^^^^^^^^ help: try: `super::insidefoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:207:13
+   |
+LL |         use super_imports::*;
+   |             ^^^^^^^^^^^^^^^^ help: try: `super_imports::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:216:17
+   |
+LL |             use super::super::*;
+   |                 ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
+
+error: usage of wildcard import
+  --> $DIR/wildcard_imports.rs:225:13
+   |
+LL |         use super::super::super_imports::*;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
+
+error: aborting due to 20 previous errors
 

From ff9a9ed37c5e0b41c083c92aa908b1277e97ef09 Mon Sep 17 00:00:00 2001
From: Julian Wollersberger
 <24991778+Julian-Wollersberger@users.noreply.github.com>
Date: Wed, 13 May 2020 10:03:49 +0200
Subject: [PATCH 6/9] Replace some usages of the old `unescape_` functions in
 AST, clippy and tests.

---
 clippy_lints/src/write.rs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index 5ad43ad55a36..26bf463bd292 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -483,8 +483,8 @@ fn check_newlines(fmtstr: &StrLit) -> bool {
     };
 
     match fmtstr.style {
-        StrStyle::Cooked => unescape::unescape_str(contents, &mut cb),
-        StrStyle::Raw(_) => unescape::unescape_raw_str(contents, &mut cb),
+        StrStyle::Cooked => unescape::unescape_literal(contents, unescape::Mode::Str, &mut cb),
+        StrStyle::Raw(_) => unescape::unescape_literal(contents, unescape::Mode::RawStr, &mut cb),
     }
 
     should_lint

From 0a86335cd428fe87f95af68aa402b08284c1123a Mon Sep 17 00:00:00 2001
From: csmoe <csmoe@msn.com>
Date: Thu, 14 May 2020 23:07:46 +0800
Subject: [PATCH 7/9] implement type_implments_trait query

---
 clippy_lints/src/utils/mod.rs | 18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)

diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index 2fd080e9ef0f..84a324f76c5b 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -40,15 +40,12 @@ use rustc_hir::{
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::map::Map;
-use rustc_middle::traits;
 use rustc_middle::ty::{self, layout::IntegerExt, subst::GenericArg, Binder, Ty, TyCtxt, TypeFoldable};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::symbol::{self, kw, Symbol};
 use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
 use rustc_target::abi::Integer;
-use rustc_trait_selection::traits::predicate_for_trait_def;
-use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use smallvec::SmallVec;
 
@@ -326,19 +323,8 @@ pub fn implements_trait<'a, 'tcx>(
     trait_id: DefId,
     ty_params: &[GenericArg<'tcx>],
 ) -> bool {
-    let ty = cx.tcx.erase_regions(&ty);
-    let obligation = predicate_for_trait_def(
-        cx.tcx,
-        cx.param_env,
-        traits::ObligationCause::dummy(),
-        trait_id,
-        0,
-        ty,
-        ty_params,
-    );
-    cx.tcx
-        .infer_ctxt()
-        .enter(|infcx| infcx.predicate_must_hold_modulo_regions(&obligation))
+    let ty_params = cx.tcx.mk_substs(ty_params.iter());
+    cx.tcx.type_implements_trait((trait_id, ty, ty_params, cx.param_env))
 }
 
 /// Gets the `hir::TraitRef` of the trait the given method is implemented for.

From 404ae5b211c9fb3960b64ecbf91d903d484b0c20 Mon Sep 17 00:00:00 2001
From: flip1995 <hello@philkrones.com>
Date: Sun, 17 May 2020 01:14:28 +0200
Subject: [PATCH 8/9] Re-remove util/dev

Maybe someday, git subtree will do it right
---
 util/dev | 7 -------
 1 file changed, 7 deletions(-)
 delete mode 100755 util/dev

diff --git a/util/dev b/util/dev
deleted file mode 100755
index 319de217e0d9..000000000000
--- a/util/dev
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/sh
-CARGO_TARGET_DIR=$(pwd)/target/
-export CARGO_TARGET_DIR
-
-echo 'Deprecated! `util/dev` usage is deprecated, please use `cargo dev` instead.'
-
-cd clippy_dev && cargo run -- "$@"

From 7f317b708fe0889c04b7590ba53f3a41afa44a1d Mon Sep 17 00:00:00 2001
From: flip1995 <hello@philkrones.com>
Date: Sun, 17 May 2020 01:18:43 +0200
Subject: [PATCH 9/9] Run fmt

---
 src/driver.rs | 222 +++++++++++++++++++++++++-------------------------
 1 file changed, 110 insertions(+), 112 deletions(-)

diff --git a/src/driver.rs b/src/driver.rs
index 1ce0300f2390..d3a7e24937f9 100644
--- a/src/driver.rs
+++ b/src/driver.rs
@@ -295,121 +295,119 @@ fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<Pat
 pub fn main() {
     rustc_driver::init_rustc_env_logger();
     lazy_static::initialize(&ICE_HOOK);
-    exit(
-        rustc_driver::catch_with_exit_code(move || {
-            let mut orig_args: Vec<String> = env::args().collect();
-
-            if orig_args.iter().any(|a| a == "--version" || a == "-V") {
-                let version_info = rustc_tools_util::get_version_info!();
-                println!("{}", version_info);
-                exit(0);
-            }
+    exit(rustc_driver::catch_with_exit_code(move || {
+        let mut orig_args: Vec<String> = env::args().collect();
 
-            // Get the sysroot, looking from most specific to this invocation to the least:
-            // - command line
-            // - runtime environment
-            //    - SYSROOT
-            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
-            // - sysroot from rustc in the path
-            // - compile-time environment
-            //    - SYSROOT
-            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
-            let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
-            let have_sys_root_arg = sys_root_arg.is_some();
-            let sys_root = sys_root_arg
-                .map(PathBuf::from)
-                .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
-                .or_else(|| {
-                    let home = std::env::var("RUSTUP_HOME")
-                        .or_else(|_| std::env::var("MULTIRUST_HOME"))
-                        .ok();
-                    let toolchain = std::env::var("RUSTUP_TOOLCHAIN")
-                        .or_else(|_| std::env::var("MULTIRUST_TOOLCHAIN"))
-                        .ok();
-                    toolchain_path(home, toolchain)
-                })
-                .or_else(|| {
-                    Command::new("rustc")
-                        .arg("--print")
-                        .arg("sysroot")
-                        .output()
-                        .ok()
-                        .and_then(|out| String::from_utf8(out.stdout).ok())
-                        .map(|s| PathBuf::from(s.trim()))
-                })
-                .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
-                .or_else(|| {
-                    let home = option_env!("RUSTUP_HOME")
-                        .or(option_env!("MULTIRUST_HOME"))
-                        .map(ToString::to_string);
-                    let toolchain = option_env!("RUSTUP_TOOLCHAIN")
-                        .or(option_env!("MULTIRUST_TOOLCHAIN"))
-                        .map(ToString::to_string);
-                    toolchain_path(home, toolchain)
-                })
-                .map(|pb| pb.to_string_lossy().to_string())
-                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
-
-            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
-            // We're invoking the compiler programmatically, so we ignore this/
-            let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());
-
-            if wrapper_mode {
-                // we still want to be able to invoke it normally though
-                orig_args.remove(1);
-            }
+        if orig_args.iter().any(|a| a == "--version" || a == "-V") {
+            let version_info = rustc_tools_util::get_version_info!();
+            println!("{}", version_info);
+            exit(0);
+        }
 
-            if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
-                display_help();
-                exit(0);
-            }
+        // Get the sysroot, looking from most specific to this invocation to the least:
+        // - command line
+        // - runtime environment
+        //    - SYSROOT
+        //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
+        // - sysroot from rustc in the path
+        // - compile-time environment
+        //    - SYSROOT
+        //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
+        let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
+        let have_sys_root_arg = sys_root_arg.is_some();
+        let sys_root = sys_root_arg
+            .map(PathBuf::from)
+            .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
+            .or_else(|| {
+                let home = std::env::var("RUSTUP_HOME")
+                    .or_else(|_| std::env::var("MULTIRUST_HOME"))
+                    .ok();
+                let toolchain = std::env::var("RUSTUP_TOOLCHAIN")
+                    .or_else(|_| std::env::var("MULTIRUST_TOOLCHAIN"))
+                    .ok();
+                toolchain_path(home, toolchain)
+            })
+            .or_else(|| {
+                Command::new("rustc")
+                    .arg("--print")
+                    .arg("sysroot")
+                    .output()
+                    .ok()
+                    .and_then(|out| String::from_utf8(out.stdout).ok())
+                    .map(|s| PathBuf::from(s.trim()))
+            })
+            .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
+            .or_else(|| {
+                let home = option_env!("RUSTUP_HOME")
+                    .or(option_env!("MULTIRUST_HOME"))
+                    .map(ToString::to_string);
+                let toolchain = option_env!("RUSTUP_TOOLCHAIN")
+                    .or(option_env!("MULTIRUST_TOOLCHAIN"))
+                    .map(ToString::to_string);
+                toolchain_path(home, toolchain)
+            })
+            .map(|pb| pb.to_string_lossy().to_string())
+            .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
 
-            let should_describe_lints = || {
-                let args: Vec<_> = env::args().collect();
-                args.windows(2).any(|args| {
-                    args[1] == "help"
-                        && match args[0].as_str() {
-                            "-W" | "-A" | "-D" | "-F" => true,
-                            _ => false,
-                        }
-                })
-            };
-
-            if !wrapper_mode && should_describe_lints() {
-                describe_lints();
-                exit(0);
-            }
+        // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
+        // We're invoking the compiler programmatically, so we ignore this/
+        let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());
+
+        if wrapper_mode {
+            // we still want to be able to invoke it normally though
+            orig_args.remove(1);
+        }
+
+        if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
+            display_help();
+            exit(0);
+        }
+
+        let should_describe_lints = || {
+            let args: Vec<_> = env::args().collect();
+            args.windows(2).any(|args| {
+                args[1] == "help"
+                    && match args[0].as_str() {
+                        "-W" | "-A" | "-D" | "-F" => true,
+                        _ => false,
+                    }
+            })
+        };
 
-            // this conditional check for the --sysroot flag is there so users can call
-            // `clippy_driver` directly
-            // without having to pass --sysroot or anything
-            let mut args: Vec<String> = orig_args.clone();
-            if !have_sys_root_arg {
-                args.extend(vec!["--sysroot".into(), sys_root]);
-            };
-
-            // this check ensures that dependencies are built but not linted and the final
-            // crate is linted but not built
-            let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true")
-                || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none();
-
-            if clippy_enabled {
-                args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]);
-                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
-                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
-                        if s.is_empty() {
-                            None
-                        } else {
-                            Some(s.to_string())
-                        }
-                    }));
-                }
+        if !wrapper_mode && should_describe_lints() {
+            describe_lints();
+            exit(0);
+        }
+
+        // this conditional check for the --sysroot flag is there so users can call
+        // `clippy_driver` directly
+        // without having to pass --sysroot or anything
+        let mut args: Vec<String> = orig_args.clone();
+        if !have_sys_root_arg {
+            args.extend(vec!["--sysroot".into(), sys_root]);
+        };
+
+        // this check ensures that dependencies are built but not linted and the final
+        // crate is linted but not built
+        let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true")
+            || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none();
+
+        if clippy_enabled {
+            args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]);
+            if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
+                args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
+                    if s.is_empty() {
+                        None
+                    } else {
+                        Some(s.to_string())
+                    }
+                }));
             }
-            let mut clippy = ClippyCallbacks;
-            let mut default = DefaultCallbacks;
-            let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
-                if clippy_enabled { &mut clippy } else { &mut default };
-            rustc_driver::run_compiler(&args, callbacks, None, None)
-        })
-    )
+        }
+        let mut clippy = ClippyCallbacks;
+        let mut default = DefaultCallbacks;
+        let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
+            if clippy_enabled { &mut clippy } else { &mut default };
+        rustc_driver::run_compiler(&args, callbacks, None, None)
+    }))
 }