mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
migrate: for_loops_over_fallibles.rs
This commit is contained in:
parent
3c1a1f3643
commit
ca7df9a2a9
@ -16,6 +16,13 @@ lint_enum_intrinsics_mem_variant =
|
|||||||
lint_expectation = this lint expectation is unfulfilled
|
lint_expectation = this lint expectation is unfulfilled
|
||||||
.note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
|
.note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
|
||||||
|
|
||||||
|
lint_for_loops_over_fallibles =
|
||||||
|
for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
|
||||||
|
.suggestion = consider using `if let` to clear intent
|
||||||
|
.remove_next = to iterate over `{$recv_snip}` remove the call to `next`
|
||||||
|
.use_while_let = to check pattern in a loop use `while let`
|
||||||
|
.use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents
|
||||||
|
|
||||||
lint_non_binding_let_on_sync_lock =
|
lint_non_binding_let_on_sync_lock =
|
||||||
non-binding let on a synchronization lock
|
non-binding let on a synchronization lock
|
||||||
|
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
use crate::{LateContext, LateLintPass, LintContext};
|
#![deny(rustc::untranslatable_diagnostic)]
|
||||||
|
#![deny(rustc::diagnostic_outside_of_impl)]
|
||||||
|
use crate::{
|
||||||
|
lints::{
|
||||||
|
ForLoopsOverFalliblesDiag, ForLoopsOverFalliblesLoopSub, ForLoopsOverFalliblesQuestionMark,
|
||||||
|
ForLoopsOverFalliblesSuggestion,
|
||||||
|
},
|
||||||
|
LateContext, LateLintPass, LintContext,
|
||||||
|
};
|
||||||
|
|
||||||
use hir::{Expr, Pat};
|
use hir::{Expr, Pat};
|
||||||
use rustc_errors::{Applicability, DelayDm};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
|
use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
|
||||||
use rustc_middle::ty::{self, List};
|
use rustc_middle::ty::{self, List};
|
||||||
@ -53,53 +60,29 @@ impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let msg = DelayDm(|| {
|
let sub = if let Some(recv) = extract_iterator_next_call(cx, arg)
|
||||||
format!(
|
|
||||||
"for loop over {article} `{ty}`. This is more readably written as an `if let` statement",
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
cx.struct_span_lint(FOR_LOOPS_OVER_FALLIBLES, arg.span, msg, |lint| {
|
|
||||||
if let Some(recv) = extract_iterator_next_call(cx, arg)
|
|
||||||
&& let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
|
&& let Ok(recv_snip) = cx.sess().source_map().span_to_snippet(recv.span)
|
||||||
{
|
{
|
||||||
lint.span_suggestion(
|
ForLoopsOverFalliblesLoopSub::RemoveNext { suggestion: recv.span.between(arg.span.shrink_to_hi()), recv_snip }
|
||||||
recv.span.between(arg.span.shrink_to_hi()),
|
|
||||||
format!("to iterate over `{recv_snip}` remove the call to `next`"),
|
|
||||||
".by_ref()",
|
|
||||||
Applicability::MaybeIncorrect
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
lint.multipart_suggestion_verbose(
|
ForLoopsOverFalliblesLoopSub::UseWhileLet { start_span: expr.span.with_hi(pat.span.lo()), end_span: pat.span.between(arg.span), var }
|
||||||
"to check pattern in a loop use `while let`",
|
} ;
|
||||||
vec![
|
let question_mark = if suggest_question_mark(cx, adt, substs, expr.span) {
|
||||||
// NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
|
Some(ForLoopsOverFalliblesQuestionMark { suggestion: arg.span.shrink_to_hi() })
|
||||||
(expr.span.with_hi(pat.span.lo()), format!("while let {var}(")),
|
} else {
|
||||||
(pat.span.between(arg.span), ") = ".to_string()),
|
None
|
||||||
],
|
};
|
||||||
Applicability::MaybeIncorrect
|
let suggestion = ForLoopsOverFalliblesSuggestion {
|
||||||
);
|
var,
|
||||||
}
|
start_span: expr.span.with_hi(pat.span.lo()),
|
||||||
|
end_span: pat.span.between(arg.span),
|
||||||
|
};
|
||||||
|
|
||||||
if suggest_question_mark(cx, adt, substs, expr.span) {
|
cx.emit_spanned_lint(
|
||||||
lint.span_suggestion(
|
FOR_LOOPS_OVER_FALLIBLES,
|
||||||
arg.span.shrink_to_hi(),
|
arg.span,
|
||||||
"consider unwrapping the `Result` with `?` to iterate over its contents",
|
ForLoopsOverFalliblesDiag { article, ty, sub, question_mark, suggestion },
|
||||||
"?",
|
);
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
lint.multipart_suggestion_verbose(
|
|
||||||
"consider using `if let` to clear intent",
|
|
||||||
vec![
|
|
||||||
// NB can't use `until` here because `expr.span` and `pat.span` have different syntax contexts
|
|
||||||
(expr.span.with_hi(pat.span.lo()), format!("if let {var}(")),
|
|
||||||
(pat.span.between(arg.span), ") = ".to_string()),
|
|
||||||
],
|
|
||||||
Applicability::MaybeIncorrect,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,6 +333,55 @@ impl<'a> DecorateLint<'a, ()> for Expectation<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// for_loops_over_fallibles.rs
|
||||||
|
#[derive(LintDiagnostic)]
|
||||||
|
#[diag(lint_for_loops_over_fallibles)]
|
||||||
|
pub struct ForLoopsOverFalliblesDiag<'a> {
|
||||||
|
pub article: &'static str,
|
||||||
|
pub ty: &'static str,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub sub: ForLoopsOverFalliblesLoopSub<'a>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub question_mark: Option<ForLoopsOverFalliblesQuestionMark>,
|
||||||
|
#[subdiagnostic]
|
||||||
|
pub suggestion: ForLoopsOverFalliblesSuggestion<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
pub enum ForLoopsOverFalliblesLoopSub<'a> {
|
||||||
|
#[suggestion(remove_next, code = ".by_ref()", applicability = "maybe-incorrect")]
|
||||||
|
RemoveNext {
|
||||||
|
#[primary_span]
|
||||||
|
suggestion: Span,
|
||||||
|
recv_snip: String,
|
||||||
|
},
|
||||||
|
#[multipart_suggestion(use_while_let, applicability = "maybe-incorrect")]
|
||||||
|
UseWhileLet {
|
||||||
|
#[suggestion_part(code = "while let {var}(")]
|
||||||
|
start_span: Span,
|
||||||
|
#[suggestion_part(code = ") = ")]
|
||||||
|
end_span: Span,
|
||||||
|
var: &'a str,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[suggestion(use_question_mark, code = "?", applicability = "maybe-incorrect")]
|
||||||
|
pub struct ForLoopsOverFalliblesQuestionMark {
|
||||||
|
#[primary_span]
|
||||||
|
pub suggestion: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subdiagnostic)]
|
||||||
|
#[multipart_suggestion(suggestion, applicability = "maybe-incorrect")]
|
||||||
|
pub struct ForLoopsOverFalliblesSuggestion<'a> {
|
||||||
|
pub var: &'a str,
|
||||||
|
#[suggestion_part(code = "if let {var}(")]
|
||||||
|
pub start_span: Span,
|
||||||
|
#[suggestion_part(code = ") = ")]
|
||||||
|
pub end_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
// internal.rs
|
// internal.rs
|
||||||
#[derive(LintDiagnostic)]
|
#[derive(LintDiagnostic)]
|
||||||
#[diag(lint_default_hash_types)]
|
#[diag(lint_default_hash_types)]
|
||||||
|
Loading…
Reference in New Issue
Block a user