mirror of
https://github.com/rust-lang/rust-clippy
synced 2025-02-16 05:58:41 +00:00
Auto merge of #8616 - pitaj:single_element_loop_arrays, r=llogiq
single_element_loop: handle arrays for Edition2021 changelog: [`single_element_loop`] handle arrays in Edition 2021, handle `.iter_mut()` and `.into_iter()`, and wrap in parens if necessary
This commit is contained in:
commit
f6b29923c6
4 changed files with 172 additions and 16 deletions
|
@ -2,9 +2,12 @@ use super::SINGLE_ELEMENT_LOOP;
|
||||||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
use clippy_utils::source::{indent_of, snippet_with_applicability};
|
use clippy_utils::source::{indent_of, snippet_with_applicability};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
|
use rustc_ast::util::parser::PREC_PREFIX;
|
||||||
|
use rustc_ast::Mutability;
|
||||||
use rustc_errors::Applicability;
|
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_lint::LateContext;
|
||||||
|
use rustc_span::edition::Edition;
|
||||||
|
|
||||||
pub(super) fn check<'tcx>(
|
pub(super) fn check<'tcx>(
|
||||||
cx: &LateContext<'tcx>,
|
cx: &LateContext<'tcx>,
|
||||||
|
@ -13,31 +16,84 @@ pub(super) fn check<'tcx>(
|
||||||
body: &'tcx Expr<'_>,
|
body: &'tcx Expr<'_>,
|
||||||
expr: &'tcx Expr<'_>,
|
expr: &'tcx Expr<'_>,
|
||||||
) {
|
) {
|
||||||
let arg_expr = match arg.kind {
|
let (arg_expression, prefix) = match arg.kind {
|
||||||
ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg,
|
ExprKind::AddrOf(
|
||||||
ExprKind::MethodCall(method, [arg], _) if method.ident.name == rustc_span::sym::iter => arg,
|
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,
|
_ => return,
|
||||||
};
|
};
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let ExprKind::Array([arg_expression]) = arg_expr.kind;
|
|
||||||
if let ExprKind::Block(block, _) = body.kind;
|
if let ExprKind::Block(block, _) = body.kind;
|
||||||
if !block.stmts.is_empty();
|
if !block.stmts.is_empty();
|
||||||
then {
|
then {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
|
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();
|
let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
|
||||||
block_str.remove(0);
|
block_str.remove(0);
|
||||||
block_str.pop();
|
block_str.pop();
|
||||||
let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0));
|
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(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
SINGLE_ELEMENT_LOOP,
|
SINGLE_ELEMENT_LOOP,
|
||||||
expr.span,
|
expr.span,
|
||||||
"for loop over a single element",
|
"for loop over a single element",
|
||||||
"try",
|
"try",
|
||||||
format!("{{\n{}let {} = &{};{}}}", indent, pat_snip, arg_snip, block_str),
|
format!("{{\n{indent}let {pat_snip} = {prefix}{arg_snip};{block_str}}}"),
|
||||||
applicability,
|
applicability,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,31 @@ fn main() {
|
||||||
let item1 = 2;
|
let item1 = 2;
|
||||||
{
|
{
|
||||||
let item = &item1;
|
let item = &item1;
|
||||||
println!("{}", item);
|
dbg!(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let item = &item1;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,26 @@
|
||||||
fn main() {
|
fn main() {
|
||||||
let item1 = 2;
|
let item1 = 2;
|
||||||
for item in &[item1] {
|
for item in &[item1] {
|
||||||
println!("{}", item);
|
dbg!(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
for item in [item1].iter() {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ error: for loop over a single element
|
||||||
--> $DIR/single_element_loop.rs:7:5
|
--> $DIR/single_element_loop.rs:7:5
|
||||||
|
|
|
|
||||||
LL | / for item in &[item1] {
|
LL | / for item in &[item1] {
|
||||||
LL | | println!("{}", item);
|
LL | | dbg!(item);
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
|
@ -11,7 +11,7 @@ help: try
|
||||||
|
|
|
|
||||||
LL ~ {
|
LL ~ {
|
||||||
LL + let item = &item1;
|
LL + let item = &item1;
|
||||||
LL + println!("{}", item);
|
LL + dbg!(item);
|
||||||
LL + }
|
LL + }
|
||||||
|
|
|
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ error: for loop over a single element
|
||||||
--> $DIR/single_element_loop.rs:11:5
|
--> $DIR/single_element_loop.rs:11:5
|
||||||
|
|
|
|
||||||
LL | / for item in [item1].iter() {
|
LL | / for item in [item1].iter() {
|
||||||
LL | | println!("{:?}", item);
|
LL | | dbg!(item);
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____^
|
| |_____^
|
||||||
|
|
|
|
||||||
|
@ -27,9 +27,73 @@ help: try
|
||||||
|
|
|
|
||||||
LL ~ {
|
LL ~ {
|
||||||
LL + let item = &item1;
|
LL + let item = &item1;
|
||||||
LL + println!("{:?}", item);
|
LL + dbg!(item);
|
||||||
LL + }
|
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
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue