Auto merge of #5583 - ebroto:reversed_empty_ranges, r=yaahc,flip1995

Reversed empty ranges

This lint checks range expressions with inverted limits which result in empty ranges. This includes also the ranges used to index slices.

The lint reverse_range_loop was covering iteration of reversed ranges in a for loop, which is a subset of what this new lint covers, so it has been removed. I'm not sure if that's the best choice. It would be doable to check in the new lint that we are not in the arguments of a for loop; I went for removing it because the logic was too similar to keep them separated.

changelog: Added reversed_empty_ranges lint that checks for ranges where the limits have been inverted, resulting in empty ranges. Removed reverse_range_loop which was covering a subset of the new lint.

Closes #4192
Closes #96
This commit is contained in:
bors 2020-05-14 12:59:24 +00:00
commit e1842b0cac
21 changed files with 500 additions and 313 deletions

View File

@ -1545,7 +1545,7 @@ Released 2018-09-13
[`result_map_unit_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unit_fn
[`result_map_unwrap_or_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_map_unwrap_or_else
[`result_unwrap_used`]: https://rust-lang.github.io/rust-clippy/master/index.html#result_unwrap_used
[`reverse_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#reverse_range_loop
[`reversed_empty_ranges`]: https://rust-lang.github.io/rust-clippy/master/index.html#reversed_empty_ranges
[`same_functions_in_if_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#same_functions_in_if_condition
[`search_is_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#search_is_some
[`serde_api_misuse`]: https://rust-lang.github.io/rust-clippy/master/index.html#serde_api_misuse

View File

@ -624,7 +624,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&loops::NEEDLESS_COLLECT,
&loops::NEEDLESS_RANGE_LOOP,
&loops::NEVER_LOOP,
&loops::REVERSE_RANGE_LOOP,
&loops::WHILE_IMMUTABLE_CONDITION,
&loops::WHILE_LET_LOOP,
&loops::WHILE_LET_ON_ITERATOR,
@ -770,6 +769,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&ranges::RANGE_MINUS_ONE,
&ranges::RANGE_PLUS_ONE,
&ranges::RANGE_ZIP_WITH_LEN,
&ranges::REVERSED_EMPTY_RANGES,
&redundant_clone::REDUNDANT_CLONE,
&redundant_field_names::REDUNDANT_FIELD_NAMES,
&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING,
@ -1283,7 +1283,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&loops::NEEDLESS_COLLECT),
LintId::of(&loops::NEEDLESS_RANGE_LOOP),
LintId::of(&loops::NEVER_LOOP),
LintId::of(&loops::REVERSE_RANGE_LOOP),
LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
LintId::of(&loops::WHILE_LET_LOOP),
LintId::of(&loops::WHILE_LET_ON_ITERATOR),
@ -1384,6 +1383,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&question_mark::QUESTION_MARK),
LintId::of(&ranges::RANGE_MINUS_ONE),
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
LintId::of(&redundant_clone::REDUNDANT_CLONE),
LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
LintId::of(&redundant_pattern_matching::REDUNDANT_PATTERN_MATCHING),
@ -1656,7 +1656,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&loops::FOR_LOOP_OVER_RESULT),
LintId::of(&loops::ITER_NEXT_LOOP),
LintId::of(&loops::NEVER_LOOP),
LintId::of(&loops::REVERSE_RANGE_LOOP),
LintId::of(&loops::WHILE_IMMUTABLE_CONDITION),
LintId::of(&mem_discriminant::MEM_DISCRIMINANT_NON_ENUM),
LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
@ -1675,6 +1674,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&open_options::NONSENSICAL_OPEN_OPTIONS),
LintId::of(&option_env_unwrap::OPTION_ENV_UNWRAP),
LintId::of(&ptr::MUT_FROM_REF),
LintId::of(&ranges::REVERSED_EMPTY_RANGES),
LintId::of(&regex::INVALID_REGEX),
LintId::of(&serde_api::SERDE_API_MISUSE),
LintId::of(&suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
@ -1785,6 +1785,10 @@ fn register_removed_non_tool_lints(store: &mut rustc_lint::LintStore) {
"unsafe_vector_initialization",
"the replacement suggested by this lint had substantially different behavior",
);
store.register_removed(
"reverse_range_loop",
"this lint is now included in reversed_empty_ranges",
);
}
/// Register renamed lints.

View File

@ -1,4 +1,4 @@
use crate::consts::{constant, Constant};
use crate::consts::constant;
use crate::reexport::Name;
use crate::utils::paths;
use crate::utils::usage::{is_unused, mutated_variables};
@ -8,7 +8,7 @@
multispan_sugg, snippet, snippet_opt, snippet_with_applicability, span_lint, span_lint_and_help,
span_lint_and_sugg, span_lint_and_then, SpanlessEq,
};
use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sext, sugg};
use crate::utils::{is_type_diagnostic_item, qpath_res, same_tys, sugg};
use if_chain::if_chain;
use rustc_ast::ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@ -270,30 +270,6 @@
"collecting an iterator when collect is not needed"
}
declare_clippy_lint! {
/// **What it does:** Checks for loops over ranges `x..y` where both `x` and `y`
/// are constant and `x` is greater or equal to `y`, unless the range is
/// reversed or has a negative `.step_by(_)`.
///
/// **Why is it bad?** Such loops will either be skipped or loop until
/// wrap-around (in debug code, this may `panic!()`). Both options are probably
/// not intended.
///
/// **Known problems:** The lint cannot catch loops over dynamically defined
/// ranges. Doing this would require simulating all possible inputs and code
/// paths through the program, which would be complex and error-prone.
///
/// **Example:**
/// ```ignore
/// for x in 5..10 - 5 {
/// ..
/// } // oops, stray `-`
/// ```
pub REVERSE_RANGE_LOOP,
correctness,
"iteration over an empty range, such as `10..0` or `5..5`"
}
declare_clippy_lint! {
/// **What it does:** Checks `for` loops over slices with an explicit counter
/// and suggests the use of `.enumerate()`.
@ -463,7 +439,6 @@
FOR_LOOP_OVER_OPTION,
WHILE_LET_LOOP,
NEEDLESS_COLLECT,
REVERSE_RANGE_LOOP,
EXPLICIT_COUNTER_LOOP,
EMPTY_LOOP,
WHILE_LET_ON_ITERATOR,
@ -761,7 +736,6 @@ fn check_for_loop<'a, 'tcx>(
expr: &'tcx Expr<'_>,
) {
check_for_loop_range(cx, pat, arg, body, expr);
check_for_loop_reverse_range(cx, arg, expr);
check_for_loop_arg(cx, pat, arg, expr);
check_for_loop_explicit_counter(cx, pat, arg, body, expr);
check_for_loop_over_map_kv(cx, pat, arg, body, expr);
@ -1248,78 +1222,6 @@ fn is_end_eq_array_len<'tcx>(
false
}
fn check_for_loop_reverse_range<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, arg: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
// if this for loop is iterating over a two-sided range...
if let Some(higher::Range {
start: Some(start),
end: Some(end),
limits,
}) = higher::range(cx, arg)
{
// ...and both sides are compile-time constant integers...
if let Some((start_idx, _)) = constant(cx, cx.tables, start) {
if let Some((end_idx, _)) = constant(cx, cx.tables, end) {
// ...and the start index is greater than the end index,
// this loop will never run. This is often confusing for developers
// who think that this will iterate from the larger value to the
// smaller value.
let ty = cx.tables.expr_ty(start);
let (sup, eq) = match (start_idx, end_idx) {
(Constant::Int(start_idx), Constant::Int(end_idx)) => (
match ty.kind {
ty::Int(ity) => sext(cx.tcx, start_idx, ity) > sext(cx.tcx, end_idx, ity),
ty::Uint(_) => start_idx > end_idx,
_ => false,
},
start_idx == end_idx,
),
_ => (false, false),
};
if sup {
let start_snippet = snippet(cx, start.span, "_");
let end_snippet = snippet(cx, end.span, "_");
let dots = if limits == ast::RangeLimits::Closed {
"..="
} else {
".."
};
span_lint_and_then(
cx,
REVERSE_RANGE_LOOP,
expr.span,
"this range is empty so this for loop will never run",
|diag| {
diag.span_suggestion(
arg.span,
"consider using the following if you are attempting to iterate over this \
range in reverse",
format!(
"({end}{dots}{start}).rev()",
end = end_snippet,
dots = dots,
start = start_snippet
),
Applicability::MaybeIncorrect,
);
},
);
} else if eq && limits != ast::RangeLimits::Closed {
// if they are equal, it's also problematic - this loop
// will never run.
span_lint(
cx,
REVERSE_RANGE_LOOP,
expr.span,
"this range is empty so this for loop will never run",
);
}
}
}
}
}
fn lint_iter_method(cx: &LateContext<'_, '_>, args: &[Expr<'_>], arg: &Expr<'_>, method_name: &str) {
let mut applicability = Applicability::MachineApplicable;
let object = snippet_with_applicability(cx, args[0].span, "_", &mut applicability);

View File

@ -1,14 +1,17 @@
use crate::consts::{constant, Constant};
use if_chain::if_chain;
use rustc_ast::ast::RangeLimits;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Spanned;
use std::cmp::Ordering;
use crate::utils::sugg::Sugg;
use crate::utils::{get_parent_expr, is_integer_const, snippet, snippet_opt, span_lint, span_lint_and_then};
use crate::utils::{higher, SpanlessEq};
use crate::utils::{is_integer_const, snippet, snippet_opt, span_lint, span_lint_and_then};
declare_clippy_lint! {
/// **What it does:** Checks for zipping a collection with the range of
@ -84,10 +87,44 @@
"`x..=(y-1)` reads better as `x..y`"
}
declare_clippy_lint! {
/// **What it does:** Checks for range expressions `x..y` where both `x` and `y`
/// are constant and `x` is greater or equal to `y`.
///
/// **Why is this bad?** Empty ranges yield no values so iterating them is a no-op.
/// Moreover, trying to use a reversed range to index a slice will panic at run-time.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust,no_run
/// fn main() {
/// (10..=0).for_each(|x| println!("{}", x));
///
/// let arr = [1, 2, 3, 4, 5];
/// let sub = &arr[3..1];
/// }
/// ```
/// Use instead:
/// ```rust
/// fn main() {
/// (0..=10).rev().for_each(|x| println!("{}", x));
///
/// let arr = [1, 2, 3, 4, 5];
/// let sub = &arr[1..3];
/// }
/// ```
pub REVERSED_EMPTY_RANGES,
correctness,
"reversing the limits of range expressions, resulting in empty ranges"
}
declare_lint_pass!(Ranges => [
RANGE_ZIP_WITH_LEN,
RANGE_PLUS_ONE,
RANGE_MINUS_ONE
RANGE_MINUS_ONE,
REVERSED_EMPTY_RANGES,
]);
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Ranges {
@ -124,6 +161,7 @@ fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr<'_>) {
check_exclusive_range_plus_one(cx, expr);
check_inclusive_range_minus_one(cx, expr);
check_reversed_empty_range(cx, expr);
}
}
@ -202,6 +240,76 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
}
}
fn check_reversed_empty_range(cx: &LateContext<'_, '_>, expr: &Expr<'_>) {
fn inside_indexing_expr(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
matches!(
get_parent_expr(cx, expr),
Some(Expr {
kind: ExprKind::Index(..),
..
})
)
}
fn is_empty_range(limits: RangeLimits, ordering: Ordering) -> bool {
match limits {
RangeLimits::HalfOpen => ordering != Ordering::Less,
RangeLimits::Closed => ordering == Ordering::Greater,
}
}
if_chain! {
if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::range(cx, expr);
let ty = cx.tables.expr_ty(start);
if let ty::Int(_) | ty::Uint(_) = ty.kind;
if let Some((start_idx, _)) = constant(cx, cx.tables, start);
if let Some((end_idx, _)) = constant(cx, cx.tables, end);
if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx);
if is_empty_range(limits, ordering);
then {
if inside_indexing_expr(cx, expr) {
let (reason, outcome) = if ordering == Ordering::Equal {
("empty", "always yield an empty slice")
} else {
("reversed", "panic at run-time")
};
span_lint(
cx,
REVERSED_EMPTY_RANGES,
expr.span,
&format!("this range is {} and using it to index a slice will {}", reason, outcome),
);
} else {
span_lint_and_then(
cx,
REVERSED_EMPTY_RANGES,
expr.span,
"this range is empty so it will yield no values",
|diag| {
if ordering != Ordering::Equal {
let start_snippet = snippet(cx, start.span, "_");
let end_snippet = snippet(cx, end.span, "_");
let dots = match limits {
RangeLimits::HalfOpen => "..",
RangeLimits::Closed => "..="
};
diag.span_suggestion(
expr.span,
"consider using the following if you are attempting to iterate over this \
range in reverse",
format!("({}{}{}).rev()", end_snippet, dots, start_snippet),
Applicability::MaybeIncorrect,
);
}
},
);
}
}
}
}
fn y_plus_one<'t>(cx: &LateContext<'_, '_>, expr: &'t Expr<'_>) -> Option<&'t Expr<'t>> {
match expr.kind {
ExprKind::Binary(

View File

@ -1922,11 +1922,11 @@
module: "methods",
},
Lint {
name: "reverse_range_loop",
name: "reversed_empty_ranges",
group: "correctness",
desc: "iteration over an empty range, such as `10..0` or `5..5`",
desc: "reversing the limits of range expressions, resulting in empty ranges",
deprecation: None,
module: "loops",
module: "ranges",
},
Lint {
name: "same_functions_in_if_condition",

View File

@ -21,7 +21,6 @@ impl Unrelated {
clippy::explicit_iter_loop,
clippy::explicit_into_iter_loop,
clippy::iter_next_loop,
clippy::reverse_range_loop,
clippy::for_kv_map
)]
#[allow(
@ -32,61 +31,8 @@ impl Unrelated {
)]
#[allow(clippy::many_single_char_names, unused_variables)]
fn main() {
const MAX_LEN: usize = 42;
let mut vec = vec![1, 2, 3, 4];
for i in (0..10).rev() {
println!("{}", i);
}
for i in (0..=10).rev() {
println!("{}", i);
}
for i in (0..MAX_LEN).rev() {
println!("{}", i);
}
for i in 5..=5 {
// not an error, this is the range with only one element “5”
println!("{}", i);
}
for i in 0..10 {
// not an error, the start index is less than the end index
println!("{}", i);
}
for i in -10..0 {
// not an error
println!("{}", i);
}
for i in (10..0).map(|x| x * 2) {
// not an error, it can't be known what arbitrary methods do to a range
println!("{}", i);
}
// testing that the empty range lint folds constants
for i in (5 + 4..10).rev() {
println!("{}", i);
}
for i in ((3 - 1)..(5 + 2)).rev() {
println!("{}", i);
}
for i in (2 * 2)..(2 * 3) {
// no error, 4..6 is fine
println!("{}", i);
}
let x = 42;
for i in x..10 {
// no error, not constant-foldable
println!("{}", i);
}
// See #601
for i in 0..10 {
// no error, id_col does not exist outside the loop

View File

@ -21,7 +21,6 @@ fn iter(&self) -> std::slice::Iter<u8> {
clippy::explicit_iter_loop,
clippy::explicit_into_iter_loop,
clippy::iter_next_loop,
clippy::reverse_range_loop,
clippy::for_kv_map
)]
#[allow(
@ -32,61 +31,8 @@ fn iter(&self) -> std::slice::Iter<u8> {
)]
#[allow(clippy::many_single_char_names, unused_variables)]
fn main() {
const MAX_LEN: usize = 42;
let mut vec = vec![1, 2, 3, 4];
for i in 10..0 {
println!("{}", i);
}
for i in 10..=0 {
println!("{}", i);
}
for i in MAX_LEN..0 {
println!("{}", i);
}
for i in 5..=5 {
// not an error, this is the range with only one element “5”
println!("{}", i);
}
for i in 0..10 {
// not an error, the start index is less than the end index
println!("{}", i);
}
for i in -10..0 {
// not an error
println!("{}", i);
}
for i in (10..0).map(|x| x * 2) {
// not an error, it can't be known what arbitrary methods do to a range
println!("{}", i);
}
// testing that the empty range lint folds constants
for i in 10..5 + 4 {
println!("{}", i);
}
for i in (5 + 2)..(3 - 1) {
println!("{}", i);
}
for i in (2 * 2)..(2 * 3) {
// no error, 4..6 is fine
println!("{}", i);
}
let x = 42;
for i in x..10 {
// no error, not constant-foldable
println!("{}", i);
}
// See #601
for i in 0..10 {
// no error, id_col does not exist outside the loop

View File

@ -1,61 +1,5 @@
error: this range is empty so this for loop will never run
--> $DIR/for_loop_fixable.rs:38:14
|
LL | for i in 10..0 {
| ^^^^^
|
= note: `-D clippy::reverse-range-loop` implied by `-D warnings`
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (0..10).rev() {
| ^^^^^^^^^^^^^
error: this range is empty so this for loop will never run
--> $DIR/for_loop_fixable.rs:42:14
|
LL | for i in 10..=0 {
| ^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (0..=10).rev() {
| ^^^^^^^^^^^^^^
error: this range is empty so this for loop will never run
--> $DIR/for_loop_fixable.rs:46:14
|
LL | for i in MAX_LEN..0 {
| ^^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (0..MAX_LEN).rev() {
| ^^^^^^^^^^^^^^^^^^
error: this range is empty so this for loop will never run
--> $DIR/for_loop_fixable.rs:71:14
|
LL | for i in 10..5 + 4 {
| ^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (5 + 4..10).rev() {
| ^^^^^^^^^^^^^^^^^
error: this range is empty so this for loop will never run
--> $DIR/for_loop_fixable.rs:75:14
|
LL | for i in (5 + 2)..(3 - 1) {
| ^^^^^^^^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in ((3 - 1)..(5 + 2)).rev() {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:97:15
--> $DIR/for_loop_fixable.rs:43:15
|
LL | for _v in vec.iter() {}
| ^^^^^^^^^^ help: to write this more concisely, try: `&vec`
@ -63,13 +7,13 @@ LL | for _v in vec.iter() {}
= note: `-D clippy::explicit-iter-loop` implied by `-D warnings`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:99:15
--> $DIR/for_loop_fixable.rs:45:15
|
LL | for _v in vec.iter_mut() {}
| ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec`
error: it is more concise to loop over containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:102:15
--> $DIR/for_loop_fixable.rs:48:15
|
LL | for _v in out_vec.into_iter() {}
| ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec`
@ -77,76 +21,76 @@ LL | for _v in out_vec.into_iter() {}
= note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:107:15
--> $DIR/for_loop_fixable.rs:53:15
|
LL | for _v in [1, 2, 3].iter() {}
| ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:111:15
--> $DIR/for_loop_fixable.rs:57:15
|
LL | for _v in [0; 32].iter() {}
| ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:116:15
--> $DIR/for_loop_fixable.rs:62:15
|
LL | for _v in ll.iter() {}
| ^^^^^^^^^ help: to write this more concisely, try: `&ll`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:119:15
--> $DIR/for_loop_fixable.rs:65:15
|
LL | for _v in vd.iter() {}
| ^^^^^^^^^ help: to write this more concisely, try: `&vd`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:122:15
--> $DIR/for_loop_fixable.rs:68:15
|
LL | for _v in bh.iter() {}
| ^^^^^^^^^ help: to write this more concisely, try: `&bh`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:125:15
--> $DIR/for_loop_fixable.rs:71:15
|
LL | for _v in hm.iter() {}
| ^^^^^^^^^ help: to write this more concisely, try: `&hm`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:128:15
--> $DIR/for_loop_fixable.rs:74:15
|
LL | for _v in bt.iter() {}
| ^^^^^^^^^ help: to write this more concisely, try: `&bt`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:131:15
--> $DIR/for_loop_fixable.rs:77:15
|
LL | for _v in hs.iter() {}
| ^^^^^^^^^ help: to write this more concisely, try: `&hs`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:134:15
--> $DIR/for_loop_fixable.rs:80:15
|
LL | for _v in bs.iter() {}
| ^^^^^^^^^ help: to write this more concisely, try: `&bs`
error: it is more concise to loop over containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:309:18
--> $DIR/for_loop_fixable.rs:255:18
|
LL | for i in iterator.into_iter() {
| ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator`
error: it is more concise to loop over references to containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:329:18
--> $DIR/for_loop_fixable.rs:275:18
|
LL | for _ in t.into_iter() {}
| ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t`
error: it is more concise to loop over containers instead of using explicit iteration methods
--> $DIR/for_loop_fixable.rs:331:18
--> $DIR/for_loop_fixable.rs:277:18
|
LL | for _ in r.into_iter() {}
| ^^^^^^^^^^^^^ help: to write this more concisely, try: `r`
error: aborting due to 20 previous errors
error: aborting due to 15 previous errors

View File

@ -5,7 +5,6 @@
clippy::explicit_iter_loop,
clippy::explicit_into_iter_loop,
clippy::iter_next_loop,
clippy::reverse_range_loop,
clippy::for_kv_map
)]
#[allow(
@ -16,25 +15,8 @@
unused,
dead_code
)]
#[allow(clippy::many_single_char_names, unused_variables)]
fn main() {
for i in 5..5 {
println!("{}", i);
}
let vec = vec![1, 2, 3, 4];
for _v in vec.iter().next() {}
for i in (5 + 2)..(8 - 1) {
println!("{}", i);
}
const ZERO: usize = 0;
for i in ZERO..vec.len() {
if f(&vec[i], &vec[i]) {
panic!("at the disco");
}
}
}

View File

@ -1,9 +1,10 @@
error[E0425]: cannot find function `f` in this scope
--> $DIR/for_loop_unfixable.rs:36:12
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:21:15
|
LL | if f(&vec[i], &vec[i]) {
| ^ help: a local variable with a similar name exists: `i`
LL | for _v in vec.iter().next() {}
| ^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::iter-next-loop` implied by `-D warnings`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0425`.

View File

@ -104,7 +104,7 @@ fn index(&self, _: usize) -> &i32 {
dst[i - 0] = src[i];
}
#[allow(clippy::reverse_range_loop)]
#[allow(clippy::reversed_empty_ranges)]
for i in 0..0 {
dst[i] = src[i];
}

View File

@ -0,0 +1,24 @@
// run-rustfix
#![warn(clippy::reversed_empty_ranges)]
const ANSWER: i32 = 42;
fn main() {
(21..=42).rev().for_each(|x| println!("{}", x));
let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
for _ in (-42..=-21).rev() {}
for _ in (21u32..42u32).rev() {}
// These should be ignored as they are not empty ranges:
(21..=42).for_each(|x| println!("{}", x));
(21..42).for_each(|x| println!("{}", x));
let arr = [1, 2, 3, 4, 5];
let _ = &arr[1..=3];
let _ = &arr[1..3];
for _ in 21..=42 {}
for _ in 21..42 {}
}

View File

@ -0,0 +1,24 @@
// run-rustfix
#![warn(clippy::reversed_empty_ranges)]
const ANSWER: i32 = 42;
fn main() {
(42..=21).for_each(|x| println!("{}", x));
let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
for _ in -21..=-42 {}
for _ in 42u32..21u32 {}
// These should be ignored as they are not empty ranges:
(21..=42).for_each(|x| println!("{}", x));
(21..42).for_each(|x| println!("{}", x));
let arr = [1, 2, 3, 4, 5];
let _ = &arr[1..=3];
let _ = &arr[1..3];
for _ in 21..=42 {}
for _ in 21..42 {}
}

View File

@ -0,0 +1,47 @@
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_fixable.rs:7:5
|
LL | (42..=21).for_each(|x| println!("{}", x));
| ^^^^^^^^^
|
= note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | (21..=42).rev().for_each(|x| println!("{}", x));
| ^^^^^^^^^^^^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_fixable.rs:8:13
|
LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
| ^^^^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_fixable.rs:10:14
|
LL | for _ in -21..=-42 {}
| ^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for _ in (-42..=-21).rev() {}
| ^^^^^^^^^^^^^^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_fixable.rs:11:14
|
LL | for _ in 42u32..21u32 {}
| ^^^^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for _ in (21u32..42u32).rev() {}
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View File

@ -0,0 +1,57 @@
// run-rustfix
#![warn(clippy::reversed_empty_ranges)]
fn main() {
const MAX_LEN: usize = 42;
for i in (0..10).rev() {
println!("{}", i);
}
for i in (0..=10).rev() {
println!("{}", i);
}
for i in (0..MAX_LEN).rev() {
println!("{}", i);
}
for i in 5..=5 {
// not an error, this is the range with only one element “5”
println!("{}", i);
}
for i in 0..10 {
// not an error, the start index is less than the end index
println!("{}", i);
}
for i in -10..0 {
// not an error
println!("{}", i);
}
for i in (0..10).rev().map(|x| x * 2) {
println!("{}", i);
}
// testing that the empty range lint folds constants
for i in (5 + 4..10).rev() {
println!("{}", i);
}
for i in ((3 - 1)..(5 + 2)).rev() {
println!("{}", i);
}
for i in (2 * 2)..(2 * 3) {
// no error, 4..6 is fine
println!("{}", i);
}
let x = 42;
for i in x..10 {
// no error, not constant-foldable
println!("{}", i);
}
}

View File

@ -0,0 +1,57 @@
// run-rustfix
#![warn(clippy::reversed_empty_ranges)]
fn main() {
const MAX_LEN: usize = 42;
for i in 10..0 {
println!("{}", i);
}
for i in 10..=0 {
println!("{}", i);
}
for i in MAX_LEN..0 {
println!("{}", i);
}
for i in 5..=5 {
// not an error, this is the range with only one element “5”
println!("{}", i);
}
for i in 0..10 {
// not an error, the start index is less than the end index
println!("{}", i);
}
for i in -10..0 {
// not an error
println!("{}", i);
}
for i in (10..0).map(|x| x * 2) {
println!("{}", i);
}
// testing that the empty range lint folds constants
for i in 10..5 + 4 {
println!("{}", i);
}
for i in (5 + 2)..(3 - 1) {
println!("{}", i);
}
for i in (2 * 2)..(2 * 3) {
// no error, 4..6 is fine
println!("{}", i);
}
let x = 42;
for i in x..10 {
// no error, not constant-foldable
println!("{}", i);
}
}

View File

@ -0,0 +1,69 @@
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_loops_fixable.rs:7:14
|
LL | for i in 10..0 {
| ^^^^^
|
= note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (0..10).rev() {
| ^^^^^^^^^^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_loops_fixable.rs:11:14
|
LL | for i in 10..=0 {
| ^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (0..=10).rev() {
| ^^^^^^^^^^^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_loops_fixable.rs:15:14
|
LL | for i in MAX_LEN..0 {
| ^^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (0..MAX_LEN).rev() {
| ^^^^^^^^^^^^^^^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_loops_fixable.rs:34:14
|
LL | for i in (10..0).map(|x| x * 2) {
| ^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (0..10).rev().map(|x| x * 2) {
| ^^^^^^^^^^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_loops_fixable.rs:39:14
|
LL | for i in 10..5 + 4 {
| ^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in (5 + 4..10).rev() {
| ^^^^^^^^^^^^^^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_loops_fixable.rs:43:14
|
LL | for i in (5 + 2)..(3 - 1) {
| ^^^^^^^^^^^^^^^^
|
help: consider using the following if you are attempting to iterate over this range in reverse
|
LL | for i in ((3 - 1)..(5 + 2)).rev() {
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors

View File

@ -0,0 +1,11 @@
#![warn(clippy::reversed_empty_ranges)]
fn main() {
for i in 5..5 {
println!("{}", i);
}
for i in (5 + 2)..(8 - 1) {
println!("{}", i);
}
}

View File

@ -0,0 +1,16 @@
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_loops_unfixable.rs:4:14
|
LL | for i in 5..5 {
| ^^^^
|
= note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_loops_unfixable.rs:8:14
|
LL | for i in (5 + 2)..(8 - 1) {
| ^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,15 @@
#![warn(clippy::reversed_empty_ranges)]
const ANSWER: i32 = 42;
const SOME_NUM: usize = 3;
fn main() {
let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21);
let arr = [1, 2, 3, 4, 5];
let _ = &arr[3usize..=1usize];
let _ = &arr[SOME_NUM..1];
let _ = &arr[3..3];
for _ in ANSWER..ANSWER {}
}

View File

@ -0,0 +1,34 @@
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_unfixable.rs:7:13
|
LL | let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21);
| ^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::reversed-empty-ranges` implied by `-D warnings`
error: this range is reversed and using it to index a slice will panic at run-time
--> $DIR/reversed_empty_ranges_unfixable.rs:10:18
|
LL | let _ = &arr[3usize..=1usize];
| ^^^^^^^^^^^^^^^
error: this range is reversed and using it to index a slice will panic at run-time
--> $DIR/reversed_empty_ranges_unfixable.rs:11:18
|
LL | let _ = &arr[SOME_NUM..1];
| ^^^^^^^^^^^
error: this range is empty and using it to index a slice will always yield an empty slice
--> $DIR/reversed_empty_ranges_unfixable.rs:12:18
|
LL | let _ = &arr[3..3];
| ^^^^
error: this range is empty so it will yield no values
--> $DIR/reversed_empty_ranges_unfixable.rs:14:14
|
LL | for _ in ANSWER..ANSWER {}
| ^^^^^^^^^^^^^^
error: aborting due to 5 previous errors