Auto merge of #10672 - Centri3:excessive-width-lints, r=Alexendoo

Add `excessive_nesting` lint

changelog: new lint [`excessive_nesting`]
This commit is contained in:
bors 2023-06-09 20:47:06 +00:00
commit 476efe92e7
12 changed files with 1193 additions and 1 deletions

View File

@ -4759,6 +4759,7 @@ 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_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
[`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

View File

@ -158,6 +158,16 @@ The maximum cognitive complexity a function can have
* [`cognitive_complexity`](https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity)
## `excessive-nesting-threshold`
The maximum amount of nesting a block can reside in
**Default Value:** `0` (`u64`)
---
**Affected lints:**
* [`excessive_nesting`](https://rust-lang.github.io/rust-clippy/master/index.html#excessive_nesting)
## `disallowed-names`
The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
`".."` can be used as part of the list to indicate, that the configured values should be appended to the

View File

@ -160,6 +160,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_nesting::EXCESSIVE_NESTING_INFO,
crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
crate::exit::EXIT_INFO,

View File

@ -0,0 +1,180 @@
use clippy_utils::{diagnostics::span_lint_and_help, source::snippet};
use rustc_ast::{
node_id::NodeSet,
visit::{walk_block, walk_item, Visitor},
Block, Crate, Inline, Item, ItemKind, ModKind, NodeId,
};
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;
declare_clippy_lint! {
/// ### What it does
/// Checks for blocks which are nested beyond a certain threshold.
///
/// Note: Even though this lint is warn-by-default, it will only trigger if a maximum nesting level is defined in the clippy.toml file.
///
/// ### Why is this bad?
/// It can severely hinder readability.
///
/// ### 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);
/// }
/// }
/// ```
/// lib.rs:
/// ```rust,ignore
/// pub mod a;
/// ```
#[clippy::version = "1.70.0"]
pub EXCESSIVE_NESTING,
complexity,
"checks for blocks nested beyond a certain threshold"
}
impl_lint_pass!(ExcessiveNesting => [EXCESSIVE_NESTING]);
#[derive(Clone)]
pub struct ExcessiveNesting {
pub excessive_nesting_threshold: u64,
pub nodes: NodeSet,
}
impl ExcessiveNesting {
pub fn check_node_id(&self, cx: &EarlyContext<'_>, span: Span, node_id: NodeId) {
if self.nodes.contains(&node_id) {
span_lint_and_help(
cx,
EXCESSIVE_NESTING,
span,
"this block is too nested",
None,
"try refactoring your code to minimize nesting",
);
}
}
}
impl EarlyLintPass for ExcessiveNesting {
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
if self.excessive_nesting_threshold == 0 {
return;
}
let mut visitor = NestingVisitor {
conf: self,
cx,
nest_level: 0,
};
for item in &krate.items {
visitor.visit_item(item);
}
}
fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
self.check_node_id(cx, block.span, block.id);
}
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
self.check_node_id(cx, item.span, item.id);
}
}
struct NestingVisitor<'conf, 'cx> {
conf: &'conf mut ExcessiveNesting,
cx: &'cx EarlyContext<'cx>,
nest_level: u64,
}
impl NestingVisitor<'_, '_> {
fn check_indent(&mut self, span: Span, id: NodeId) -> bool {
if self.nest_level > self.conf.excessive_nesting_threshold && !in_external_macro(self.cx.sess(), span) {
self.conf.nodes.insert(id);
return true;
}
false
}
}
impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
fn visit_block(&mut self, block: &Block) {
if block.span.from_expansion() {
return;
}
// TODO: This should be rewritten using `LateLintPass` so we can use `is_from_proc_macro` instead,
// but for now, this is fine.
let snippet = snippet(self.cx, block.span, "{}").trim().to_owned();
if !snippet.starts_with('{') || !snippet.ends_with('}') {
return;
}
self.nest_level += 1;
if !self.check_indent(block.span, block.id) {
walk_block(self, block);
}
self.nest_level -= 1;
}
fn visit_item(&mut self, item: &Item) {
if item.span.from_expansion() {
return;
}
match &item.kind {
ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => {
self.nest_level += 1;
if !self.check_indent(item.span, item.id) {
walk_item(self, item);
}
self.nest_level -= 1;
},
// Reset nesting level for non-inline modules (since these are in another file)
ItemKind::Mod(..) => walk_item(
&mut NestingVisitor {
conf: self.conf,
cx: self.cx,
nest_level: 0,
},
item,
),
_ => walk_item(self, item),
}
}
}

View File

@ -123,6 +123,7 @@ mod equatable_if_let;
mod escape;
mod eta_reduction;
mod excessive_bools;
mod excessive_nesting;
mod exhaustive_items;
mod exit;
mod explicit_write;
@ -1013,6 +1014,13 @@ 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_nesting_threshold = conf.excessive_nesting_threshold;
store.register_early_pass(move || {
Box::new(excessive_nesting::ExcessiveNesting {
excessive_nesting_threshold,
nodes: rustc_ast::node_id::NodeSet::new(),
})
});
store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));

View File

@ -305,6 +305,10 @@ define_Conf! {
///
/// The maximum cognitive complexity a function can have
(cognitive_complexity_threshold: u64 = 25),
/// Lint: EXCESSIVE_NESTING.
///
/// The maximum amount of nesting a block can reside in
(excessive_nesting_threshold: u64 = 0),
/// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
///
/// Use the Cognitive Complexity lint instead.

View File

@ -0,0 +1,476 @@
//@compile-flags: --emit=link
//@no-prefer-dynamic
// NOTE: Copied from `ui/auxiliary/proc_macros.rs`, couldn't get `../` to work for some reason
#![crate_type = "proc-macro"]
#![feature(let_chains)]
#![feature(proc_macro_span)]
#![allow(clippy::excessive_nesting, dead_code)]
extern crate proc_macro;
use core::mem;
use proc_macro::{
token_stream::IntoIter,
Delimiter::{self, Brace, Parenthesis},
Group, Ident, Literal, Punct,
Spacing::{self, Alone, Joint},
Span, TokenStream, TokenTree as TT,
};
type Result<T> = core::result::Result<T, TokenStream>;
/// Make a `compile_error!` pointing to the given span.
fn make_error(msg: &str, span: Span) -> TokenStream {
TokenStream::from_iter([
TT::Ident(Ident::new("compile_error", span)),
TT::Punct(punct_with_span('!', Alone, span)),
TT::Group({
let mut msg = Literal::string(msg);
msg.set_span(span);
group_with_span(Parenthesis, TokenStream::from_iter([TT::Literal(msg)]), span)
}),
])
}
fn expect_tt<T>(tt: Option<TT>, f: impl FnOnce(TT) -> Option<T>, expected: &str, span: Span) -> Result<T> {
match tt {
None => Err(make_error(
&format!("unexpected end of input, expected {expected}"),
span,
)),
Some(tt) => {
let span = tt.span();
match f(tt) {
Some(x) => Ok(x),
None => Err(make_error(&format!("unexpected token, expected {expected}"), span)),
}
},
}
}
fn punct_with_span(c: char, spacing: Spacing, span: Span) -> Punct {
let mut p = Punct::new(c, spacing);
p.set_span(span);
p
}
fn group_with_span(delimiter: Delimiter, stream: TokenStream, span: Span) -> Group {
let mut g = Group::new(delimiter, stream);
g.set_span(span);
g
}
/// Token used to escape the following token from the macro's span rules.
const ESCAPE_CHAR: char = '$';
/// Takes a single token followed by a sequence of tokens. Returns the sequence of tokens with their
/// span set to that of the first token. Tokens may be escaped with either `#ident` or `#(tokens)`.
#[proc_macro]
pub fn with_span(input: TokenStream) -> TokenStream {
let mut iter = input.into_iter();
let span = iter.next().unwrap().span();
let mut res = TokenStream::new();
if let Err(e) = write_with_span(span, iter, &mut res) {
e
} else {
res
}
}
/// Takes a sequence of tokens and return the tokens with the span set such that they appear to be
/// from an external macro. Tokens may be escaped with either `#ident` or `#(tokens)`.
#[proc_macro]
pub fn external(input: TokenStream) -> TokenStream {
let mut res = TokenStream::new();
if let Err(e) = write_with_span(Span::mixed_site(), input.into_iter(), &mut res) {
e
} else {
res
}
}
/// Copies all the tokens, replacing all their spans with the given span. Tokens can be escaped
/// either by `#ident` or `#(tokens)`.
fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Result<()> {
while let Some(tt) = input.next() {
match tt {
TT::Punct(p) if p.as_char() == ESCAPE_CHAR => {
expect_tt(
input.next(),
|tt| match tt {
tt @ (TT::Ident(_) | TT::Literal(_)) => {
out.extend([tt]);
Some(())
},
TT::Punct(mut p) if p.as_char() == ESCAPE_CHAR => {
p.set_span(s);
out.extend([TT::Punct(p)]);
Some(())
},
TT::Group(g) if g.delimiter() == Parenthesis => {
out.extend([TT::Group(group_with_span(Delimiter::None, g.stream(), g.span()))]);
Some(())
},
_ => None,
},
"an ident, a literal, or parenthesized tokens",
p.span(),
)?;
},
TT::Group(g) => {
let mut stream = TokenStream::new();
write_with_span(s, g.stream().into_iter(), &mut stream)?;
out.extend([TT::Group(group_with_span(g.delimiter(), stream, s))]);
},
mut tt => {
tt.set_span(s);
out.extend([tt]);
},
}
}
Ok(())
}
/// Within the item this attribute is attached to, an `inline!` macro is available which expands the
/// contained tokens as though they came from a macro expansion.
///
/// Within the `inline!` macro, any token preceded by `$` is passed as though it were an argument
/// with an automatically chosen fragment specifier. `$ident` will be passed as `ident`, `$1` or
/// `$"literal"` will be passed as `literal`, `$'lt` will be passed as `lifetime`, and `$(...)` will
/// pass the contained tokens as a `tt` sequence (the wrapping parenthesis are removed). If another
/// specifier is required it can be specified within parenthesis like `$(@expr ...)`. This will
/// expand the remaining tokens as a single argument.
///
/// Multiple `inline!` macros may be nested within each other. This will expand as nested macro
/// calls. However, any arguments will be passed as though they came from the outermost context.
#[proc_macro_attribute]
pub fn inline_macros(args: TokenStream, input: TokenStream) -> TokenStream {
let mut args = args.into_iter();
let mac_name = match args.next() {
Some(TT::Ident(name)) => Some(name),
Some(tt) => {
return make_error(
"unexpected argument, expected either an ident or no arguments",
tt.span(),
);
},
None => None,
};
if let Some(tt) = args.next() {
return make_error(
"unexpected argument, expected either an ident or no arguments",
tt.span(),
);
};
let mac_name = if let Some(mac_name) = mac_name {
Ident::new(&format!("__inline_mac_{mac_name}"), Span::call_site())
} else {
let mut input = match LookaheadIter::new(input.clone().into_iter()) {
Some(x) => x,
None => return input,
};
loop {
match input.next() {
None => break Ident::new("__inline_mac", Span::call_site()),
Some(TT::Ident(kind)) => match &*kind.to_string() {
"impl" => break Ident::new("__inline_mac_impl", Span::call_site()),
kind @ ("struct" | "enum" | "union" | "fn" | "mod" | "trait" | "type" | "const" | "static") => {
if let TT::Ident(name) = &input.tt {
break Ident::new(&format!("__inline_mac_{kind}_{name}"), Span::call_site());
} else {
break Ident::new(&format!("__inline_mac_{kind}"), Span::call_site());
}
},
_ => {},
},
_ => {},
}
}
};
let mut expander = Expander::default();
let mut mac = MacWriter::new(mac_name);
if let Err(e) = expander.expand(input.into_iter(), &mut mac) {
return e;
}
let mut out = TokenStream::new();
mac.finish(&mut out);
out.extend(expander.expn);
out
}
/// Wraps a `TokenStream` iterator with a single token lookahead.
struct LookaheadIter {
tt: TT,
iter: IntoIter,
}
impl LookaheadIter {
fn new(mut iter: IntoIter) -> Option<Self> {
iter.next().map(|tt| Self { tt, iter })
}
/// Get's the lookahead token, replacing it with the next token in the stream.
/// Note: If there isn't a next token, this will not return the lookahead token.
fn next(&mut self) -> Option<TT> {
self.iter.next().map(|tt| mem::replace(&mut self.tt, tt))
}
}
/// Builds the macro used to implement all the `inline!` macro calls.
struct MacWriter {
name: Ident,
macros: TokenStream,
next_idx: usize,
}
impl MacWriter {
fn new(name: Ident) -> Self {
Self {
name,
macros: TokenStream::new(),
next_idx: 0,
}
}
/// Inserts a new `inline!` call.
fn insert(&mut self, name_span: Span, bang_span: Span, body: Group, expander: &mut Expander) -> Result<()> {
let idx = self.next_idx;
self.next_idx += 1;
let mut inner = Expander::for_arm(idx);
inner.expand(body.stream().into_iter(), self)?;
let new_arm = inner.arm.unwrap();
self.macros.extend([
TT::Group(Group::new(Parenthesis, new_arm.args_def)),
TT::Punct(Punct::new('=', Joint)),
TT::Punct(Punct::new('>', Alone)),
TT::Group(Group::new(Parenthesis, inner.expn)),
TT::Punct(Punct::new(';', Alone)),
]);
expander.expn.extend([
TT::Ident({
let mut name = self.name.clone();
name.set_span(name_span);
name
}),
TT::Punct(punct_with_span('!', Alone, bang_span)),
]);
let mut call_body = TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]);
if let Some(arm) = expander.arm.as_mut() {
if !new_arm.args.is_empty() {
arm.add_sub_args(new_arm.args, &mut call_body);
}
} else {
call_body.extend(new_arm.args);
}
let mut g = Group::new(body.delimiter(), call_body);
g.set_span(body.span());
expander.expn.extend([TT::Group(g)]);
Ok(())
}
/// Creates the macro definition.
fn finish(self, out: &mut TokenStream) {
if self.next_idx != 0 {
out.extend([
TT::Ident(Ident::new("macro_rules", Span::call_site())),
TT::Punct(Punct::new('!', Alone)),
TT::Ident(self.name),
TT::Group(Group::new(Brace, self.macros)),
])
}
}
}
struct MacroArm {
args_def: TokenStream,
args: Vec<TT>,
}
impl MacroArm {
fn add_single_arg_def(&mut self, kind: &str, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
self.args_def.extend([
TT::Punct(Punct::new('$', Alone)),
TT::Ident(name.clone()),
TT::Punct(Punct::new(':', Alone)),
TT::Ident(Ident::new(kind, Span::call_site())),
]);
name.set_span(arg_span);
out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]);
}
fn add_parenthesized_arg_def(&mut self, kind: Ident, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
self.args_def.extend([TT::Group(Group::new(
Parenthesis,
TokenStream::from_iter([
TT::Punct(Punct::new('$', Alone)),
TT::Ident(name.clone()),
TT::Punct(Punct::new(':', Alone)),
TT::Ident(kind),
]),
))]);
name.set_span(arg_span);
out.extend([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]);
}
fn add_multi_arg_def(&mut self, dollar_span: Span, arg_span: Span, out: &mut TokenStream) {
let mut name = Ident::new(&format!("_{}", self.args.len()), Span::call_site());
self.args_def.extend([TT::Group(Group::new(
Parenthesis,
TokenStream::from_iter([
TT::Punct(Punct::new('$', Alone)),
TT::Group(Group::new(
Parenthesis,
TokenStream::from_iter([
TT::Punct(Punct::new('$', Alone)),
TT::Ident(name.clone()),
TT::Punct(Punct::new(':', Alone)),
TT::Ident(Ident::new("tt", Span::call_site())),
]),
)),
TT::Punct(Punct::new('*', Alone)),
]),
))]);
name.set_span(arg_span);
out.extend([
TT::Punct(punct_with_span('$', Alone, dollar_span)),
TT::Group(group_with_span(
Parenthesis,
TokenStream::from_iter([TT::Punct(punct_with_span('$', Alone, dollar_span)), TT::Ident(name)]),
dollar_span,
)),
TT::Punct(punct_with_span('*', Alone, dollar_span)),
]);
}
fn add_arg(&mut self, dollar_span: Span, tt: TT, input: &mut IntoIter, out: &mut TokenStream) -> Result<()> {
match tt {
TT::Punct(p) if p.as_char() == ESCAPE_CHAR => out.extend([TT::Punct(p)]),
TT::Punct(p) if p.as_char() == '\'' && p.spacing() == Joint => {
let lt_name = expect_tt(
input.next(),
|tt| match tt {
TT::Ident(x) => Some(x),
_ => None,
},
"lifetime name",
p.span(),
)?;
let arg_span = p.span().join(lt_name.span()).unwrap_or(p.span());
self.add_single_arg_def("lifetime", dollar_span, arg_span, out);
self.args.extend([TT::Punct(p), TT::Ident(lt_name)]);
},
TT::Ident(x) => {
self.add_single_arg_def("ident", dollar_span, x.span(), out);
self.args.push(TT::Ident(x));
},
TT::Literal(x) => {
self.add_single_arg_def("literal", dollar_span, x.span(), out);
self.args.push(TT::Literal(x));
},
TT::Group(g) if g.delimiter() == Parenthesis => {
let mut inner = g.stream().into_iter();
if let Some(TT::Punct(p)) = inner.next()
&& p.as_char() == '@'
{
let kind = expect_tt(
inner.next(),
|tt| match tt {
TT::Ident(kind) => Some(kind),
_ => None,
},
"a macro fragment specifier",
p.span(),
)?;
self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out);
self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span())))
} else {
self.add_multi_arg_def(dollar_span, g.span(), out);
self.args.push(TT::Group(g));
}
},
tt => return Err(make_error("unsupported escape", tt.span())),
};
Ok(())
}
fn add_sub_args(&mut self, args: Vec<TT>, out: &mut TokenStream) {
self.add_multi_arg_def(Span::call_site(), Span::call_site(), out);
self.args
.extend([TT::Group(Group::new(Parenthesis, TokenStream::from_iter(args)))]);
}
}
#[derive(Default)]
struct Expander {
arm: Option<MacroArm>,
expn: TokenStream,
}
impl Expander {
fn for_arm(idx: usize) -> Self {
Self {
arm: Some(MacroArm {
args_def: TokenStream::from_iter([TT::Literal(Literal::usize_unsuffixed(idx))]),
args: Vec::new(),
}),
expn: TokenStream::new(),
}
}
fn write_tt(&mut self, tt: TT, mac: &mut MacWriter) -> Result<()> {
match tt {
TT::Group(g) => {
let outer = mem::take(&mut self.expn);
self.expand(g.stream().into_iter(), mac)?;
let inner = mem::replace(&mut self.expn, outer);
self.expn
.extend([TT::Group(group_with_span(g.delimiter(), inner, g.span()))]);
},
tt => self.expn.extend([tt]),
}
Ok(())
}
fn expand(&mut self, input: IntoIter, mac: &mut MacWriter) -> Result<()> {
let Some(mut input) = LookaheadIter::new(input) else {
return Ok(());
};
while let Some(tt) = input.next() {
if let TT::Punct(p) = &tt
&& p.as_char() == ESCAPE_CHAR
&& let Some(arm) = self.arm.as_mut()
{
arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?;
if input.next().is_none() {
return Ok(());
}
} else if let TT::Punct(p) = &input.tt
&& p.as_char() == '!'
&& let TT::Ident(name) = &tt
&& name.to_string() == "inline"
{
let g = expect_tt(
input.iter.next(),
|tt| match tt {
TT::Group(g) => Some(g),
_ => None,
},
"macro arguments",
p.span(),
)?;
mac.insert(name.span(), p.span(), g, self)?;
if input.next().is_none() {
return Ok(());
}
} else {
self.write_tt(tt, mac)?;
}
}
self.write_tt(input.tt, mac)
}
}

View File

@ -0,0 +1 @@
excessive-nesting-threshold = 4

View File

@ -0,0 +1,196 @@
//@aux-build:proc_macros.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 proc_macros;
static X: u32 = {
let x = {
let y = {
let z = {
let w = { 3 };
w
};
z
};
y
};
x
};
macro_rules! xx {
() => {{
{
{
{
{
{
{
{
{
{
{
println!("ehe"); // should not lint
}
}
}
}
}
}
}
}
}
}
}};
}
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, but cc is
}
let x = { 1 }; // warning
}
}
}
#[allow(clippy::excessive_nesting)]
fn l() {{{{{{{{{}}}}}}}}}
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 {}
} // not here
} // only warning should be here
}
}
}
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
})();
external! { {{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}} }; // ensure this isn't linted in external macros
with_span! { span {{{{{{{{{{{{}}}}}}}}}}}} }; // don't lint for proc macros
xx!(); // ensure this is never linted
let boo = true;
!{boo as u32 + !{boo as u32 + !{boo as u32}}};
// this is a mess, but that's intentional
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}}}};
}

View File

@ -0,0 +1,314 @@
error: this block is too nested
--> $DIR/excessive_nesting.rs:20:25
|
LL | let w = { 3 };
| ^^^^^
|
= help: try refactoring your code to minimize nesting
= note: `-D clippy::excessive-nesting` implied by `-D warnings`
error: this block is too nested
--> $DIR/excessive_nesting.rs:66:17
|
LL | / impl C {
LL | | pub fn c() {}
LL | | }
| |_________________^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:80:25
|
LL | let x = { 1 }; // not a warning, but cc is
| ^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:97:17
|
LL | / pub mod e {
LL | | pub mod f {}
LL | | } // not here
| |_________________^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:110:18
|
LL | a_but_not({{{{{{{{0}}}}}}}});
| ^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:111:12
|
LL | a.a({{{{{{{{{0}}}}}}}}});
| ^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:112:12
|
LL | (0, {{{{{{{1}}}}}}});
| ^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:117:25
|
LL | if true {
| _________________________^
LL | | if true {
LL | |
LL | | }
LL | | }
| |_________________^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:129:29
|
LL | let z = (|| {
| _____________________________^
LL | | let w = { 3 };
LL | | w
LL | | })();
| |_________________^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:148:13
|
LL | y += {{{{{5}}}}};
| ^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:149:20
|
LL | let z = y + {{{{{{{{{5}}}}}}}}};
| ^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:150:12
|
LL | [0, {{{{{{{{{{0}}}}}}}}}}];
| ^^^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:151:25
|
LL | let mut xx = [0; {{{{{{{{100}}}}}}}}];
| ^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:152:11
|
LL | xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:153:13
|
LL | &mut {{{{{{{{{{y}}}}}}}}}};
| ^^^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:155:17
|
LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
| ^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:155:28
|
LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}}
| ^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:157:28
|
LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
| ^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:157:48
|
LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}}
| ^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:159:14
|
LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
| ^^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:159:35
|
LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}}
| ^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:161:23
|
LL | let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:163:8
|
LL | {{{{1;}}}}..{{{{{{3}}}}}};
| ^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:163:20
|
LL | {{{{1;}}}}..{{{{{{3}}}}}};
| ^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:164:8
|
LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
| ^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:164:21
|
LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}};
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:165:10
|
LL | ..{{{{{{{5}}}}}}};
| ^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:166:11
|
LL | ..={{{{{3}}}}};
| ^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:167:8
|
LL | {{{{{1;}}}}}..;
| ^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:169:20
|
LL | loop { break {{{{1}}}} };
| ^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:170:13
|
LL | loop {{{{{{}}}}}}
| ^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:172:14
|
LL | match {{{{{{true}}}}}} {
| ^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:173:20
|
LL | true => {{{{}}}},
| ^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:174:21
|
LL | false => {{{{}}}},
| ^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:180:17
|
LL | / {
LL | | println!("warning! :)");
LL | | }
| |_________________^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:189:28
|
LL | async fn c() -> u32 {{{{{{{0}}}}}}}
| ^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: this block is too nested
--> $DIR/excessive_nesting.rs:195:8
|
LL | {{{{b().await}}}};
| ^^^^^^^^^^^
|
= help: try refactoring your code to minimize nesting
error: aborting due to 37 previous errors

View File

@ -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
@ -85,6 +86,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
enforced-import-renames
enum-variant-name-threshold
enum-variant-size-threshold
excessive-nesting-threshold
future-size-threshold
ignore-interior-mutability
large-error-threshold

View File

@ -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 {
() => {