blob: 5c6da6d5aed3a43270a6c026aabaa83e37893c8f [file] [log] [blame]
#![warn(clippy::range_minus_one, clippy::range_plus_one)]
#![allow(unused_parens)]
#![allow(clippy::iter_with_drain)]
use std::ops::{Index, IndexMut, Range, RangeBounds, RangeInclusive};
fn f() -> usize {
42
}
macro_rules! macro_plus_one {
($m: literal) => {
for i in 0..$m + 1 {
println!("{}", i);
}
};
}
macro_rules! macro_minus_one {
($m: literal) => {
for i in 0..=$m - 1 {
println!("{}", i);
}
};
}
fn main() {
for _ in 0..2 {}
for _ in 0..=2 {}
for _ in 0..=3 {}
//~^ range_plus_one
for _ in 0..=3 + 1 {}
for _ in 0..=5 {}
//~^ range_plus_one
for _ in 0..=1 + 5 {}
for _ in 1..=1 {}
//~^ range_plus_one
for _ in 1..=1 + 1 {}
for _ in 0..13 + 13 {}
for _ in 0..=13 - 7 {}
for _ in 0..=f() {}
//~^ range_plus_one
for _ in 0..=(1 + f()) {}
// Those are not linted, as in the general case we cannot be sure that the exact type won't be
// important.
let _ = ..11 - 1;
let _ = ..=11 - 1;
let _ = ..=(11 - 1);
let _ = (1..11 + 1);
let _ = (f() + 1)..(f() + 1);
const ONE: usize = 1;
// integer consts are linted, too
for _ in 1..=ONE {}
//~^ range_plus_one
let mut vec: Vec<()> = std::vec::Vec::new();
vec.drain(..);
macro_plus_one!(5);
macro_minus_one!(5);
// As an instance of `Iterator`
(1..=10).for_each(|_| {});
//~^ range_plus_one
// As an instance of `IntoIterator`
#[allow(clippy::useless_conversion)]
(1..=10).into_iter().for_each(|_| {});
//~^ range_plus_one
// As an instance of `RangeBounds`
{
let _ = (1..=10).start_bound();
//~^ range_plus_one
}
// As a `SliceIndex`
let a = [10, 20, 30];
let _ = &a[1..=1];
//~^ range_plus_one
// As method call argument
vec.drain(2..=3);
//~^ range_plus_one
// As function call argument
take_arg(10..=20);
//~^ range_plus_one
// As function call argument inside a block
take_arg({ 10..=20 });
//~^ range_plus_one
// Do not lint in case types are unified
take_arg(if true { 10..20 } else { 10..20 + 1 });
// Do not lint, as the same type is used for both parameters
take_args(10..20 + 1, 10..21);
// Do not lint, as the range type is also used indirectly in second parameter
take_arg_and_struct(10..20 + 1, S { t: 1..2 });
// As target of `IndexMut`
let mut a = [10, 20, 30];
a[0..=2][0] = 1;
//~^ range_plus_one
}
fn take_arg<T: Iterator<Item = u32>>(_: T) {}
fn take_args<T: Iterator<Item = u32>>(_: T, _: T) {}
struct S<T> {
t: T,
}
fn take_arg_and_struct<T: Iterator<Item = u32>>(_: T, _: S<T>) {}
fn no_index_by_range_inclusive(a: usize) {
struct S;
impl Index<Range<usize>> for S {
type Output = [u32];
fn index(&self, _: Range<usize>) -> &Self::Output {
&[]
}
}
_ = &S[0..a + 1];
}
fn no_index_mut_with_switched_range(a: usize) {
struct S(u32);
impl Index<Range<usize>> for S {
type Output = u32;
fn index(&self, _: Range<usize>) -> &Self::Output {
&self.0
}
}
impl IndexMut<Range<usize>> for S {
fn index_mut(&mut self, _: Range<usize>) -> &mut Self::Output {
&mut self.0
}
}
impl Index<RangeInclusive<usize>> for S {
type Output = u32;
fn index(&self, _: RangeInclusive<usize>) -> &Self::Output {
&self.0
}
}
S(2)[0..a + 1] = 3;
}
fn issue9908() {
// Simplified test case
let _ = || 0..=1;
// Original test case
let full_length = 1024;
let range = {
// do some stuff, omit here
None
};
let range = range.map(|(s, t)| s..=t).unwrap_or(0..=(full_length - 1));
assert_eq!(range, 0..=1023);
}
fn issue9908_2(n: usize) -> usize {
(1..n).sum()
//~^ range_minus_one
}