mod explicit_into_iter_loop;
mod explicit_iter_loop;
mod for_kv_map;
-mod for_loops_over_fallibles;
mod iter_next_loop;
+mod manual_find;
mod manual_flatten;
mod manual_memcpy;
+mod missing_spin_loop;
mod mut_range_bound;
mod needless_collect;
mod needless_range_loop;
/// dst[i + 64] = src[i];
/// }
/// ```
- /// Could be written as:
+ ///
+ /// Use instead:
/// ```rust
/// # let src = vec![1];
/// # let mut dst = vec![0; 65];
/// println!("{}", vec[i]);
/// }
/// ```
- /// Could be written as:
+ ///
+ /// Use instead:
/// ```rust
/// let vec = vec!['a', 'b', 'c'];
/// for i in vec {
/// // ..
/// }
/// ```
- /// can be rewritten to
+ ///
+ /// Use instead:
/// ```rust
/// # let y = vec![1];
/// for x in &y {
"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);
- ///
- /// // Bad
- /// for x in opt {
- /// // ..
- /// }
- ///
- /// // Good
- /// if let Some(x) = opt {
- /// // ..
- /// }
- /// ```
- ///
- /// // or
- ///
- /// ```rust
- /// # let res: Result<i32, std::io::Error> = Ok(1);
- ///
- /// // Bad
- /// for x in &res {
- /// // ..
- /// }
- ///
- /// // Good
- /// 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! {
/// ### What it does
/// Detects `loop + match` combinations that are easier
/// i += 1;
/// }
/// ```
- /// Could be written as
+ ///
+ /// Use instead:
/// ```rust
/// # let v = vec![1];
/// # fn bar(bar: usize, baz: usize) {}
///
/// ### Example
/// ```ignore
- /// while let Some(val) = iter() {
+ /// while let Some(val) = iter.next() {
+ /// ..
+ /// }
+ /// ```
+ ///
+ /// Use instead:
+ /// ```ignore
+ /// for val in &mut iter {
/// ..
/// }
/// ```
///
/// ### Why is this bad?
/// This kind of operation can be expressed more succinctly with
- /// `vec![item;SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also
+ /// `vec![item; SIZE]` or `vec.resize(NEW_SIZE, item)` and using these alternatives may also
/// have better performance.
///
/// ### Example
/// vec.push(item2);
/// }
/// ```
- /// could be written as
+ ///
+ /// Use instead:
/// ```rust
/// let item1 = 2;
/// let item2 = 3;
/// println!("{}", item);
/// }
/// ```
- /// could be written as
+ ///
+ /// Use instead:
/// ```rust
/// let item1 = 2;
/// let item = &item1;
"for loops over `Option`s or `Result`s with a single expression can be simplified"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Check for empty spin loops
+ ///
+ /// ### Why is this bad?
+ /// The loop body should have something like `thread::park()` or at least
+ /// `std::hint::spin_loop()` to avoid needlessly burning cycles and conserve
+ /// energy. Perhaps even better use an actual lock, if possible.
+ ///
+ /// ### Known problems
+ /// This lint doesn't currently trigger on `while let` or
+ /// `loop { match .. { .. } }` loops, which would be considered idiomatic in
+ /// combination with e.g. `AtomicBool::compare_exchange_weak`.
+ ///
+ /// ### Example
+ ///
+ /// ```ignore
+ /// use core::sync::atomic::{AtomicBool, Ordering};
+ /// let b = AtomicBool::new(true);
+ /// // give a ref to `b` to another thread,wait for it to become false
+ /// while b.load(Ordering::Acquire) {};
+ /// ```
+ /// Use instead:
+ /// ```rust,no_run
+ ///# use core::sync::atomic::{AtomicBool, Ordering};
+ ///# let b = AtomicBool::new(true);
+ /// while b.load(Ordering::Acquire) {
+ /// std::hint::spin_loop()
+ /// }
+ /// ```
+ #[clippy::version = "1.61.0"]
+ pub MISSING_SPIN_LOOP,
+ perf,
+ "An empty busy waiting loop"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Check for manual implementations of Iterator::find
+ ///
+ /// ### Why is this bad?
+ /// It doesn't affect performance, but using `find` is shorter and easier to read.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// fn example(arr: Vec<i32>) -> Option<i32> {
+ /// for el in arr {
+ /// if el == 1 {
+ /// return Some(el);
+ /// }
+ /// }
+ /// None
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// fn example(arr: Vec<i32>) -> Option<i32> {
+ /// arr.into_iter().find(|&el| el == 1)
+ /// }
+ /// ```
+ #[clippy::version = "1.64.0"]
+ pub MANUAL_FIND,
+ complexity,
+ "manual implementation of `Iterator::find`"
+}
+
declare_lint_pass!(Loops => [
MANUAL_MEMCPY,
MANUAL_FLATTEN,
EXPLICIT_ITER_LOOP,
EXPLICIT_INTO_ITER_LOOP,
ITER_NEXT_LOOP,
- FOR_LOOPS_OVER_FALLIBLES,
WHILE_LET_LOOP,
NEEDLESS_COLLECT,
EXPLICIT_COUNTER_LOOP,
WHILE_IMMUTABLE_CONDITION,
SAME_ITEM_PUSH,
SINGLE_ELEMENT_LOOP,
+ MISSING_SPIN_LOOP,
+ MANUAL_FIND,
]);
impl<'tcx> LateLintPass<'tcx> for Loops {
- #[allow(clippy::too_many_lines)]
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let for_loop = higher::ForLoop::hir(expr);
if let Some(higher::ForLoop {
if let Some(higher::While { condition, body }) = higher::While::hir(expr) {
while_immutable_condition::check(cx, condition, body);
+ missing_spin_loop::check(cx, condition, body);
}
needless_collect::check(expr, cx);
single_element_loop::check(cx, pat, arg, body, expr);
same_item_push::check(cx, pat, arg, body, expr);
manual_flatten::check(cx, pat, arg, body, span);
+ manual_find::check(cx, pat, arg, body, span, expr);
}
-fn check_for_loop_arg(cx: &LateContext<'_>, pat: &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 {
+fn check_for_loop_arg(cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
+ if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
let method_name = method.ident.as_str();
// check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
match method_name {
- "iter" | "iter_mut" => explicit_iter_loop::check(cx, self_arg, arg, method_name),
+ "iter" | "iter_mut" => {
+ explicit_iter_loop::check(cx, self_arg, arg, method_name);
+ },
"into_iter" => {
explicit_iter_loop::check(cx, self_arg, arg, method_name);
explicit_into_iter_loop::check(cx, self_arg, arg);
},
"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);
- }
}