about summary refs log tree commit diff
path: root/clippy_lints/src
diff options
context:
space:
mode:
Diffstat (limited to 'clippy_lints/src')
-rw-r--r--clippy_lints/src/default_instead_of_iter_empty.rs68
-rw-r--r--clippy_lints/src/lib.register_all.rs1
-rw-r--r--clippy_lints/src/lib.register_lints.rs1
-rw-r--r--clippy_lints/src/lib.register_style.rs1
-rw-r--r--clippy_lints/src/lib.rs2
5 files changed, 73 insertions, 0 deletions
diff --git a/clippy_lints/src/default_instead_of_iter_empty.rs b/clippy_lints/src/default_instead_of_iter_empty.rs
new file mode 100644
index 00000000000..3c996d3d2ae
--- /dev/null
+++ b/clippy_lints/src/default_instead_of_iter_empty.rs
@@ -0,0 +1,68 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::last_path_segment;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{match_def_path, paths};
+use rustc_errors::Applicability;
+use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// It checks for `std::iter::Empty::default()` and suggests replacing it with
+    /// `std::iter::empty()`.
+    /// ### Why is this bad?
+    /// `std::iter::empty()` is the more idiomatic way.
+    /// ### Example
+    /// ```rust
+    /// let _ = std::iter::Empty::<usize>::default();
+    /// let iter: std::iter::Empty<usize> = std::iter::Empty::default();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let _ = std::iter::empty::<usize>();
+    /// let iter: std::iter::Empty<usize> = std::iter::empty();
+    /// ```
+    #[clippy::version = "1.63.0"]
+    pub DEFAULT_INSTEAD_OF_ITER_EMPTY,
+    style,
+    "check `std::iter::Empty::default()` and replace with `std::iter::empty()`"
+}
+declare_lint_pass!(DefaultIterEmpty => [DEFAULT_INSTEAD_OF_ITER_EMPTY]);
+
+impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Call(iter_expr, []) = &expr.kind
+            && let ExprKind::Path(QPath::TypeRelative(ty, _)) = &iter_expr.kind
+            && let TyKind::Path(ty_path) = &ty.kind
+            && let QPath::Resolved(None, path) = ty_path
+            && let def::Res::Def(_, def_id) = &path.res
+            && match_def_path(cx, *def_id, &paths::ITER_EMPTY)
+        {
+            let mut applicability = Applicability::MachineApplicable;
+            let sugg = make_sugg(cx, ty_path, &mut applicability);
+            span_lint_and_sugg(
+                cx,
+                DEFAULT_INSTEAD_OF_ITER_EMPTY,
+                expr.span,
+                "`std::iter::empty()` is the more idiomatic way",
+                "try",
+                sugg,
+                applicability,
+            );
+        }
+    }
+}
+
+fn make_sugg(cx: &LateContext<'_>, ty_path: &rustc_hir::QPath<'_>, applicability: &mut Applicability) -> String {
+    if let Some(last) = last_path_segment(ty_path).args
+        && let Some(iter_ty) = last.args.iter().find_map(|arg| match arg {
+            GenericArg::Type(ty) => Some(ty),
+            _ => None,
+        })
+    {
+        format!("std::iter::empty::<{}>()", snippet_with_applicability(cx, iter_ty.span, "..", applicability))
+    } else {
+        "std::iter::empty()".to_owned()
+    }
+}
diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs
index 8a2cfbff953..7876f21f6e6 100644
--- a/clippy_lints/src/lib.register_all.rs
+++ b/clippy_lints/src/lib.register_all.rs
@@ -43,6 +43,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(copies::IF_SAME_THEN_ELSE),
     LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
     LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
+    LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
     LintId::of(dereference::NEEDLESS_BORROW),
     LintId::of(derivable_impls::DERIVABLE_IMPLS),
     LintId::of(derive::DERIVE_HASH_XOR_EQ),
diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs
index 8ad984c68b8..de22f50cf94 100644
--- a/clippy_lints/src/lib.register_lints.rs
+++ b/clippy_lints/src/lib.register_lints.rs
@@ -105,6 +105,7 @@ store.register_lints(&[
     dbg_macro::DBG_MACRO,
     default::DEFAULT_TRAIT_ACCESS,
     default::FIELD_REASSIGN_WITH_DEFAULT,
+    default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY,
     default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
     default_union_representation::DEFAULT_UNION_REPRESENTATION,
     dereference::EXPLICIT_DEREF_METHODS,
diff --git a/clippy_lints/src/lib.register_style.rs b/clippy_lints/src/lib.register_style.rs
index b6992ae0ad2..d52ec50e542 100644
--- a/clippy_lints/src/lib.register_style.rs
+++ b/clippy_lints/src/lib.register_style.rs
@@ -14,6 +14,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(collapsible_if::COLLAPSIBLE_IF),
     LintId::of(comparison_chain::COMPARISON_CHAIN),
     LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
+    LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
     LintId::of(dereference::NEEDLESS_BORROW),
     LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 84898eae05a..dcee11cc28c 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -199,6 +199,7 @@ mod crate_in_macro_def;
 mod create_dir;
 mod dbg_macro;
 mod default;
+mod default_instead_of_iter_empty;
 mod default_numeric_fallback;
 mod default_union_representation;
 mod dereference;
@@ -910,6 +911,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch));
     store.register_late_pass(|| Box::new(as_underscore::AsUnderscore));
     store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec));
+    store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }