|
1 | | -use crate::{LateContext, LateLintPass, LintContext}; |
| 1 | +#![deny(rustc::untranslatable_diagnostic)] |
| 2 | +#![deny(rustc::diagnostic_outside_of_impl)] |
| 3 | +use crate::{ |
| 4 | + lints::{ |
| 5 | + ForLoopsOverFalliblesDiag, ForLoopsOverFalliblesLoopSub, ForLoopsOverFalliblesQuestionMark, |
| 6 | + ForLoopsOverFalliblesSuggestion, |
| 7 | + }, |
| 8 | + LateContext, LateLintPass, LintContext, |
| 9 | +}; |
2 | 10 |
|
3 | 11 | use hir::{Expr, Pat}; |
4 | | -use rustc_errors::{Applicability, DelayDm}; |
5 | 12 | use rustc_hir as hir; |
6 | 13 | use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause}; |
7 | 14 | use rustc_middle::ty::{self, List}; |
@@ -53,53 +60,29 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles { |
53 | 60 | _ => return, |
54 | 61 | }; |
55 | 62 |
|
56 | | - let msg = DelayDm(|| { |
57 | | - format!( |
58 | | - "for loop over {article} `{ty}`. This is more readably written as an `if let` statement", |
59 | | - ) |
60 | | - }); |
61 | | - |
62 | | - cx.struct_span_lint(FOR_LOOPS_OVER_FALLIBLES, arg.span, msg, |lint| { |
63 | | - if let Some(recv) = extract_iterator_next_call(cx, arg) |
| 63 | + let sub = if let Some(recv) = extract_iterator_next_call(cx, arg) |
64 | 64 | && let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span) |
65 | 65 | { |
66 | | - lint.span_suggestion( |
67 | | - recv.span.between(arg.span.shrink_to_hi()), |
68 | | - format!("to iterate over `{recv_snip}` remove the call to `next`"), |
69 | | - ".by_ref()", |
70 | | - Applicability::MaybeIncorrect |
71 | | - ); |
| 66 | + ForLoopsOverFalliblesLoopSub::RemoveNext { suggestion: recv.span.between(arg.span.shrink_to_hi()), recv_snip } |
72 | 67 | } else { |
73 | | - lint.multipart_suggestion_verbose( |
74 | | - "to check pattern in a loop use `while let`", |
75 | | - vec![ |
76 | | - // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts |
77 | | - (expr.span.with_hi(pat.span.lo()), format!("while let {var}(")), |
78 | | - (pat.span.between(arg.span), ") = ".to_string()), |
79 | | - ], |
80 | | - Applicability::MaybeIncorrect |
81 | | - ); |
82 | | - } |
83 | | - |
84 | | - if suggest_question_mark(cx, adt, substs, expr.span) { |
85 | | - lint.span_suggestion( |
86 | | - arg.span.shrink_to_hi(), |
87 | | - "consider unwrapping the `Result` with `?` to iterate over its contents", |
88 | | - "?", |
89 | | - Applicability::MaybeIncorrect, |
90 | | - ); |
91 | | - } |
92 | | - |
93 | | - lint.multipart_suggestion_verbose( |
94 | | - "consider using `if let` to clear intent", |
95 | | - vec![ |
96 | | - // NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts |
97 | | - (expr.span.with_hi(pat.span.lo()), format!("if let {var}(")), |
98 | | - (pat.span.between(arg.span), ") = ".to_string()), |
99 | | - ], |
100 | | - Applicability::MaybeIncorrect, |
101 | | - ) |
102 | | - }) |
| 68 | + ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var } |
| 69 | + } ; |
| 70 | + let question_mark = if suggest_question_mark(cx, adt, substs, expr.span) { |
| 71 | + Some(ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() }) |
| 72 | + } else { |
| 73 | + None |
| 74 | + }; |
| 75 | + let suggestion = ForLoopsOverFalliblesSuggestion { |
| 76 | + var, |
| 77 | + start_span: expr.span.with_hi(pat.span.lo()), |
| 78 | + end_span: pat.span.between(arg.span), |
| 79 | + }; |
| 80 | + |
| 81 | + cx.emit_spanned_lint( |
| 82 | + FOR_LOOPS_OVER_FALLIBLES, |
| 83 | + arg.span, |
| 84 | + ForLoopsOverFalliblesDiag { article, ty, sub, question_mark, suggestion }, |
| 85 | + ); |
103 | 86 | } |
104 | 87 | } |
105 | 88 |
|
|
0 commit comments