Rollup merge of #99696 - WaffleLapkin:uplift, r=fee1-dead
Uplift `clippy::for_loops_over_fallibles` lint into rustc This PR, as the title suggests, uplifts [`clippy::for_loops_over_fallibles`] lint into rustc. This lint warns for code like this: ```rust for _ in Some(1) {} for _ in Ok::<_, ()>(1) {} ``` i.e. directly iterating over `Option` and `Result` using `for` loop. There are a number of suggestions that this PR adds (on top of what clippy suggested): 1. If the argument (? is there a better name for that expression) of a `for` loop is a `.next()` call, then we can suggest removing it (or rather replacing with `.by_ref()` to allow iterator being used later) ```rust for _ in iter.next() {} // turns into for _ in iter.by_ref() {} ``` 2. (otherwise) We can suggest using `while let`, this is useful for non-iterator, iterator-like things like [async] channels ```rust for _ in rx.recv() {} // turns into while let Some(_) = rx.recv() {} ``` 3. If the argument type is `Result<impl IntoIterator, _>` and the body has a `Result<_, _>` type, we can suggest using `?` ```rust for _ in f() {} // turns into for _ in f()? {} ``` 4. To preserve the original behavior and clear intent, we can suggest using `if let` ```rust for _ in f() {} // turns into if let Some(_) = f() {} ``` (P.S. `Some` and `Ok` are interchangeable depending on the type) I still feel that the lint wording/look is somewhat off, so I'll be happy to hear suggestions (on how to improve suggestions :D)! Resolves #99272 [`clippy::for_loops_over_fallibles`]: https://rust-lang.github.io/rust-clippy/master/index.html#for_loops_over_fallibles
This commit is contained in:
commit
7e16f9f1ea
26 changed files with 381 additions and 366 deletions
|
@ -244,14 +244,12 @@ pub trait Visitor<'ast>: Sized {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! walk_list {
|
macro_rules! walk_list {
|
||||||
($visitor: expr, $method: ident, $list: expr) => {
|
($visitor: expr, $method: ident, $list: expr $(, $($extra_args: expr),* )?) => {
|
||||||
for elem in $list {
|
{
|
||||||
$visitor.$method(elem)
|
#[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
|
||||||
}
|
for elem in $list {
|
||||||
};
|
$visitor.$method(elem $(, $($extra_args,)* )?)
|
||||||
($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
|
}
|
||||||
for elem in $list {
|
|
||||||
$visitor.$method(elem, $($extra_args,)*)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
183
compiler/rustc_lint/src/for_loops_over_fallibles.rs
Normal file
183
compiler/rustc_lint/src/for_loops_over_fallibles.rs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
use crate::{LateContext, LateLintPass, LintContext};
|
||||||
|
|
||||||
|
use hir::{Expr, Pat};
|
||||||
|
use rustc_errors::{Applicability, DelayDm};
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_infer::traits::TraitEngine;
|
||||||
|
use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
|
||||||
|
use rustc_middle::ty::{self, List};
|
||||||
|
use rustc_span::{sym, Span};
|
||||||
|
use rustc_trait_selection::traits::TraitEngineExt;
|
||||||
|
|
||||||
|
declare_lint! {
|
||||||
|
/// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// let opt = Some(1);
|
||||||
|
/// for x in opt { /* ... */}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// {{produces}}
|
||||||
|
///
|
||||||
|
/// ### Explanation
|
||||||
|
///
|
||||||
|
/// Both `Option` and `Result` implement `IntoIterator` trait, which allows using them in a `for` loop.
|
||||||
|
/// `for` loop over `Option` or `Result` will iterate either 0 (if the value is `None`/`Err(_)`)
|
||||||
|
/// or 1 time (if the value is `Some(_)`/`Ok(_)`). This is not very useful and is more clearly expressed
|
||||||
|
/// via `if let`.
|
||||||
|
///
|
||||||
|
/// `for` loop can also be accidentally written with the intention to call a function multiple times,
|
||||||
|
/// while the function returns `Some(_)`, in these cases `while let` loop should be used instead.
|
||||||
|
///
|
||||||
|
/// The "intended" use of `IntoIterator` implementations for `Option` and `Result` is passing them to
|
||||||
|
/// generic code that expects something implementing `IntoIterator`. For example using `.chain(option)`
|
||||||
|
/// to optionally add a value to an iterator.
|
||||||
|
pub FOR_LOOPS_OVER_FALLIBLES,
|
||||||
|
Warn,
|
||||||
|
"for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
|
||||||
|
}
|
||||||
|
|
||||||
|
declare_lint_pass!(ForLoopsOverFallibles => [FOR_LOOPS_OVER_FALLIBLES]);
|
||||||
|
|
||||||
|
impl<'tcx> LateLintPass<'tcx> for ForLoopsOverFallibles {
|
||||||
|
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
||||||
|
let Some((pat, arg)) = extract_for_loop(expr) else { return };
|
||||||
|
|
||||||
|
let ty = cx.typeck_results().expr_ty(arg);
|
||||||
|
|
||||||
|
let &ty::Adt(adt, substs) = ty.kind() else { return };
|
||||||
|
|
||||||
|
let (article, ty, var) = match adt.did() {
|
||||||
|
did if cx.tcx.is_diagnostic_item(sym::Option, did) => ("an", "Option", "Some"),
|
||||||
|
did if cx.tcx.is_diagnostic_item(sym::Result, did) => ("a", "Result", "Ok"),
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = DelayDm(|| {
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
lint.span_suggestion(
|
||||||
|
recv.span.between(arg.span.shrink_to_hi()),
|
||||||
|
format!("to iterate over `{recv_snip}` remove the call to `next`"),
|
||||||
|
".by_ref()",
|
||||||
|
Applicability::MaybeIncorrect
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
lint.multipart_suggestion_verbose(
|
||||||
|
format!("to check pattern in a loop use `while let`"),
|
||||||
|
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!("while let {var}(")),
|
||||||
|
(pat.span.between(arg.span), format!(") = ")),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if suggest_question_mark(cx, adt, substs, expr.span) {
|
||||||
|
lint.span_suggestion(
|
||||||
|
arg.span.shrink_to_hi(),
|
||||||
|
"consider unwrapping the `Result` with `?` to iterate over its contents",
|
||||||
|
"?",
|
||||||
|
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), format!(") = ")),
|
||||||
|
],
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_for_loop<'tcx>(expr: &Expr<'tcx>) -> Option<(&'tcx Pat<'tcx>, &'tcx Expr<'tcx>)> {
|
||||||
|
if let hir::ExprKind::DropTemps(e) = expr.kind
|
||||||
|
&& let hir::ExprKind::Match(iterexpr, [arm], hir::MatchSource::ForLoopDesugar) = e.kind
|
||||||
|
&& let hir::ExprKind::Call(_, [arg]) = iterexpr.kind
|
||||||
|
&& let hir::ExprKind::Loop(block, ..) = arm.body.kind
|
||||||
|
&& let [stmt] = block.stmts
|
||||||
|
&& let hir::StmtKind::Expr(e) = stmt.kind
|
||||||
|
&& let hir::ExprKind::Match(_, [_, some_arm], _) = e.kind
|
||||||
|
&& let hir::PatKind::Struct(_, [field], _) = some_arm.pat.kind
|
||||||
|
{
|
||||||
|
Some((field.pat, arg))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_iterator_next_call<'tcx>(
|
||||||
|
cx: &LateContext<'_>,
|
||||||
|
expr: &Expr<'tcx>,
|
||||||
|
) -> Option<&'tcx Expr<'tcx>> {
|
||||||
|
// This won't work for `Iterator::next(iter)`, is this an issue?
|
||||||
|
if let hir::ExprKind::MethodCall(_, recv, _, _) = expr.kind
|
||||||
|
&& cx.typeck_results().type_dependent_def_id(expr.hir_id) == cx.tcx.lang_items().next_fn()
|
||||||
|
{
|
||||||
|
Some(recv)
|
||||||
|
} else {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn suggest_question_mark<'tcx>(
|
||||||
|
cx: &LateContext<'tcx>,
|
||||||
|
adt: ty::AdtDef<'tcx>,
|
||||||
|
substs: &List<ty::GenericArg<'tcx>>,
|
||||||
|
span: Span,
|
||||||
|
) -> bool {
|
||||||
|
let Some(body_id) = cx.enclosing_body else { return false };
|
||||||
|
let Some(into_iterator_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else { return false };
|
||||||
|
|
||||||
|
if !cx.tcx.is_diagnostic_item(sym::Result, adt.did()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the function/closure/constant we are in has a `Result` type.
|
||||||
|
// Otherwise suggesting using `?` may not be a good idea.
|
||||||
|
{
|
||||||
|
let ty = cx.typeck_results().expr_ty(&cx.tcx.hir().body(body_id).value);
|
||||||
|
let ty::Adt(ret_adt, ..) = ty.kind() else { return false };
|
||||||
|
if !cx.tcx.is_diagnostic_item(sym::Result, ret_adt.did()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = substs.type_at(0);
|
||||||
|
let infcx = cx.tcx.infer_ctxt().build();
|
||||||
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
||||||
|
|
||||||
|
let cause = ObligationCause::new(
|
||||||
|
span,
|
||||||
|
body_id.hir_id,
|
||||||
|
rustc_infer::traits::ObligationCauseCode::MiscObligation,
|
||||||
|
);
|
||||||
|
fulfill_cx.register_bound(
|
||||||
|
&infcx,
|
||||||
|
ty::ParamEnv::empty(),
|
||||||
|
// Erase any region vids from the type, which may not be resolved
|
||||||
|
infcx.tcx.erase_regions(ty),
|
||||||
|
into_iterator_did,
|
||||||
|
cause,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Select all, including ambiguous predicates
|
||||||
|
let errors = fulfill_cx.select_all_or_error(&infcx);
|
||||||
|
|
||||||
|
errors.is_empty()
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ mod early;
|
||||||
mod enum_intrinsics_non_enums;
|
mod enum_intrinsics_non_enums;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod expect;
|
mod expect;
|
||||||
|
mod for_loops_over_fallibles;
|
||||||
pub mod hidden_unicode_codepoints;
|
pub mod hidden_unicode_codepoints;
|
||||||
mod internal;
|
mod internal;
|
||||||
mod late;
|
mod late;
|
||||||
|
@ -86,6 +87,7 @@ use rustc_span::Span;
|
||||||
use array_into_iter::ArrayIntoIter;
|
use array_into_iter::ArrayIntoIter;
|
||||||
use builtin::*;
|
use builtin::*;
|
||||||
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
|
||||||
|
use for_loops_over_fallibles::*;
|
||||||
use hidden_unicode_codepoints::*;
|
use hidden_unicode_codepoints::*;
|
||||||
use internal::*;
|
use internal::*;
|
||||||
use let_underscore::*;
|
use let_underscore::*;
|
||||||
|
@ -188,6 +190,7 @@ macro_rules! late_lint_mod_passes {
|
||||||
$macro!(
|
$macro!(
|
||||||
$args,
|
$args,
|
||||||
[
|
[
|
||||||
|
ForLoopsOverFallibles: ForLoopsOverFallibles,
|
||||||
HardwiredLints: HardwiredLints,
|
HardwiredLints: HardwiredLints,
|
||||||
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
|
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
|
||||||
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
|
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
|
||||||
|
|
|
@ -57,6 +57,7 @@ fn test_get_resource() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg_attr(not(bootstrap), allow(for_loops_over_fallibles))]
|
||||||
fn test_option_dance() {
|
fn test_option_dance() {
|
||||||
let x = Some(());
|
let x = Some(());
|
||||||
let mut y = Some(5);
|
let mut y = Some(5);
|
||||||
|
|
|
@ -1017,7 +1017,7 @@ impl<'a> Children<'a> for HM<'a> {
|
||||||
where C: Context + PrePost<Self>, Self: Sized
|
where C: Context + PrePost<Self>, Self: Sized
|
||||||
{
|
{
|
||||||
if let Some(ref hm) = self.contents.get() {
|
if let Some(ref hm) = self.contents.get() {
|
||||||
for (k, v) in hm.iter().nth(index / 2) {
|
if let Some((k, v)) = hm.iter().nth(index / 2) {
|
||||||
[k, v][index % 2].descend_into_self(context);
|
[k, v][index % 2].descend_into_self(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1032,7 +1032,7 @@ impl<'a> Children<'a> for VD<'a> {
|
||||||
where C: Context + PrePost<Self>, Self: Sized
|
where C: Context + PrePost<Self>, Self: Sized
|
||||||
{
|
{
|
||||||
if let Some(ref vd) = self.contents.get() {
|
if let Some(ref vd) = self.contents.get() {
|
||||||
for r in vd.iter().nth(index) {
|
if let Some(r) = vd.iter().nth(index) {
|
||||||
r.descend_into_self(context);
|
r.descend_into_self(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1047,7 +1047,7 @@ impl<'a> Children<'a> for VM<'a> {
|
||||||
where C: Context + PrePost<VM<'a>>
|
where C: Context + PrePost<VM<'a>>
|
||||||
{
|
{
|
||||||
if let Some(ref vd) = self.contents.get() {
|
if let Some(ref vd) = self.contents.get() {
|
||||||
for (_idx, r) in vd.iter().nth(index) {
|
if let Some((_idx, r)) = vd.iter().nth(index) {
|
||||||
r.descend_into_self(context);
|
r.descend_into_self(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1062,7 +1062,7 @@ impl<'a> Children<'a> for LL<'a> {
|
||||||
where C: Context + PrePost<LL<'a>>
|
where C: Context + PrePost<LL<'a>>
|
||||||
{
|
{
|
||||||
if let Some(ref ll) = self.contents.get() {
|
if let Some(ref ll) = self.contents.get() {
|
||||||
for r in ll.iter().nth(index) {
|
if let Some(r) = ll.iter().nth(index) {
|
||||||
r.descend_into_self(context);
|
r.descend_into_self(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1077,7 +1077,7 @@ impl<'a> Children<'a> for BH<'a> {
|
||||||
where C: Context + PrePost<BH<'a>>
|
where C: Context + PrePost<BH<'a>>
|
||||||
{
|
{
|
||||||
if let Some(ref bh) = self.contents.get() {
|
if let Some(ref bh) = self.contents.get() {
|
||||||
for r in bh.iter().nth(index) {
|
if let Some(r) = bh.iter().nth(index) {
|
||||||
r.descend_into_self(context);
|
r.descend_into_self(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1092,7 +1092,7 @@ impl<'a> Children<'a> for BTM<'a> {
|
||||||
where C: Context + PrePost<BTM<'a>>
|
where C: Context + PrePost<BTM<'a>>
|
||||||
{
|
{
|
||||||
if let Some(ref bh) = self.contents.get() {
|
if let Some(ref bh) = self.contents.get() {
|
||||||
for (k, v) in bh.iter().nth(index / 2) {
|
if let Some((k, v)) = bh.iter().nth(index / 2) {
|
||||||
[k, v][index % 2].descend_into_self(context);
|
[k, v][index % 2].descend_into_self(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1107,7 +1107,7 @@ impl<'a> Children<'a> for BTS<'a> {
|
||||||
where C: Context + PrePost<BTS<'a>>
|
where C: Context + PrePost<BTS<'a>>
|
||||||
{
|
{
|
||||||
if let Some(ref bh) = self.contents.get() {
|
if let Some(ref bh) = self.contents.get() {
|
||||||
for r in bh.iter().nth(index) {
|
if let Some(r) = bh.iter().nth(index) {
|
||||||
r.descend_into_self(context);
|
r.descend_into_self(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// run-pass
|
// run-pass
|
||||||
#![allow(unreachable_code)]
|
#![allow(unreachable_code)]
|
||||||
|
#![allow(for_loops_over_fallibles)]
|
||||||
#![deny(unused_variables)]
|
#![deny(unused_variables)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
43
src/test/ui/lint/for_loop_over_fallibles.rs
Normal file
43
src/test/ui/lint/for_loop_over_fallibles.rs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
// Common
|
||||||
|
for _ in Some(1) {}
|
||||||
|
//~^ WARN for loop over an `Option`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
for _ in Ok::<_, ()>(1) {}
|
||||||
|
//~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
|
||||||
|
// `Iterator::next` specific
|
||||||
|
for _ in [0; 0].iter().next() {}
|
||||||
|
//~^ WARN for loop over an `Option`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to iterate over `[0; 0].iter()` remove the call to `next`
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
|
||||||
|
// `Result<impl Iterator, _>`, but function doesn't return `Result`
|
||||||
|
for _ in Ok::<_, ()>([0; 0].iter()) {}
|
||||||
|
//~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
}
|
||||||
|
|
||||||
|
fn _returns_result() -> Result<(), ()> {
|
||||||
|
// `Result<impl Iterator, _>`
|
||||||
|
for _ in Ok::<_, ()>([0; 0].iter()) {}
|
||||||
|
//~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider unwrapping the `Result` with `?` to iterate over its contents
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
|
||||||
|
// `Result<impl IntoIterator>`
|
||||||
|
for _ in Ok::<_, ()>([0; 0]) {}
|
||||||
|
//~^ WARN for loop over a `Result`. This is more readably written as an `if let` statement
|
||||||
|
//~| HELP to check pattern in a loop use `while let`
|
||||||
|
//~| HELP consider unwrapping the `Result` with `?` to iterate over its contents
|
||||||
|
//~| HELP consider using `if let` to clear intent
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
101
src/test/ui/lint/for_loop_over_fallibles.stderr
Normal file
101
src/test/ui/lint/for_loop_over_fallibles.stderr
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
warning: for loop over an `Option`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:5:14
|
||||||
|
|
|
||||||
|
LL | for _ in Some(1) {}
|
||||||
|
| ^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(for_loops_over_fallibles)]` on by default
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Some(_) = Some(1) {}
|
||||||
|
| ~~~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Some(_) = Some(1) {}
|
||||||
|
| ~~~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: for loop over a `Result`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:9:14
|
||||||
|
|
|
||||||
|
LL | for _ in Ok::<_, ()>(1) {}
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Ok(_) = Ok::<_, ()>(1) {}
|
||||||
|
| ~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Ok(_) = Ok::<_, ()>(1) {}
|
||||||
|
| ~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: for loop over an `Option`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:15:14
|
||||||
|
|
|
||||||
|
LL | for _ in [0; 0].iter().next() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to iterate over `[0; 0].iter()` remove the call to `next`
|
||||||
|
|
|
||||||
|
LL | for _ in [0; 0].iter().by_ref() {}
|
||||||
|
| ~~~~~~~~~
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Some(_) = [0; 0].iter().next() {}
|
||||||
|
| ~~~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: for loop over a `Result`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:21:14
|
||||||
|
|
|
||||||
|
LL | for _ in Ok::<_, ()>([0; 0].iter()) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
|
||||||
|
| ~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
|
||||||
|
| ~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: for loop over a `Result`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:29:14
|
||||||
|
|
|
||||||
|
LL | for _ in Ok::<_, ()>([0; 0].iter()) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
|
||||||
|
| ~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider unwrapping the `Result` with `?` to iterate over its contents
|
||||||
|
|
|
||||||
|
LL | for _ in Ok::<_, ()>([0; 0].iter())? {}
|
||||||
|
| +
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Ok(_) = Ok::<_, ()>([0; 0].iter()) {}
|
||||||
|
| ~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: for loop over a `Result`. This is more readably written as an `if let` statement
|
||||||
|
--> $DIR/for_loop_over_fallibles.rs:36:14
|
||||||
|
|
|
||||||
|
LL | for _ in Ok::<_, ()>([0; 0]) {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
help: to check pattern in a loop use `while let`
|
||||||
|
|
|
||||||
|
LL | while let Ok(_) = Ok::<_, ()>([0; 0]) {}
|
||||||
|
| ~~~~~~~~~~~~~ ~~~
|
||||||
|
help: consider unwrapping the `Result` with `?` to iterate over its contents
|
||||||
|
|
|
||||||
|
LL | for _ in Ok::<_, ()>([0; 0])? {}
|
||||||
|
| +
|
||||||
|
help: consider using `if let` to clear intent
|
||||||
|
|
|
||||||
|
LL | if let Ok(_) = Ok::<_, ()>([0; 0]) {}
|
||||||
|
| ~~~~~~~~~~ ~~~
|
||||||
|
|
||||||
|
warning: 6 warnings emitted
|
||||||
|
|
|
@ -109,7 +109,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
|
||||||
LintId::of(loops::EMPTY_LOOP),
|
LintId::of(loops::EMPTY_LOOP),
|
||||||
LintId::of(loops::EXPLICIT_COUNTER_LOOP),
|
LintId::of(loops::EXPLICIT_COUNTER_LOOP),
|
||||||
LintId::of(loops::FOR_KV_MAP),
|
LintId::of(loops::FOR_KV_MAP),
|
||||||
LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
|
|
||||||
LintId::of(loops::ITER_NEXT_LOOP),
|
LintId::of(loops::ITER_NEXT_LOOP),
|
||||||
LintId::of(loops::MANUAL_FIND),
|
LintId::of(loops::MANUAL_FIND),
|
||||||
LintId::of(loops::MANUAL_FLATTEN),
|
LintId::of(loops::MANUAL_FLATTEN),
|
||||||
|
|
|
@ -227,7 +227,6 @@ store.register_lints(&[
|
||||||
loops::EXPLICIT_INTO_ITER_LOOP,
|
loops::EXPLICIT_INTO_ITER_LOOP,
|
||||||
loops::EXPLICIT_ITER_LOOP,
|
loops::EXPLICIT_ITER_LOOP,
|
||||||
loops::FOR_KV_MAP,
|
loops::FOR_KV_MAP,
|
||||||
loops::FOR_LOOPS_OVER_FALLIBLES,
|
|
||||||
loops::ITER_NEXT_LOOP,
|
loops::ITER_NEXT_LOOP,
|
||||||
loops::MANUAL_FIND,
|
loops::MANUAL_FIND,
|
||||||
loops::MANUAL_FLATTEN,
|
loops::MANUAL_FLATTEN,
|
||||||
|
|
|
@ -21,7 +21,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
|
||||||
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
|
LintId::of(formatting::SUSPICIOUS_ELSE_FORMATTING),
|
||||||
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
LintId::of(formatting::SUSPICIOUS_UNARY_OP_FORMATTING),
|
||||||
LintId::of(loops::EMPTY_LOOP),
|
LintId::of(loops::EMPTY_LOOP),
|
||||||
LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
|
|
||||||
LintId::of(loops::MUT_RANGE_BOUND),
|
LintId::of(loops::MUT_RANGE_BOUND),
|
||||||
LintId::of(methods::NO_EFFECT_REPLACE),
|
LintId::of(methods::NO_EFFECT_REPLACE),
|
||||||
LintId::of(methods::SUSPICIOUS_MAP),
|
LintId::of(methods::SUSPICIOUS_MAP),
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
use super::FOR_LOOPS_OVER_FALLIBLES;
|
|
||||||
use clippy_utils::diagnostics::span_lint_and_help;
|
|
||||||
use clippy_utils::source::snippet;
|
|
||||||
use clippy_utils::ty::is_type_diagnostic_item;
|
|
||||||
use rustc_hir::{Expr, Pat};
|
|
||||||
use rustc_lint::LateContext;
|
|
||||||
use rustc_span::symbol::sym;
|
|
||||||
|
|
||||||
/// Checks for `for` loops over `Option`s and `Result`s.
|
|
||||||
pub(super) fn check(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>, method_name: Option<&str>) {
|
|
||||||
let ty = cx.typeck_results().expr_ty(arg);
|
|
||||||
if is_type_diagnostic_item(cx, ty, sym::Option) {
|
|
||||||
let help_string = if let Some(method_name) = method_name {
|
|
||||||
format!(
|
|
||||||
"consider replacing `for {0} in {1}.{method_name}()` with `if let Some({0}) = {1}`",
|
|
||||||
snippet(cx, pat.span, "_"),
|
|
||||||
snippet(cx, arg.span, "_")
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"consider replacing `for {0} in {1}` with `if let Some({0}) = {1}`",
|
|
||||||
snippet(cx, pat.span, "_"),
|
|
||||||
snippet(cx, arg.span, "_")
|
|
||||||
)
|
|
||||||
};
|
|
||||||
span_lint_and_help(
|
|
||||||
cx,
|
|
||||||
FOR_LOOPS_OVER_FALLIBLES,
|
|
||||||
arg.span,
|
|
||||||
&format!(
|
|
||||||
"for loop over `{0}`, which is an `Option`. This is more readably written as an \
|
|
||||||
`if let` statement",
|
|
||||||
snippet(cx, arg.span, "_")
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
&help_string,
|
|
||||||
);
|
|
||||||
} else if is_type_diagnostic_item(cx, ty, sym::Result) {
|
|
||||||
let help_string = if let Some(method_name) = method_name {
|
|
||||||
format!(
|
|
||||||
"consider replacing `for {0} in {1}.{method_name}()` with `if let Ok({0}) = {1}`",
|
|
||||||
snippet(cx, pat.span, "_"),
|
|
||||||
snippet(cx, arg.span, "_")
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"consider replacing `for {0} in {1}` with `if let Ok({0}) = {1}`",
|
|
||||||
snippet(cx, pat.span, "_"),
|
|
||||||
snippet(cx, arg.span, "_")
|
|
||||||
)
|
|
||||||
};
|
|
||||||
span_lint_and_help(
|
|
||||||
cx,
|
|
||||||
FOR_LOOPS_OVER_FALLIBLES,
|
|
||||||
arg.span,
|
|
||||||
&format!(
|
|
||||||
"for loop over `{0}`, which is a `Result`. This is more readably written as an \
|
|
||||||
`if let` statement",
|
|
||||||
snippet(cx, arg.span, "_")
|
|
||||||
),
|
|
||||||
None,
|
|
||||||
&help_string,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ use rustc_hir::Expr;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
|
||||||
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
|
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) {
|
||||||
if is_trait_method(cx, arg, sym::Iterator) {
|
if is_trait_method(cx, arg, sym::Iterator) {
|
||||||
span_lint(
|
span_lint(
|
||||||
cx,
|
cx,
|
||||||
|
@ -14,8 +14,5 @@ pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
|
||||||
"you are iterating over `Iterator::next()` which is an Option; this will compile but is \
|
"you are iterating over `Iterator::next()` which is an Option; this will compile but is \
|
||||||
probably not what you want",
|
probably not what you want",
|
||||||
);
|
);
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ mod explicit_counter_loop;
|
||||||
mod explicit_into_iter_loop;
|
mod explicit_into_iter_loop;
|
||||||
mod explicit_iter_loop;
|
mod explicit_iter_loop;
|
||||||
mod for_kv_map;
|
mod for_kv_map;
|
||||||
mod for_loops_over_fallibles;
|
|
||||||
mod iter_next_loop;
|
mod iter_next_loop;
|
||||||
mod manual_find;
|
mod manual_find;
|
||||||
mod manual_flatten;
|
mod manual_flatten;
|
||||||
|
@ -173,49 +172,6 @@ declare_clippy_lint! {
|
||||||
"for-looping over `_.next()` which is probably not intended"
|
"for-looping over `_.next()` which is probably not intended"
|
||||||
}
|
}
|
||||||
|
|
||||||
declare_clippy_lint! {
|
|
||||||
/// ### What it does
|
|
||||||
/// Checks for `for` loops over `Option` or `Result` values.
|
|
||||||
///
|
|
||||||
/// ### Why is this bad?
|
|
||||||
/// Readability. This is more clearly expressed as an `if
|
|
||||||
/// let`.
|
|
||||||
///
|
|
||||||
/// ### Example
|
|
||||||
/// ```rust
|
|
||||||
/// # let opt = Some(1);
|
|
||||||
/// # let res: Result<i32, std::io::Error> = Ok(1);
|
|
||||||
/// for x in opt {
|
|
||||||
/// // ..
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// for x in &res {
|
|
||||||
/// // ..
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// for x in res.iter() {
|
|
||||||
/// // ..
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Use instead:
|
|
||||||
/// ```rust
|
|
||||||
/// # let opt = Some(1);
|
|
||||||
/// # let res: Result<i32, std::io::Error> = Ok(1);
|
|
||||||
/// if let Some(x) = opt {
|
|
||||||
/// // ..
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// if let Ok(x) = res {
|
|
||||||
/// // ..
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[clippy::version = "1.45.0"]
|
|
||||||
pub FOR_LOOPS_OVER_FALLIBLES,
|
|
||||||
suspicious,
|
|
||||||
"for-looping over an `Option` or a `Result`, which is more clearly expressed as an `if let`"
|
|
||||||
}
|
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
/// Detects `loop + match` combinations that are easier
|
/// Detects `loop + match` combinations that are easier
|
||||||
|
@ -648,7 +604,6 @@ declare_lint_pass!(Loops => [
|
||||||
EXPLICIT_ITER_LOOP,
|
EXPLICIT_ITER_LOOP,
|
||||||
EXPLICIT_INTO_ITER_LOOP,
|
EXPLICIT_INTO_ITER_LOOP,
|
||||||
ITER_NEXT_LOOP,
|
ITER_NEXT_LOOP,
|
||||||
FOR_LOOPS_OVER_FALLIBLES,
|
|
||||||
WHILE_LET_LOOP,
|
WHILE_LET_LOOP,
|
||||||
NEEDLESS_COLLECT,
|
NEEDLESS_COLLECT,
|
||||||
EXPLICIT_COUNTER_LOOP,
|
EXPLICIT_COUNTER_LOOP,
|
||||||
|
@ -739,30 +694,22 @@ fn check_for_loop<'tcx>(
|
||||||
manual_find::check(cx, pat, arg, body, span, expr);
|
manual_find::check(cx, pat, arg, body, span, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_for_loop_arg(cx: &LateContext<'_>, pat: &Pat<'_>, arg: &Expr<'_>) {
|
fn check_for_loop_arg(cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
|
||||||
let mut next_loop_linted = false; // whether or not ITER_NEXT_LOOP lint was used
|
|
||||||
|
|
||||||
if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
|
if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
|
||||||
let method_name = method.ident.as_str();
|
let method_name = method.ident.as_str();
|
||||||
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
|
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
|
||||||
match method_name {
|
match method_name {
|
||||||
"iter" | "iter_mut" => {
|
"iter" | "iter_mut" => {
|
||||||
explicit_iter_loop::check(cx, self_arg, arg, method_name);
|
explicit_iter_loop::check(cx, self_arg, arg, method_name);
|
||||||
for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
|
|
||||||
},
|
},
|
||||||
"into_iter" => {
|
"into_iter" => {
|
||||||
explicit_iter_loop::check(cx, self_arg, arg, method_name);
|
explicit_iter_loop::check(cx, self_arg, arg, method_name);
|
||||||
explicit_into_iter_loop::check(cx, self_arg, arg);
|
explicit_into_iter_loop::check(cx, self_arg, arg);
|
||||||
for_loops_over_fallibles::check(cx, pat, self_arg, Some(method_name));
|
|
||||||
},
|
},
|
||||||
"next" => {
|
"next" => {
|
||||||
next_loop_linted = iter_next_loop::check(cx, arg);
|
iter_next_loop::check(cx, arg);
|
||||||
},
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !next_loop_linted {
|
|
||||||
for_loops_over_fallibles::check(cx, pat, arg, None);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
|
||||||
("clippy::disallowed_method", "clippy::disallowed_methods"),
|
("clippy::disallowed_method", "clippy::disallowed_methods"),
|
||||||
("clippy::disallowed_type", "clippy::disallowed_types"),
|
("clippy::disallowed_type", "clippy::disallowed_types"),
|
||||||
("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
|
("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),
|
||||||
("clippy::for_loop_over_option", "clippy::for_loops_over_fallibles"),
|
("clippy::for_loop_over_option", "for_loops_over_fallibles"),
|
||||||
("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
|
("clippy::for_loop_over_result", "for_loops_over_fallibles"),
|
||||||
("clippy::identity_conversion", "clippy::useless_conversion"),
|
("clippy::identity_conversion", "clippy::useless_conversion"),
|
||||||
("clippy::if_let_some_result", "clippy::match_result_ok"),
|
("clippy::if_let_some_result", "clippy::match_result_ok"),
|
||||||
("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
|
("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
|
||||||
|
@ -31,6 +31,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
|
||||||
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
|
("clippy::to_string_in_display", "clippy::recursive_format_impl"),
|
||||||
("clippy::zero_width_space", "clippy::invisible_characters"),
|
("clippy::zero_width_space", "clippy::invisible_characters"),
|
||||||
("clippy::drop_bounds", "drop_bounds"),
|
("clippy::drop_bounds", "drop_bounds"),
|
||||||
|
("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"),
|
||||||
("clippy::into_iter_on_array", "array_into_iter"),
|
("clippy::into_iter_on_array", "array_into_iter"),
|
||||||
("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
|
("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"),
|
||||||
("clippy::invalid_ref", "invalid_value"),
|
("clippy::invalid_ref", "invalid_value"),
|
||||||
|
|
|
@ -170,7 +170,6 @@ docs! {
|
||||||
"fn_to_numeric_cast_any",
|
"fn_to_numeric_cast_any",
|
||||||
"fn_to_numeric_cast_with_truncation",
|
"fn_to_numeric_cast_with_truncation",
|
||||||
"for_kv_map",
|
"for_kv_map",
|
||||||
"for_loops_over_fallibles",
|
|
||||||
"forget_copy",
|
"forget_copy",
|
||||||
"forget_non_drop",
|
"forget_non_drop",
|
||||||
"forget_ref",
|
"forget_ref",
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
### What it does
|
|
||||||
Checks for `for` loops over `Option` or `Result` values.
|
|
||||||
|
|
||||||
### Why is this bad?
|
|
||||||
Readability. This is more clearly expressed as an `if
|
|
||||||
let`.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
```
|
|
||||||
for x in opt {
|
|
||||||
// ..
|
|
||||||
}
|
|
||||||
|
|
||||||
for x in &res {
|
|
||||||
// ..
|
|
||||||
}
|
|
||||||
|
|
||||||
for x in res.iter() {
|
|
||||||
// ..
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Use instead:
|
|
||||||
```
|
|
||||||
if let Some(x) = opt {
|
|
||||||
// ..
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(x) = res {
|
|
||||||
// ..
|
|
||||||
}
|
|
||||||
```
|
|
|
@ -8,6 +8,7 @@
|
||||||
clippy::for_kv_map
|
clippy::for_kv_map
|
||||||
)]
|
)]
|
||||||
#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
|
#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
|
||||||
|
#[allow(for_loops_over_fallibles)]
|
||||||
fn main() {
|
fn main() {
|
||||||
let vec = vec![1, 2, 3, 4];
|
let vec = vec![1, 2, 3, 4];
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
|
error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
|
||||||
--> $DIR/for_loop_unfixable.rs:14:15
|
--> $DIR/for_loop_unfixable.rs:15:15
|
||||||
|
|
|
|
||||||
LL | for _v in vec.iter().next() {}
|
LL | for _v in vec.iter().next() {}
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
#![warn(clippy::for_loops_over_fallibles)]
|
|
||||||
#![allow(clippy::uninlined_format_args)]
|
|
||||||
|
|
||||||
fn for_loops_over_fallibles() {
|
|
||||||
let option = Some(1);
|
|
||||||
let mut result = option.ok_or("x not found");
|
|
||||||
let v = vec![0, 1, 2];
|
|
||||||
|
|
||||||
// check over an `Option`
|
|
||||||
for x in option {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check over an `Option`
|
|
||||||
for x in option.iter() {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check over a `Result`
|
|
||||||
for x in result {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check over a `Result`
|
|
||||||
for x in result.iter_mut() {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check over a `Result`
|
|
||||||
for x in result.into_iter() {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
for x in option.ok_or("x not found") {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure LOOP_OVER_NEXT lint takes clippy::precedence when next() is the last call
|
|
||||||
// in the chain
|
|
||||||
for x in v.iter().next() {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure we lint when next() is not the last call in the chain
|
|
||||||
for x in v.iter().next().and(Some(0)) {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
for x in v.iter().next().ok_or("x not found") {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for false positives
|
|
||||||
|
|
||||||
// for loop false positive
|
|
||||||
for x in v {
|
|
||||||
println!("{}", x);
|
|
||||||
}
|
|
||||||
|
|
||||||
// while let false positive for Option
|
|
||||||
while let Some(x) = option {
|
|
||||||
println!("{}", x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// while let false positive for Result
|
|
||||||
while let Ok(x) = result {
|
|
||||||
println!("{}", x);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,95 +0,0 @@
|
||||||
error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:10:14
|
|
||||||
|
|
|
||||||
LL | for x in option {
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider replacing `for x in option` with `if let Some(x) = option`
|
|
||||||
= note: `-D clippy::for-loops-over-fallibles` implied by `-D warnings`
|
|
||||||
|
|
||||||
error: for loop over `option`, which is an `Option`. This is more readably written as an `if let` statement
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:15:14
|
|
||||||
|
|
|
||||||
LL | for x in option.iter() {
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider replacing `for x in option.iter()` with `if let Some(x) = option`
|
|
||||||
|
|
||||||
error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:20:14
|
|
||||||
|
|
|
||||||
LL | for x in result {
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider replacing `for x in result` with `if let Ok(x) = result`
|
|
||||||
|
|
||||||
error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:25:14
|
|
||||||
|
|
|
||||||
LL | for x in result.iter_mut() {
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider replacing `for x in result.iter_mut()` with `if let Ok(x) = result`
|
|
||||||
|
|
||||||
error: for loop over `result`, which is a `Result`. This is more readably written as an `if let` statement
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:30:14
|
|
||||||
|
|
|
||||||
LL | for x in result.into_iter() {
|
|
||||||
| ^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider replacing `for x in result.into_iter()` with `if let Ok(x) = result`
|
|
||||||
|
|
||||||
error: for loop over `option.ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:34:14
|
|
||||||
|
|
|
||||||
LL | for x in option.ok_or("x not found") {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider replacing `for x in option.ok_or("x not found")` with `if let Ok(x) = option.ok_or("x not found")`
|
|
||||||
|
|
||||||
error: you are iterating over `Iterator::next()` which is an Option; this will compile but is probably not what you want
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:40:14
|
|
||||||
|
|
|
||||||
LL | for x in v.iter().next() {
|
|
||||||
| ^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= note: `#[deny(clippy::iter_next_loop)]` on by default
|
|
||||||
|
|
||||||
error: for loop over `v.iter().next().and(Some(0))`, which is an `Option`. This is more readably written as an `if let` statement
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:45:14
|
|
||||||
|
|
|
||||||
LL | for x in v.iter().next().and(Some(0)) {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider replacing `for x in v.iter().next().and(Some(0))` with `if let Some(x) = v.iter().next().and(Some(0))`
|
|
||||||
|
|
||||||
error: for loop over `v.iter().next().ok_or("x not found")`, which is a `Result`. This is more readably written as an `if let` statement
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:49:14
|
|
||||||
|
|
|
||||||
LL | for x in v.iter().next().ok_or("x not found") {
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider replacing `for x in v.iter().next().ok_or("x not found")` with `if let Ok(x) = v.iter().next().ok_or("x not found")`
|
|
||||||
|
|
||||||
error: this loop never actually loops
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:61:5
|
|
||||||
|
|
|
||||||
LL | / while let Some(x) = option {
|
|
||||||
LL | | println!("{}", x);
|
|
||||||
LL | | break;
|
|
||||||
LL | | }
|
|
||||||
| |_____^
|
|
||||||
|
|
|
||||||
= note: `#[deny(clippy::never_loop)]` on by default
|
|
||||||
|
|
||||||
error: this loop never actually loops
|
|
||||||
--> $DIR/for_loops_over_fallibles.rs:67:5
|
|
||||||
|
|
|
||||||
LL | / while let Ok(x) = result {
|
|
||||||
LL | | println!("{}", x);
|
|
||||||
LL | | break;
|
|
||||||
LL | | }
|
|
||||||
| |_____^
|
|
||||||
|
|
||||||
error: aborting due to 11 previous errors
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
clippy::unit_arg,
|
clippy::unit_arg,
|
||||||
clippy::match_ref_pats,
|
clippy::match_ref_pats,
|
||||||
clippy::redundant_pattern_matching,
|
clippy::redundant_pattern_matching,
|
||||||
clippy::for_loops_over_fallibles,
|
for_loops_over_fallibles,
|
||||||
dead_code
|
dead_code
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
clippy::unit_arg,
|
clippy::unit_arg,
|
||||||
clippy::match_ref_pats,
|
clippy::match_ref_pats,
|
||||||
clippy::redundant_pattern_matching,
|
clippy::redundant_pattern_matching,
|
||||||
clippy::for_loops_over_fallibles,
|
for_loops_over_fallibles,
|
||||||
dead_code
|
dead_code
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#![allow(clippy::disallowed_methods)]
|
#![allow(clippy::disallowed_methods)]
|
||||||
#![allow(clippy::disallowed_types)]
|
#![allow(clippy::disallowed_types)]
|
||||||
#![allow(clippy::mixed_read_write_in_expression)]
|
#![allow(clippy::mixed_read_write_in_expression)]
|
||||||
#![allow(clippy::for_loops_over_fallibles)]
|
#![allow(for_loops_over_fallibles)]
|
||||||
#![allow(clippy::useless_conversion)]
|
#![allow(clippy::useless_conversion)]
|
||||||
#![allow(clippy::match_result_ok)]
|
#![allow(clippy::match_result_ok)]
|
||||||
#![allow(clippy::overly_complex_bool_expr)]
|
#![allow(clippy::overly_complex_bool_expr)]
|
||||||
|
@ -45,8 +45,8 @@
|
||||||
#![warn(clippy::disallowed_methods)]
|
#![warn(clippy::disallowed_methods)]
|
||||||
#![warn(clippy::disallowed_types)]
|
#![warn(clippy::disallowed_types)]
|
||||||
#![warn(clippy::mixed_read_write_in_expression)]
|
#![warn(clippy::mixed_read_write_in_expression)]
|
||||||
#![warn(clippy::for_loops_over_fallibles)]
|
#![warn(for_loops_over_fallibles)]
|
||||||
#![warn(clippy::for_loops_over_fallibles)]
|
#![warn(for_loops_over_fallibles)]
|
||||||
#![warn(clippy::useless_conversion)]
|
#![warn(clippy::useless_conversion)]
|
||||||
#![warn(clippy::match_result_ok)]
|
#![warn(clippy::match_result_ok)]
|
||||||
#![warn(clippy::overly_complex_bool_expr)]
|
#![warn(clippy::overly_complex_bool_expr)]
|
||||||
|
@ -65,6 +65,7 @@
|
||||||
#![warn(clippy::recursive_format_impl)]
|
#![warn(clippy::recursive_format_impl)]
|
||||||
#![warn(clippy::invisible_characters)]
|
#![warn(clippy::invisible_characters)]
|
||||||
#![warn(drop_bounds)]
|
#![warn(drop_bounds)]
|
||||||
|
#![warn(for_loops_over_fallibles)]
|
||||||
#![warn(array_into_iter)]
|
#![warn(array_into_iter)]
|
||||||
#![warn(invalid_atomic_ordering)]
|
#![warn(invalid_atomic_ordering)]
|
||||||
#![warn(invalid_value)]
|
#![warn(invalid_value)]
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#![allow(clippy::disallowed_methods)]
|
#![allow(clippy::disallowed_methods)]
|
||||||
#![allow(clippy::disallowed_types)]
|
#![allow(clippy::disallowed_types)]
|
||||||
#![allow(clippy::mixed_read_write_in_expression)]
|
#![allow(clippy::mixed_read_write_in_expression)]
|
||||||
#![allow(clippy::for_loops_over_fallibles)]
|
#![allow(for_loops_over_fallibles)]
|
||||||
#![allow(clippy::useless_conversion)]
|
#![allow(clippy::useless_conversion)]
|
||||||
#![allow(clippy::match_result_ok)]
|
#![allow(clippy::match_result_ok)]
|
||||||
#![allow(clippy::overly_complex_bool_expr)]
|
#![allow(clippy::overly_complex_bool_expr)]
|
||||||
|
@ -65,6 +65,7 @@
|
||||||
#![warn(clippy::to_string_in_display)]
|
#![warn(clippy::to_string_in_display)]
|
||||||
#![warn(clippy::zero_width_space)]
|
#![warn(clippy::zero_width_space)]
|
||||||
#![warn(clippy::drop_bounds)]
|
#![warn(clippy::drop_bounds)]
|
||||||
|
#![warn(clippy::for_loops_over_fallibles)]
|
||||||
#![warn(clippy::into_iter_on_array)]
|
#![warn(clippy::into_iter_on_array)]
|
||||||
#![warn(clippy::invalid_atomic_ordering)]
|
#![warn(clippy::invalid_atomic_ordering)]
|
||||||
#![warn(clippy::invalid_ref)]
|
#![warn(clippy::invalid_ref)]
|
||||||
|
|
|
@ -54,17 +54,17 @@ error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_r
|
||||||
LL | #![warn(clippy::eval_order_dependence)]
|
LL | #![warn(clippy::eval_order_dependence)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
|
||||||
|
|
||||||
error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
|
error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
|
||||||
--> $DIR/rename.rs:48:9
|
--> $DIR/rename.rs:48:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::for_loop_over_option)]
|
LL | #![warn(clippy::for_loop_over_option)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
|
||||||
|
|
||||||
error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
|
error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
|
||||||
--> $DIR/rename.rs:49:9
|
--> $DIR/rename.rs:49:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::for_loop_over_result)]
|
LL | #![warn(clippy::for_loop_over_result)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
|
||||||
|
|
||||||
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
|
error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
|
||||||
--> $DIR/rename.rs:50:9
|
--> $DIR/rename.rs:50:9
|
||||||
|
@ -174,59 +174,65 @@ error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
|
||||||
LL | #![warn(clippy::drop_bounds)]
|
LL | #![warn(clippy::drop_bounds)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
|
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
|
||||||
|
|
||||||
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
|
error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
|
||||||
--> $DIR/rename.rs:68:9
|
--> $DIR/rename.rs:68:9
|
||||||
|
|
|
|
||||||
|
LL | #![warn(clippy::for_loops_over_fallibles)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
|
||||||
|
|
||||||
|
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
|
||||||
|
--> $DIR/rename.rs:69:9
|
||||||
|
|
|
||||||
LL | #![warn(clippy::into_iter_on_array)]
|
LL | #![warn(clippy::into_iter_on_array)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
|
||||||
|
|
||||||
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
|
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
|
||||||
--> $DIR/rename.rs:69:9
|
--> $DIR/rename.rs:70:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::invalid_atomic_ordering)]
|
LL | #![warn(clippy::invalid_atomic_ordering)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
|
||||||
|
|
||||||
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
|
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
|
||||||
--> $DIR/rename.rs:70:9
|
--> $DIR/rename.rs:71:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::invalid_ref)]
|
LL | #![warn(clippy::invalid_ref)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
|
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
|
||||||
|
|
||||||
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
|
error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
|
||||||
--> $DIR/rename.rs:71:9
|
--> $DIR/rename.rs:72:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::mem_discriminant_non_enum)]
|
LL | #![warn(clippy::mem_discriminant_non_enum)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
|
||||||
|
|
||||||
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
|
error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
|
||||||
--> $DIR/rename.rs:72:9
|
--> $DIR/rename.rs:73:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::panic_params)]
|
LL | #![warn(clippy::panic_params)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
|
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
|
||||||
|
|
||||||
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
|
error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally`
|
||||||
--> $DIR/rename.rs:73:9
|
--> $DIR/rename.rs:74:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::positional_named_format_parameters)]
|
LL | #![warn(clippy::positional_named_format_parameters)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally`
|
||||||
|
|
||||||
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
|
error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
|
||||||
--> $DIR/rename.rs:74:9
|
--> $DIR/rename.rs:75:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::temporary_cstring_as_ptr)]
|
LL | #![warn(clippy::temporary_cstring_as_ptr)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
|
||||||
|
|
||||||
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
|
error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
|
||||||
--> $DIR/rename.rs:75:9
|
--> $DIR/rename.rs:76:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::unknown_clippy_lints)]
|
LL | #![warn(clippy::unknown_clippy_lints)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
|
||||||
|
|
||||||
error: lint `clippy::unused_label` has been renamed to `unused_labels`
|
error: lint `clippy::unused_label` has been renamed to `unused_labels`
|
||||||
--> $DIR/rename.rs:76:9
|
--> $DIR/rename.rs:77:9
|
||||||
|
|
|
|
||||||
LL | #![warn(clippy::unused_label)]
|
LL | #![warn(clippy::unused_label)]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
|
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
|
||||||
|
|
||||||
error: aborting due to 38 previous errors
|
error: aborting due to 39 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue