about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md3
-rw-r--r--clippy_lints/src/declared_lints.rs3
-rw-r--r--clippy_lints/src/excessive_nesting.rs325
-rw-r--r--clippy_lints/src/excessive_width.rs82
-rw-r--r--clippy_lints/src/lib.rs14
-rw-r--r--clippy_lints/src/utils/conf.rs14
-rw-r--r--tests/ui-toml/excessive_nesting/auxiliary/macro_rules.rs7
-rw-r--r--tests/ui-toml/excessive_nesting/clippy.toml1
-rw-r--r--tests/ui-toml/excessive_nesting/excessive_nesting.rs191
-rw-r--r--tests/ui-toml/excessive_nesting/excessive_nesting.stderr358
-rw-r--r--tests/ui-toml/excessive_width/clippy.toml3
-rw-r--r--tests/ui-toml/excessive_width/excessive_width.rs26
-rw-r--r--tests/ui-toml/excessive_width/excessive_width.stderr24
-rw-r--r--tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr1
-rw-r--r--tests/ui/auxiliary/macro_rules.rs1
-rw-r--r--tests/ui/excessive_width.rs44
-rw-r--r--tests/ui/excessive_width.stderr11
17 files changed, 893 insertions, 215 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 76fd81a25c6..69ac2c893d9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4758,9 +4758,8 @@ Released 2018-09-13
 [`erasing_op`]: https://rust-lang.github.io/rust-clippy/master/index.html#erasing_op
 [`err_expect`]: https://rust-lang.github.io/rust-clippy/master/index.html#err_expect
 [`eval_order_dependence`]: https://rust-lang.github.io/rust-clippy/master/index.html#eval_order_dependence
-[`excessive_indentation`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_indentation
+[`excessive_nesting`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting
 [`excessive_precision`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_precision
-[`excessive_width`]: https://rust-lang.github.io/rust-clippy/master/index.html#excessive_width
 [`exhaustive_enums`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_enums
 [`exhaustive_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#exhaustive_structs
 [`exit`]: https://rust-lang.github.io/rust-clippy/master/index.html#exit
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 20911348690..0c51996b625 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -159,8 +159,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
     crate::excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS_INFO,
     crate::excessive_bools::STRUCT_EXCESSIVE_BOOLS_INFO,
-    crate::excessive_width::EXCESSIVE_INDENTATION_INFO,
-    crate::excessive_width::EXCESSIVE_WIDTH_INFO,
+    crate::excessive_nesting::EXCESSIVE_NESTING_INFO,
     crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
     crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
     crate::exit::EXIT_INFO,
diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs
new file mode 100644
index 00000000000..a60e2442fa2
--- /dev/null
+++ b/clippy_lints/src/excessive_nesting.rs
@@ -0,0 +1,325 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::{
+    node_id::NodeId,
+    ptr::P,
+    visit::{FnKind, Visitor},
+    Arm, AssocItemKind, Block, Expr, ExprKind, Inline, Item, ItemKind, Local, LocalKind, ModKind, ModSpans, Pat,
+    PatKind, Stmt, StmtKind,
+};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
+use thin_vec::ThinVec;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for blocks which are indented beyond a certain threshold.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// It can severely hinder readability. The default is very generous; if you
+    /// exceed this, it's a sign you should refactor.
+    ///
+    /// ### Known issues
+    ///
+    /// Nested inline modules will all be linted, rather than just the outermost one
+    /// that applies. This makes the output a bit verbose.
+    ///
+    /// ### Example
+    /// An example clippy.toml configuration:
+    /// ```toml
+    /// # clippy.toml
+    /// excessive-nesting-threshold = 3
+    /// ```
+    /// lib.rs:
+    /// ```rust,ignore
+    /// pub mod a {
+    ///     pub struct X;
+    ///     impl X {
+    ///         pub fn run(&self) {
+    ///             if true {
+    ///                 // etc...
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    /// Use instead:
+    /// a.rs:
+    /// ```rust,ignore
+    /// fn private_run(x: &X) {
+    ///     if true {
+    ///         // etc...
+    ///     }
+    /// }
+    ///
+    /// pub struct X;
+    /// impl X {
+    ///     pub fn run(&self) {
+    ///         private_run(self);
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub EXCESSIVE_NESTING,
+    restriction,
+    "checks for blocks nested beyond a certain threshold"
+}
+impl_lint_pass!(ExcessiveNesting => [EXCESSIVE_NESTING]);
+
+#[derive(Clone, Copy)]
+pub struct ExcessiveNesting {
+    pub excessive_nesting_threshold: u64,
+}
+
+impl EarlyLintPass for ExcessiveNesting {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        let conf = self;
+        NestingVisitor {
+            conf,
+            cx,
+            nest_level: 0,
+        }
+        .visit_item(item);
+    }
+}
+
+struct NestingVisitor<'conf, 'cx> {
+    conf: &'conf ExcessiveNesting,
+    cx: &'cx EarlyContext<'cx>,
+    nest_level: u64,
+}
+
+impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
+    fn visit_local(&mut self, local: &Local) {
+        self.visit_pat(&local.pat);
+
+        match &local.kind {
+            LocalKind::Init(expr) => self.visit_expr(expr),
+            LocalKind::InitElse(expr, block) => {
+                self.visit_expr(expr);
+                self.visit_block(block);
+            },
+            LocalKind::Decl => (),
+        }
+    }
+
+    fn visit_block(&mut self, block: &Block) {
+        self.nest_level += 1;
+
+        if !check_indent(self, block.span) {
+            for stmt in &block.stmts {
+                self.visit_stmt(stmt);
+            }
+        }
+
+        self.nest_level -= 1;
+    }
+
+    fn visit_stmt(&mut self, stmt: &Stmt) {
+        match &stmt.kind {
+            StmtKind::Local(local) => self.visit_local(local),
+            StmtKind::Item(item) => self.visit_item(item),
+            StmtKind::Expr(expr) | StmtKind::Semi(expr) => self.visit_expr(expr),
+            _ => (),
+        }
+    }
+
+    fn visit_arm(&mut self, arm: &Arm) {
+        self.visit_pat(&arm.pat);
+        if let Some(expr) = &arm.guard {
+            self.visit_expr(expr);
+        }
+        self.visit_expr(&arm.body);
+    }
+
+    // TODO: Is this necessary?
+    fn visit_pat(&mut self, pat: &Pat) {
+        match &pat.kind {
+            PatKind::Box(pat) | PatKind::Ref(pat, ..) | PatKind::Paren(pat) => self.visit_pat(pat),
+            PatKind::Lit(expr) => self.visit_expr(expr),
+            PatKind::Range(start, end, ..) => {
+                if let Some(expr) = start {
+                    self.visit_expr(expr);
+                }
+                if let Some(expr) = end {
+                    self.visit_expr(expr);
+                }
+            },
+            PatKind::Ident(.., pat) if let Some(pat) = pat => {
+                self.visit_pat(pat);
+            },
+            PatKind::Struct(.., pat_fields, _) => {
+                for pat_field in pat_fields {
+                    self.visit_pat(&pat_field.pat);
+                }
+            },
+            PatKind::TupleStruct(.., pats) | PatKind::Or(pats) | PatKind::Tuple(pats) | PatKind::Slice(pats) => {
+                for pat in pats {
+                    self.visit_pat(pat);
+                }
+            },
+            _ => (),
+        }
+    }
+
+    fn visit_expr(&mut self, expr: &Expr) {
+        // This is a mess, but really all it does is extract every expression from every applicable variant
+        // of ExprKind until it finds a Block.
+        match &expr.kind {
+            ExprKind::ConstBlock(anon_const) => self.visit_expr(&anon_const.value),
+            ExprKind::Call(.., args) => {
+                for expr in args {
+                    self.visit_expr(expr);
+                }
+            },
+            ExprKind::MethodCall(method_call) => {
+                for expr in &method_call.args {
+                    self.visit_expr(expr);
+                }
+            },
+            ExprKind::Tup(exprs) | ExprKind::Array(exprs) => {
+                for expr in exprs {
+                    self.visit_expr(expr);
+                }
+            },
+            ExprKind::Binary(.., left, right)
+            | ExprKind::Assign(left, right, ..)
+            | ExprKind::AssignOp(.., left, right)
+            | ExprKind::Index(left, right) => {
+                self.visit_expr(left);
+                self.visit_expr(right);
+            },
+            ExprKind::Let(pat, expr, ..) => {
+                self.visit_pat(pat);
+                self.visit_expr(expr);
+            },
+            ExprKind::Unary(.., expr)
+            | ExprKind::Await(expr)
+            | ExprKind::Field(expr, ..)
+            | ExprKind::AddrOf(.., expr)
+            | ExprKind::Try(expr) => {
+                self.visit_expr(expr);
+            },
+            ExprKind::Repeat(expr, anon_const) => {
+                self.visit_expr(expr);
+                self.visit_expr(&anon_const.value);
+            },
+            ExprKind::If(expr, block, else_expr) => {
+                self.visit_expr(expr);
+                self.visit_block(block);
+
+                if let Some(expr) = else_expr {
+                    self.visit_expr(expr);
+                }
+            },
+            ExprKind::While(expr, block, ..) => {
+                self.visit_expr(expr);
+                self.visit_block(block);
+            },
+            ExprKind::ForLoop(pat, expr, block, ..) => {
+                self.visit_pat(pat);
+                self.visit_expr(expr);
+                self.visit_block(block);
+            },
+            ExprKind::Loop(block, ..)
+            | ExprKind::Block(block, ..)
+            | ExprKind::Async(.., block)
+            | ExprKind::TryBlock(block) => {
+                self.visit_block(block);
+            },
+            ExprKind::Match(expr, arms) => {
+                self.visit_expr(expr);
+
+                for arm in arms {
+                    self.visit_arm(arm);
+                }
+            },
+            ExprKind::Closure(closure) => self.visit_expr(&closure.body),
+            ExprKind::Range(start, end, ..) => {
+                if let Some(expr) = start {
+                    self.visit_expr(expr);
+                }
+                if let Some(expr) = end {
+                    self.visit_expr(expr);
+                }
+            },
+            ExprKind::Break(.., expr) | ExprKind::Ret(expr) | ExprKind::Yield(expr) | ExprKind::Yeet(expr) => {
+                if let Some(expr) = expr {
+                    self.visit_expr(expr);
+                }
+            },
+            ExprKind::Struct(struct_expr) => {
+                for field in &struct_expr.fields {
+                    self.visit_expr(&field.expr);
+                }
+            },
+            _ => (),
+        }
+    }
+
+    fn visit_fn(&mut self, fk: FnKind<'_>, _: Span, _: NodeId) {
+        match fk {
+            FnKind::Fn(.., block) if let Some(block) = block => self.visit_block(block),
+            FnKind::Closure(.., expr) => self.visit_expr(expr),
+            // :/
+            FnKind::Fn(..) => (),
+        }
+    }
+
+    fn visit_item(&mut self, item: &Item) {
+        match &item.kind {
+            ItemKind::Static(static_item) if let Some(expr) = static_item.expr.as_ref() => self.visit_expr(expr),
+            ItemKind::Const(const_item) if let Some(expr) = const_item.expr.as_ref() => self.visit_expr(expr),
+            ItemKind::Fn(fk) if let Some(block) = fk.body.as_ref() => self.visit_block(block),
+            ItemKind::Mod(.., mod_kind)
+                if let ModKind::Loaded(items, Inline::Yes, ModSpans { inner_span, ..}) = mod_kind =>
+            {
+                self.nest_level += 1;
+
+                check_indent(self, *inner_span);
+
+                self.nest_level -= 1;
+            }
+            ItemKind::Trait(trit) => check_trait_and_impl(self, item, &trit.items),
+            ItemKind::Impl(imp) => check_trait_and_impl(self, item, &imp.items),
+            _ => (),
+        }
+    }
+}
+
+fn check_trait_and_impl(visitor: &mut NestingVisitor<'_, '_>, item: &Item, items: &ThinVec<P<Item<AssocItemKind>>>) {
+    visitor.nest_level += 1;
+
+    if !check_indent(visitor, item.span) {
+        for item in items {
+            match &item.kind {
+                AssocItemKind::Const(const_item) if let Some(expr) = const_item.expr.as_ref() => {
+                    visitor.visit_expr(expr);
+                },
+                AssocItemKind::Fn(fk) if let Some(block) = fk.body.as_ref() => visitor.visit_block(block),
+                _ => (),
+            }
+        }
+    }
+
+    visitor.nest_level -= 1;
+}
+
+fn check_indent(visitor: &NestingVisitor<'_, '_>, span: Span) -> bool {
+    if visitor.nest_level > visitor.conf.excessive_nesting_threshold && !in_external_macro(visitor.cx.sess(), span) {
+        span_lint_and_help(
+            visitor.cx,
+            EXCESSIVE_NESTING,
+            span,
+            "this block is too nested",
+            None,
+            "try refactoring your code, extraction is often both easier to read and less nested",
+        );
+
+        return true;
+    }
+
+    false
+}
diff --git a/clippy_lints/src/excessive_width.rs b/clippy_lints/src/excessive_width.rs
deleted file mode 100644
index 0e23b39a14e..00000000000
--- a/clippy_lints/src/excessive_width.rs
+++ /dev/null
@@ -1,82 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::*;
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Pos;
-
-// TODO: This still needs to be implemented.
-declare_clippy_lint! {
-    /// ### What it does
-    ///
-    /// Checks for lines which are indented beyond a certain threshold.
-    ///
-    /// ### Why is this bad?
-    ///
-    /// It can severely hinder readability. The default is very generous; if you
-    /// exceed this, it's a sign you should refactor.
-    ///
-    /// ### Example
-    /// TODO
-    /// Use instead:
-    /// TODO
-    #[clippy::version = "1.70.0"]
-    pub EXCESSIVE_INDENTATION,
-    nursery,
-    "check for lines intended beyond a certain threshold"
-}
-declare_clippy_lint! {
-    /// ### What it does
-    ///
-    /// Checks for lines which are longer than a certain threshold.
-    ///
-    /// ### Why is this bad?
-    ///
-    /// It can severely hinder readability. Almost always, running rustfmt will get this
-    /// below this threshold (or whatever you have set as max_width), but if it fails,
-    /// it's probably a sign you should refactor.
-    ///
-    /// ### Example
-    /// TODO
-    /// Use instead:
-    /// TODO
-    #[clippy::version = "1.70.0"]
-    pub EXCESSIVE_WIDTH,
-    nursery,
-    "check for lines longer than a certain threshold"
-}
-impl_lint_pass!(ExcessiveWidth => [EXCESSIVE_INDENTATION, EXCESSIVE_WIDTH]);
-
-#[derive(Clone, Copy)]
-pub struct ExcessiveWidth {
-    pub excessive_width_threshold: u64,
-    pub excessive_width_ignore_indentation: bool,
-    pub excessive_indentation_threshold: u64,
-}
-
-impl LateLintPass<'_> for ExcessiveWidth {
-    fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
-        if in_external_macro(cx.sess(), stmt.span) {
-            return;
-        }
-
-        if let Ok(lines) = cx.sess().source_map().span_to_lines(stmt.span).map(|info| info.lines) {
-            for line in &lines {
-                // TODO: yeah, no.
-                if (line.end_col.to_usize()
-                    - line.start_col.to_usize() * self.excessive_width_ignore_indentation as usize)
-                    > self.excessive_width_threshold as usize
-                {
-                    span_lint_and_help(
-                        cx,
-                        EXCESSIVE_WIDTH,
-                        stmt.span,
-                        "this line is too long",
-                        None,
-                        "consider running rustfmt or refactoring this",
-                    );
-                }
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 8b08861bc1d..202b4709ad4 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -122,7 +122,7 @@ mod equatable_if_let;
 mod escape;
 mod eta_reduction;
 mod excessive_bools;
-mod excessive_width;
+mod excessive_nesting;
 mod exhaustive_items;
 mod exit;
 mod explicit_write;
@@ -1008,14 +1008,10 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
     store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
-    let excessive_width_threshold = conf.excessive_width_threshold;
-    let excessive_width_ignore_indentation = conf.excessive_width_ignore_indentation;
-    let excessive_indentation_threshold = conf.excessive_indentation_threshold;
-    store.register_late_pass(move |_| {
-        Box::new(excessive_width::ExcessiveWidth {
-            excessive_width_threshold,
-            excessive_width_ignore_indentation,
-            excessive_indentation_threshold,
+    let excessive_nesting_threshold = conf.excessive_nesting_threshold;
+    store.register_early_pass(move || {
+        Box::new(excessive_nesting::ExcessiveNesting {
+            excessive_nesting_threshold,
         })
     });
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 1bdb5e42418..cf0da266dc9 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -305,18 +305,10 @@ define_Conf! {
     ///
     /// The maximum cognitive complexity a function can have
     (cognitive_complexity_threshold: u64 = 25),
-    /// Lint: EXCESSIVE_WIDTH.
+    /// Lint: EXCESSIVE_NESTING.
     ///
-    /// The maximum width a statement can have
-    (excessive_width_threshold: u64 = 100),
-    /// Lint: EXCESSIVE_WIDTH.
-    ///
-    /// Whether to ignore the line's indentation
-    (excessive_width_ignore_indentation: bool = true),
-    /// Lint: EXCESSIVE_INDENTATION.
-    ///
-    /// The maximum indentation a statement can have
-    (excessive_indentation_threshold: u64 = 10),
+    /// The maximum amount of nesting a block can reside in
+    (excessive_nesting_threshold: u64 = 10),
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
     ///
     /// Use the Cognitive Complexity lint instead.
diff --git a/tests/ui-toml/excessive_nesting/auxiliary/macro_rules.rs b/tests/ui-toml/excessive_nesting/auxiliary/macro_rules.rs
new file mode 100644
index 00000000000..86663db68f2
--- /dev/null
+++ b/tests/ui-toml/excessive_nesting/auxiliary/macro_rules.rs
@@ -0,0 +1,7 @@
+#[rustfmt::skip]
+#[macro_export]
+macro_rules! excessive_nesting {
+    () => {{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{
+        println!("hi!!")
+    }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}
+}
diff --git a/tests/ui-toml/excessive_nesting/clippy.toml b/tests/ui-toml/excessive_nesting/clippy.toml
new file mode 100644
index 00000000000..10be2751a86
--- /dev/null
+++ b/tests/ui-toml/excessive_nesting/clippy.toml
@@ -0,0 +1 @@
+excessive-nesting-threshold = 3
diff --git a/tests/ui-toml/excessive_nesting/excessive_nesting.rs b/tests/ui-toml/excessive_nesting/excessive_nesting.rs
new file mode 100644
index 00000000000..66fc8166314
--- /dev/null
+++ b/tests/ui-toml/excessive_nesting/excessive_nesting.rs
@@ -0,0 +1,191 @@
+//@aux-build:macro_rules.rs
+#![rustfmt::skip]
+#![feature(custom_inner_attributes)]
+#![allow(unused)]
+#![allow(clippy::let_and_return)]
+#![allow(clippy::redundant_closure_call)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(clippy::never_loop)]
+#![warn(clippy::excessive_nesting)]
+#![allow(clippy::collapsible_if)]
+
+#[macro_use]
+extern crate macro_rules;
+
+static X: u32 = {
+    let x = {
+        let y = {
+            let z = {
+                let w = { 3 };
+                w
+            };
+            z
+        };
+        y
+    };
+    x
+};
+
+macro_rules! xx {
+    () => {{
+        {
+            {
+                {
+                    {
+                        {
+                            {
+                                {
+                                    {
+                                        {
+                                            {
+                                                println!("ehe");
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }};
+}
+
+struct A;
+
+impl A {
+    pub fn a(&self, v: u32) {
+        struct B;
+
+        impl B {
+            pub fn b() {
+                struct C;
+
+                impl C {
+                    pub fn c() {}
+                }
+            }
+        }
+    }
+}
+
+struct D { d: u32 }
+
+trait Lol {
+    fn lmao() {
+        fn bb() {
+            fn cc() {
+                let x = { 1 }; // not a warning
+            }
+
+            let x = { 1 }; // warning
+        }
+    }
+}
+
+use a::{b::{c::{d::{e::{f::{}}}}}}; // should not lint
+
+pub mod a {
+    pub mod b {
+        pub mod c {
+            pub mod d {
+                pub mod e {
+                    pub mod f {}
+                }
+            }
+        }
+    }
+}
+
+fn a_but_not(v: u32) {}
+
+fn main() {
+    let a = A;
+
+    a_but_not({{{{{{{{0}}}}}}}});
+    a.a({{{{{{{{{0}}}}}}}}});
+    (0, {{{{{{{1}}}}}}});
+
+    if true {
+        if true {
+            if true {
+                if true {
+                    if true {
+
+                    }
+                }
+            }
+        }
+    }
+
+    let y = (|| {
+        let x = (|| {
+            let y = (|| {
+                let z = (|| {
+                    let w = { 3 };
+                    w
+                })();
+                z
+            })();
+            y
+        })();
+        x
+    })();
+
+    excessive_nesting!(); // ensure this isn't linted in external macros
+    xx!();
+    let boo = true;
+    !{boo as u32 + !{boo as u32 + !{boo as u32}}};
+
+    let mut y = 1;
+    y += {{{{{5}}}}};
+    let z = y + {{{{{{{{{5}}}}}}}}};
+    [0, {{{{{{{{{{0}}}}}}}}}}];
+    let mut xx = [0; {{{{{{{{100}}}}}}}}];
+    xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
+    &mut {{{{{{{{{{y}}}}}}}}}};
+
+    for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
+
+    while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
+    
+    while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
+
+    let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
+
+    {{{{1;}}}}..{{{{{{3}}}}}};
+    {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
+    ..{{{{{{{5}}}}}}};
+    ..={{{{{3}}}}};
+    {{{{{1;}}}}}..;
+
+    loop { break {{{{1}}}} };
+    loop {{{{{{}}}}}}
+
+    match {{{{{{true}}}}}} {
+        true => {{{{}}}},
+        false => {{{{}}}},
+    }
+
+    {
+        {
+            {
+                {
+                    println!("warning! :)");
+                }
+            }
+        }
+    }
+}
+
+async fn b() -> u32 {
+    async fn c() -> u32 {{{{{{{0}}}}}}}
+
+    c().await
+}
+
+async fn a() {
+    {{{{b().await}}}};
+}
diff --git a/tests/ui-toml/excessive_nesting/excessive_nesting.stderr b/tests/ui-toml/excessive_nesting/excessive_nesting.stderr
new file mode 100644
index 00000000000..0bd43da21e2
--- /dev/null
+++ b/tests/ui-toml/excessive_nesting/excessive_nesting.stderr
@@ -0,0 +1,358 @@
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:19:21
+   |
+LL |               let z = {
+   |  _____________________^
+LL | |                 let w = { 3 };
+LL | |                 w
+LL | |             };
+   | |_____________^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+   = note: `-D clippy::excessive-nesting` implied by `-D warnings`
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:63:24
+   |
+LL |               pub fn b() {
+   |  ________________________^
+LL | |                 struct C;
+LL | |
+LL | |                 impl C {
+LL | |                     pub fn c() {}
+LL | |                 }
+LL | |             }
+   | |_____________^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:67:32
+   |
+LL |                     pub fn c() {}
+   |                                ^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:79:21
+   |
+LL |               fn cc() {
+   |  _____________________^
+LL | |                 let x = { 1 }; // not a warning
+LL | |             }
+   | |_____________^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:83:21
+   |
+LL |             let x = { 1 }; // warning
+   |                     ^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:107:17
+   |
+LL |     a_but_not({{{{{{{{0}}}}}}}});
+   |                 ^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:108:11
+   |
+LL |     a.a({{{{{{{{{0}}}}}}}}});
+   |           ^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:109:11
+   |
+LL |     (0, {{{{{{{1}}}}}}});
+   |           ^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:113:21
+   |
+LL |               if true {
+   |  _____________________^
+LL | |                 if true {
+LL | |                     if true {
+LL | |
+LL | |                     }
+LL | |                 }
+LL | |             }
+   | |_____________^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:33:13
+   |
+LL | /             {
+LL | |                 {
+LL | |                     {
+LL | |                         {
+...  |
+LL | |                 }
+LL | |             }
+   | |_____________^
+...
+LL |       xx!();
+   |       ----- in this macro invocation
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+   = note: this error originates in the macro `xx` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:140:36
+   |
+LL |     !{boo as u32 + !{boo as u32 + !{boo as u32}}};
+   |                                    ^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:143:12
+   |
+LL |     y += {{{{{5}}}}};
+   |            ^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:144:19
+   |
+LL |     let z = y + {{{{{{{{{5}}}}}}}}};
+   |                   ^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:145:11
+   |
+LL |     [0, {{{{{{{{{{0}}}}}}}}}}];
+   |           ^^^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:146:24
+   |
+LL |     let mut xx = [0; {{{{{{{{100}}}}}}}}];
+   |                        ^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:147:10
+   |
+LL |     xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:148:12
+   |
+LL |     &mut {{{{{{{{{{y}}}}}}}}}};
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:150:16
+   |
+LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
+   |                ^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:150:27
+   |
+LL |     for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
+   |                           ^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:152:27
+   |
+LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
+   |                           ^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:152:47
+   |
+LL |     while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
+   |                                               ^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:154:13
+   |
+LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:154:34
+   |
+LL |     while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
+   |                                  ^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:156:22
+   |
+LL |     let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:158:7
+   |
+LL |     {{{{1;}}}}..{{{{{{3}}}}}};
+   |       ^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:158:19
+   |
+LL |     {{{{1;}}}}..{{{{{{3}}}}}};
+   |                   ^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:159:7
+   |
+LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
+   |       ^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:159:20
+   |
+LL |     {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:160:9
+   |
+LL |     ..{{{{{{{5}}}}}}};
+   |         ^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:161:10
+   |
+LL |     ..={{{{{3}}}}};
+   |          ^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:162:7
+   |
+LL |     {{{{{1;}}}}}..;
+   |       ^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:164:19
+   |
+LL |     loop { break {{{{1}}}} };
+   |                   ^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:165:12
+   |
+LL |     loop {{{{{{}}}}}}
+   |            ^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:167:13
+   |
+LL |     match {{{{{{true}}}}}} {
+   |             ^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:168:19
+   |
+LL |         true => {{{{}}}},
+   |                   ^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:169:20
+   |
+LL |         false => {{{{}}}},
+   |                    ^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:174:13
+   |
+LL | /             {
+LL | |                 {
+LL | |                     println!("warning! :)");
+LL | |                 }
+LL | |             }
+   | |_____________^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:184:27
+   |
+LL |     async fn c() -> u32 {{{{{{{0}}}}}}}
+   |                           ^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:184:28
+   |
+LL |     async fn c() -> u32 {{{{{{{0}}}}}}}
+   |                            ^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: this block is too nested
+  --> $DIR/excessive_nesting.rs:190:7
+   |
+LL |     {{{{b().await}}}};
+   |       ^^^^^^^^^^^^^
+   |
+   = help: try refactoring your code, extraction is often both easier to read and less nested
+
+error: aborting due to 40 previous errors
+
diff --git a/tests/ui-toml/excessive_width/clippy.toml b/tests/ui-toml/excessive_width/clippy.toml
deleted file mode 100644
index 1824c8a3127..00000000000
--- a/tests/ui-toml/excessive_width/clippy.toml
+++ /dev/null
@@ -1,3 +0,0 @@
-excessive-width-threshold = 20
-excessive-width-ignore-indentation = false
-excessive-indentation-threshold = 3
diff --git a/tests/ui-toml/excessive_width/excessive_width.rs b/tests/ui-toml/excessive_width/excessive_width.rs
deleted file mode 100644
index 261b937e72e..00000000000
--- a/tests/ui-toml/excessive_width/excessive_width.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-#![allow(unused)]
-#![allow(clippy::identity_op)]
-#![allow(clippy::no_effect)]
-#![warn(clippy::excessive_width)]
-
-static mut C: u32 = 2u32;
-
-#[rustfmt::skip]
-fn main() {
-    let x = 2 * unsafe { C };
-
-    {
-        {
-            // this too, even though it's only 15 characters!
-            ();
-        }
-    }
-
-    {
-        {
-            {
-                println!("this will now emit a warning, how neat!")
-            }
-        }
-    }
-}
diff --git a/tests/ui-toml/excessive_width/excessive_width.stderr b/tests/ui-toml/excessive_width/excessive_width.stderr
deleted file mode 100644
index 00dce391be0..00000000000
--- a/tests/ui-toml/excessive_width/excessive_width.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-error: this line is too long
-  --> $DIR/excessive_width.rs:10:5
-   |
-LL |     let x = 2 * unsafe { C };
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider running rustfmt or refactoring this
-   = note: `-D clippy::excessive-width` implied by `-D warnings`
-
-error: this line is too long
-  --> $DIR/excessive_width.rs:12:5
-   |
-LL | /     {
-LL | |         {
-LL | |             // this too, even though it's only 15 characters!
-LL | |             ();
-LL | |         }
-LL | |     }
-   | |_____^
-   |
-   = help: consider running rustfmt or refactoring this
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index b6038f031f3..28b6e7aa824 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -24,6 +24,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            enforced-import-renames
            enum-variant-name-threshold
            enum-variant-size-threshold
+           excessive-nesting-threshold
            future-size-threshold
            ignore-interior-mutability
            large-error-threshold
diff --git a/tests/ui/auxiliary/macro_rules.rs b/tests/ui/auxiliary/macro_rules.rs
index e5bb906663c..d9a1e76c077 100644
--- a/tests/ui/auxiliary/macro_rules.rs
+++ b/tests/ui/auxiliary/macro_rules.rs
@@ -1,7 +1,6 @@
 #![allow(dead_code)]
 
 //! Used to test that certain lints don't trigger in imported external macros
-
 #[macro_export]
 macro_rules! try_err {
     () => {
diff --git a/tests/ui/excessive_width.rs b/tests/ui/excessive_width.rs
deleted file mode 100644
index 218950f9684..00000000000
--- a/tests/ui/excessive_width.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-#![allow(unused)]
-#![allow(clippy::identity_op)]
-#![warn(clippy::excessive_width)]
-
-#[rustfmt::skip]
-fn main() {
-    let x = 1;
-
-    let really_long_binding_name_because_this_needs_to_be_over_90_characters_long = 1usize * 200 / 2 * 500 / 1;
-
-    {
-        {
-            {
-                {
-                    {
-                        {
-                            {
-                                {
-                                    {
-                                        {
-                                            {
-                                                {
-                                                    {
-                                                        {
-                                                            {
-                                                                {
-                                                                    println!("highly indented lines do not cause a warning (by default)!")
-                                                                }
-                                                            }
-                                                        }
-                                                    }
-                                                }
-                                            }
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/tests/ui/excessive_width.stderr b/tests/ui/excessive_width.stderr
deleted file mode 100644
index 707a3796b56..00000000000
--- a/tests/ui/excessive_width.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: this line is too long
-  --> $DIR/excessive_width.rs:9:5
-   |
-LL |     let really_long_binding_name_because_this_needs_to_be_over_90_characters_long = 1usize * 200 / 2 * 500 / 1;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider running rustfmt or refactoring this
-   = note: `-D clippy::excessive-width` implied by `-D warnings`
-
-error: aborting due to previous error
-