|
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