diff options
| author | Peter Jaszkowiak <p.jaszkow@gmail.com> | 2022-04-01 00:04:19 -0600 |
|---|---|---|
| committer | Peter Jaszkowiak <p.jaszkow@gmail.com> | 2022-04-01 00:04:19 -0600 |
| commit | 3bbb3e33295f4de11efb904192df1a3764d89e8d (patch) | |
| tree | 28c8f031215f56b6094388150220bb058e1db77d | |
| parent | 8ebe766695e66a97775e4992d3d08f74ce2a7270 (diff) | |
| download | rust-3bbb3e33295f4de11efb904192df1a3764d89e8d.tar.gz rust-3bbb3e33295f4de11efb904192df1a3764d89e8d.zip | |
single_element_loop: handle arrays for Edition2021
also handle `.iter_mut()`, `.into_iter()`, and wrapping in parens if necessary
| -rw-r--r-- | clippy_lints/src/loops/single_element_loop.rs | 70 | ||||
| -rw-r--r-- | tests/ui/single_element_loop.fixed | 24 | ||||
| -rw-r--r-- | tests/ui/single_element_loop.rs | 20 | ||||
| -rw-r--r-- | tests/ui/single_element_loop.stderr | 74 |
4 files changed, 172 insertions, 16 deletions
diff --git a/clippy_lints/src/loops/single_element_loop.rs b/clippy_lints/src/loops/single_element_loop.rs index 36ecd83f7d6..a0bd7ad0ac6 100644 --- a/clippy_lints/src/loops/single_element_loop.rs +++ b/clippy_lints/src/loops/single_element_loop.rs @@ -2,9 +2,12 @@ use super::SINGLE_ELEMENT_LOOP; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, snippet_with_applicability}; use if_chain::if_chain; +use rustc_ast::util::parser::PREC_PREFIX; +use rustc_ast::Mutability; use rustc_errors::Applicability; -use rustc_hir::{BorrowKind, Expr, ExprKind, Pat}; +use rustc_hir::{is_range_literal, BorrowKind, Expr, ExprKind, Pat}; use rustc_lint::LateContext; +use rustc_span::edition::Edition; pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -13,31 +16,84 @@ pub(super) fn check<'tcx>( body: &'tcx Expr<'_>, expr: &'tcx Expr<'_>, ) { - let arg_expr = match arg.kind { - ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg, - ExprKind::MethodCall(method, [arg], _) if method.ident.name == rustc_span::sym::iter => arg, + let (arg_expression, prefix) = match arg.kind { + ExprKind::AddrOf( + BorrowKind::Ref, + Mutability::Not, + Expr { + kind: ExprKind::Array([arg]), + .. + }, + ) => (arg, "&"), + ExprKind::AddrOf( + BorrowKind::Ref, + Mutability::Mut, + Expr { + kind: ExprKind::Array([arg]), + .. + }, + ) => (arg, "&mut "), + ExprKind::MethodCall( + method, + [ + Expr { + kind: ExprKind::Array([arg]), + .. + }, + ], + _, + ) if method.ident.name == rustc_span::sym::iter => (arg, "&"), + ExprKind::MethodCall( + method, + [ + Expr { + kind: ExprKind::Array([arg]), + .. + }, + ], + _, + ) if method.ident.name.as_str() == "iter_mut" => (arg, "&mut "), + ExprKind::MethodCall( + method, + [ + Expr { + kind: ExprKind::Array([arg]), + .. + }, + ], + _, + ) if method.ident.name == rustc_span::sym::into_iter => (arg, ""), + // Only check for arrays edition 2021 or later, as this case will trigger a compiler error otherwise. + ExprKind::Array([arg]) if cx.tcx.sess.edition() >= Edition::Edition2021 => (arg, ""), _ => return, }; if_chain! { - if let ExprKind::Array([arg_expression]) = arg_expr.kind; if let ExprKind::Block(block, _) = body.kind; if !block.stmts.is_empty(); then { let mut applicability = Applicability::MachineApplicable; let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability); - let arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability); + let mut arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability); let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned(); block_str.remove(0); block_str.pop(); let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)); + // Reference iterator from `&(mut) []` or `[].iter(_mut)()`. + if !prefix.is_empty() && ( + // Precedence of internal expression is less than or equal to precedence of `&expr`. + arg_expression.precedence().order() <= PREC_PREFIX || is_range_literal(arg_expression) + ) { + arg_snip = format!("({arg_snip})").into(); + } + span_lint_and_sugg( cx, SINGLE_ELEMENT_LOOP, expr.span, "for loop over a single element", "try", - format!("{{\n{}let {} = &{};{}}}", indent, pat_snip, arg_snip, block_str), + format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"), applicability, ) } diff --git a/tests/ui/single_element_loop.fixed b/tests/ui/single_element_loop.fixed index c307afffcb8..63d31ff83f9 100644 --- a/tests/ui/single_element_loop.fixed +++ b/tests/ui/single_element_loop.fixed @@ -6,11 +6,31 @@ fn main() { let item1 = 2; { let item = &item1; - println!("{}", item); + dbg!(item); } { let item = &item1; - println!("{:?}", item); + dbg!(item); + } + + { + let item = &(0..5); + dbg!(item); + } + + { + let item = &mut (0..5); + dbg!(item); + } + + { + let item = 0..5; + dbg!(item); + } + + { + let item = 0..5; + dbg!(item); } } diff --git a/tests/ui/single_element_loop.rs b/tests/ui/single_element_loop.rs index 2c0c03b7211..2cda5a329d2 100644 --- a/tests/ui/single_element_loop.rs +++ b/tests/ui/single_element_loop.rs @@ -5,10 +5,26 @@ fn main() { let item1 = 2; for item in &[item1] { - println!("{}", item); + dbg!(item); } for item in [item1].iter() { - println!("{:?}", item); + dbg!(item); + } + + for item in &[0..5] { + dbg!(item); + } + + for item in [0..5].iter_mut() { + dbg!(item); + } + + for item in [0..5] { + dbg!(item); + } + + for item in [0..5].into_iter() { + dbg!(item); } } diff --git a/tests/ui/single_element_loop.stderr b/tests/ui/single_element_loop.stderr index f52ca8c5a9b..0aeb8da1a2e 100644 --- a/tests/ui/single_element_loop.stderr +++ b/tests/ui/single_element_loop.stderr @@ -2,7 +2,7 @@ error: for loop over a single element --> $DIR/single_element_loop.rs:7:5 | LL | / for item in &[item1] { -LL | | println!("{}", item); +LL | | dbg!(item); LL | | } | |_____^ | @@ -11,7 +11,7 @@ help: try | LL ~ { LL + let item = &item1; -LL + println!("{}", item); +LL + dbg!(item); LL + } | @@ -19,7 +19,7 @@ error: for loop over a single element --> $DIR/single_element_loop.rs:11:5 | LL | / for item in [item1].iter() { -LL | | println!("{:?}", item); +LL | | dbg!(item); LL | | } | |_____^ | @@ -27,9 +27,73 @@ help: try | LL ~ { LL + let item = &item1; -LL + println!("{:?}", item); +LL + dbg!(item); LL + } | -error: aborting due to 2 previous errors +error: for loop over a single element + --> $DIR/single_element_loop.rs:15:5 + | +LL | / for item in &[0..5] { +LL | | dbg!(item); +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let item = &(0..5); +LL + dbg!(item); +LL + } + | + +error: for loop over a single element + --> $DIR/single_element_loop.rs:19:5 + | +LL | / for item in [0..5].iter_mut() { +LL | | dbg!(item); +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let item = &mut (0..5); +LL + dbg!(item); +LL + } + | + +error: for loop over a single element + --> $DIR/single_element_loop.rs:23:5 + | +LL | / for item in [0..5] { +LL | | dbg!(item); +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let item = 0..5; +LL + dbg!(item); +LL + } + | + +error: for loop over a single element + --> $DIR/single_element_loop.rs:27:5 + | +LL | / for item in [0..5].into_iter() { +LL | | dbg!(item); +LL | | } + | |_____^ + | +help: try + | +LL ~ { +LL + let item = 0..5; +LL + dbg!(item); +LL + } + | + +error: aborting due to 6 previous errors |
