Skip to content

Commit f7db895

Browse files
committed
Auto merge of #13176 - shenyifu:master, r=Manishearth
Fix fix under loop may dropping loop label when applying fix. changelog: [`explicit_counter_loop`]: fix label drop changelog: [`for_kv_map`]: add label drop test
2 parents 668b659 + 38a3462 commit f7db895

File tree

8 files changed

+67
-8
lines changed

8 files changed

+67
-8
lines changed

clippy_lints/src/loops/explicit_counter_loop.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use super::{make_iterator_snippet, IncrementVisitor, InitializeVisitor, EXPLICIT
22
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
33
use clippy_utils::source::snippet_with_applicability;
44
use clippy_utils::{get_enclosing_block, is_integer_const};
5+
use rustc_ast::Label;
56
use rustc_errors::Applicability;
67
use rustc_hir::intravisit::{walk_block, walk_expr};
78
use rustc_hir::{Expr, Pat};
@@ -17,6 +18,7 @@ pub(super) fn check<'tcx>(
1718
arg: &'tcx Expr<'_>,
1819
body: &'tcx Expr<'_>,
1920
expr: &'tcx Expr<'_>,
21+
label: Option<Label>,
2022
) {
2123
// Look for variables that are incremented once per loop iteration.
2224
let mut increment_visitor = IncrementVisitor::new(cx);
@@ -34,7 +36,7 @@ pub(super) fn check<'tcx>(
3436
{
3537
let mut applicability = Applicability::MaybeIncorrect;
3638
let span = expr.span.with_hi(arg.span.hi());
37-
39+
let loop_label = label.map_or(String::new(), |l| format!("{}: ", l.ident.name));
3840
let int_name = match ty.map(Ty::kind) {
3941
// usize or inferred
4042
Some(ty::Uint(UintTy::Usize)) | None => {
@@ -45,7 +47,7 @@ pub(super) fn check<'tcx>(
4547
format!("the variable `{name}` is used as a loop counter"),
4648
"consider using",
4749
format!(
48-
"for ({name}, {}) in {}.enumerate()",
50+
"{loop_label}for ({name}, {}) in {}.enumerate()",
4951
snippet_with_applicability(cx, pat.span, "item", &mut applicability),
5052
make_iterator_snippet(cx, arg, &mut applicability),
5153
),
@@ -68,7 +70,7 @@ pub(super) fn check<'tcx>(
6870
span,
6971
"consider using",
7072
format!(
71-
"for ({name}, {}) in (0_{int_name}..).zip({})",
73+
"{loop_label}for ({name}, {}) in (0_{int_name}..).zip({})",
7274
snippet_with_applicability(cx, pat.span, "item", &mut applicability),
7375
make_iterator_snippet(cx, arg, &mut applicability),
7476
),

clippy_lints/src/loops/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ mod while_let_on_iterator;
2525
use clippy_config::msrvs::Msrv;
2626
use clippy_config::Conf;
2727
use clippy_utils::higher;
28+
use rustc_ast::Label;
2829
use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
2930
use rustc_lint::{LateContext, LateLintPass};
3031
use rustc_session::impl_lint_pass;
@@ -760,6 +761,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
760761
body,
761762
loop_id,
762763
span,
764+
label,
763765
}) = for_loop
764766
{
765767
// we don't want to check expanded macros
@@ -768,7 +770,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
768770
if body.span.from_expansion() {
769771
return;
770772
}
771-
self.check_for_loop(cx, pat, arg, body, expr, span);
773+
self.check_for_loop(cx, pat, arg, body, expr, span, label);
772774
if let ExprKind::Block(block, _) = body.kind {
773775
never_loop::check(cx, block, loop_id, span, for_loop.as_ref());
774776
}
@@ -808,6 +810,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
808810
}
809811

810812
impl Loops {
813+
#[allow(clippy::too_many_arguments)]
811814
fn check_for_loop<'tcx>(
812815
&self,
813816
cx: &LateContext<'tcx>,
@@ -816,11 +819,12 @@ impl Loops {
816819
body: &'tcx Expr<'_>,
817820
expr: &'tcx Expr<'_>,
818821
span: Span,
822+
label: Option<Label>,
819823
) {
820824
let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr);
821825
if !is_manual_memcpy_triggered {
822826
needless_range_loop::check(cx, pat, arg, body, expr);
823-
explicit_counter_loop::check(cx, pat, arg, body, expr);
827+
explicit_counter_loop::check(cx, pat, arg, body, expr, label);
824828
}
825829
self.check_for_loop_arg(cx, pat, arg);
826830
for_kv_map::check(cx, pat, arg, body);

clippy_utils/src/higher.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub struct ForLoop<'tcx> {
2525
pub loop_id: HirId,
2626
/// entire `for` loop span
2727
pub span: Span,
28+
/// label
29+
pub label: Option<ast::Label>,
2830
}
2931

3032
impl<'tcx> ForLoop<'tcx> {
@@ -33,7 +35,7 @@ impl<'tcx> ForLoop<'tcx> {
3335
if let ExprKind::DropTemps(e) = expr.kind
3436
&& let ExprKind::Match(iterexpr, [arm], MatchSource::ForLoopDesugar) = e.kind
3537
&& let ExprKind::Call(_, [arg]) = iterexpr.kind
36-
&& let ExprKind::Loop(block, ..) = arm.body.kind
38+
&& let ExprKind::Loop(block, label, ..) = arm.body.kind
3739
&& let [stmt] = block.stmts
3840
&& let hir::StmtKind::Expr(e) = stmt.kind
3941
&& let ExprKind::Match(_, [_, some_arm], _) = e.kind
@@ -45,6 +47,7 @@ impl<'tcx> ForLoop<'tcx> {
4547
body: some_arm.body,
4648
loop_id: arm.body.hir_id,
4749
span: expr.span.ctxt().outer_expn_data().call_site,
50+
label,
4851
});
4952
}
5053
None

tests/ui/explicit_counter_loop.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,3 +278,16 @@ mod issue_10058 {
278278
}
279279
}
280280
}
281+
282+
mod issue_13123 {
283+
pub fn test() {
284+
let mut vec = vec![1, 2, 3, 4];
285+
let mut _index = 0;
286+
'label: for v in vec {
287+
_index += 1;
288+
if v == 1 {
289+
break 'label;
290+
}
291+
}
292+
}
293+
}

tests/ui/explicit_counter_loop.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,11 @@ LL | for _item in slice {
5757
|
5858
= note: `idx_u32` is of type `u32`, making it ineligible for `Iterator::enumerate`
5959

60-
error: aborting due to 9 previous errors
60+
error: the variable `_index` is used as a loop counter
61+
--> tests/ui/explicit_counter_loop.rs:286:9
62+
|
63+
LL | 'label: for v in vec {
64+
| ^^^^^^^^^^^^^^^^^^^^ help: consider using: `'label: for (_index, v) in vec.into_iter().enumerate()`
65+
66+
error: aborting due to 10 previous errors
6167

tests/ui/for_kv_map.fixed

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ fn main() {
4040
let _k = k;
4141
}
4242

43+
let m: HashMap<u64, u64> = HashMap::new();
44+
let rm = &m;
45+
'label: for k in rm.keys() {
46+
//~^ ERROR: you seem to want to iterate on a map's keys
47+
let _k = k;
48+
if *k == 0u64 {
49+
break 'label;
50+
}
51+
}
52+
4353
// The following should not produce warnings.
4454

4555
let m: HashMap<u64, u64> = HashMap::new();

tests/ui/for_kv_map.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ fn main() {
4040
let _k = k;
4141
}
4242

43+
let m: HashMap<u64, u64> = HashMap::new();
44+
let rm = &m;
45+
'label: for (k, _value) in rm {
46+
//~^ ERROR: you seem to want to iterate on a map's keys
47+
let _k = k;
48+
if *k == 0u64 {
49+
break 'label;
50+
}
51+
}
52+
4353
// The following should not produce warnings.
4454

4555
let m: HashMap<u64, u64> = HashMap::new();

tests/ui/for_kv_map.stderr

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,16 @@ help: use the corresponding method
5555
LL | for k in rm.keys() {
5656
| ~ ~~~~~~~~~
5757

58-
error: aborting due to 5 previous errors
58+
error: you seem to want to iterate on a map's keys
59+
--> tests/ui/for_kv_map.rs:45:32
60+
|
61+
LL | 'label: for (k, _value) in rm {
62+
| ^^
63+
|
64+
help: use the corresponding method
65+
|
66+
LL | 'label: for k in rm.keys() {
67+
| ~ ~~~~~~~~~
68+
69+
error: aborting due to 6 previous errors
5970

0 commit comments

Comments
 (0)