Skip to content

Commit e933bb6

Browse files
committed
Auto merge of #8989 - kyoto7250:default_iter_empty, r=Alexendoo
feat(lint): add default_iter_empty close #8915 This PR adds `default_iter_empty` lint. This lint checks `std::iter::Empty::default()` and replace with `std::iter::empty()`. Thank you in advance. --- changelog: add `default_instead_of_iter_empty` lint.
2 parents d7b5cbf + 2bb8c45 commit e933bb6

10 files changed

+139
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3348,6 +3348,7 @@ Released 2018-09-13
33483348
[`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call
33493349
[`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation
33503350
[`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
3351+
[`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty
33513352
[`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
33523353
[`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
33533354
[`default_union_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_union_representation
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::last_path_segment;
3+
use clippy_utils::source::snippet_with_applicability;
4+
use clippy_utils::{match_def_path, paths};
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
7+
use rustc_lint::{LateContext, LateLintPass};
8+
use rustc_session::{declare_lint_pass, declare_tool_lint};
9+
10+
declare_clippy_lint! {
11+
/// ### What it does
12+
/// It checks for `std::iter::Empty::default()` and suggests replacing it with
13+
/// `std::iter::empty()`.
14+
/// ### Why is this bad?
15+
/// `std::iter::empty()` is the more idiomatic way.
16+
/// ### Example
17+
/// ```rust
18+
/// let _ = std::iter::Empty::<usize>::default();
19+
/// let iter: std::iter::Empty<usize> = std::iter::Empty::default();
20+
/// ```
21+
/// Use instead:
22+
/// ```rust
23+
/// let _ = std::iter::empty::<usize>();
24+
/// let iter: std::iter::Empty<usize> = std::iter::empty();
25+
/// ```
26+
#[clippy::version = "1.63.0"]
27+
pub DEFAULT_INSTEAD_OF_ITER_EMPTY,
28+
style,
29+
"check `std::iter::Empty::default()` and replace with `std::iter::empty()`"
30+
}
31+
declare_lint_pass!(DefaultIterEmpty => [DEFAULT_INSTEAD_OF_ITER_EMPTY]);
32+
33+
impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty {
34+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
35+
if let ExprKind::Call(iter_expr, []) = &expr.kind
36+
&& let ExprKind::Path(QPath::TypeRelative(ty, _)) = &iter_expr.kind
37+
&& let TyKind::Path(ty_path) = &ty.kind
38+
&& let QPath::Resolved(None, path) = ty_path
39+
&& let def::Res::Def(_, def_id) = &path.res
40+
&& match_def_path(cx, *def_id, &paths::ITER_EMPTY)
41+
{
42+
let mut applicability = Applicability::MachineApplicable;
43+
let sugg = make_sugg(cx, ty_path, &mut applicability);
44+
span_lint_and_sugg(
45+
cx,
46+
DEFAULT_INSTEAD_OF_ITER_EMPTY,
47+
expr.span,
48+
"`std::iter::empty()` is the more idiomatic way",
49+
"try",
50+
sugg,
51+
applicability,
52+
);
53+
}
54+
}
55+
}
56+
57+
fn make_sugg(cx: &LateContext<'_>, ty_path: &rustc_hir::QPath<'_>, applicability: &mut Applicability) -> String {
58+
if let Some(last) = last_path_segment(ty_path).args
59+
&& let Some(iter_ty) = last.args.iter().find_map(|arg| match arg {
60+
GenericArg::Type(ty) => Some(ty),
61+
_ => None,
62+
})
63+
{
64+
format!("std::iter::empty::<{}>()", snippet_with_applicability(cx, iter_ty.span, "..", applicability))
65+
} else {
66+
"std::iter::empty()".to_owned()
67+
}
68+
}

clippy_lints/src/lib.register_all.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
4343
LintId::of(copies::IF_SAME_THEN_ELSE),
4444
LintId::of(crate_in_macro_def::CRATE_IN_MACRO_DEF),
4545
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
46+
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
4647
LintId::of(dereference::NEEDLESS_BORROW),
4748
LintId::of(derivable_impls::DERIVABLE_IMPLS),
4849
LintId::of(derive::DERIVE_HASH_XOR_EQ),

clippy_lints/src/lib.register_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ store.register_lints(&[
105105
dbg_macro::DBG_MACRO,
106106
default::DEFAULT_TRAIT_ACCESS,
107107
default::FIELD_REASSIGN_WITH_DEFAULT,
108+
default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY,
108109
default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
109110
default_union_representation::DEFAULT_UNION_REPRESENTATION,
110111
dereference::EXPLICIT_DEREF_METHODS,

clippy_lints/src/lib.register_style.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
1414
LintId::of(collapsible_if::COLLAPSIBLE_IF),
1515
LintId::of(comparison_chain::COMPARISON_CHAIN),
1616
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
17+
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
1718
LintId::of(dereference::NEEDLESS_BORROW),
1819
LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
1920
LintId::of(disallowed_methods::DISALLOWED_METHODS),

clippy_lints/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ mod crate_in_macro_def;
199199
mod create_dir;
200200
mod dbg_macro;
201201
mod default;
202+
mod default_instead_of_iter_empty;
202203
mod default_numeric_fallback;
203204
mod default_union_representation;
204205
mod dereference;
@@ -910,6 +911,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
910911
store.register_late_pass(|| Box::new(mismatching_type_param_order::TypeParamMismatch));
911912
store.register_late_pass(|| Box::new(as_underscore::AsUnderscore));
912913
store.register_late_pass(|| Box::new(read_zero_byte_vec::ReadZeroByteVec));
914+
store.register_late_pass(|| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
913915
// add lints here, do not remove this comment, it's used in `new_lint`
914916
}
915917

clippy_utils/src/paths.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub const IO_WRITE: [&str; 3] = ["std", "io", "Write"];
6262
pub const IPADDR_V4: [&str; 5] = ["std", "net", "ip", "IpAddr", "V4"];
6363
pub const IPADDR_V6: [&str; 5] = ["std", "net", "ip", "IpAddr", "V6"];
6464
pub const ITER_COUNT: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "count"];
65+
pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
6566
pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
6667
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
6768
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// run-rustfix
2+
#![warn(clippy::default_instead_of_iter_empty)]
3+
#![allow(dead_code)]
4+
use std::collections::HashMap;
5+
6+
#[derive(Default)]
7+
struct Iter {
8+
iter: std::iter::Empty<usize>,
9+
}
10+
11+
fn main() {
12+
// Do lint.
13+
let _ = std::iter::empty::<usize>();
14+
let _ = std::iter::empty::<HashMap<usize, usize>>();
15+
let _foo: std::iter::Empty<usize> = std::iter::empty();
16+
17+
// Do not lint.
18+
let _ = Vec::<usize>::default();
19+
let _ = String::default();
20+
let _ = Iter::default();
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// run-rustfix
2+
#![warn(clippy::default_instead_of_iter_empty)]
3+
#![allow(dead_code)]
4+
use std::collections::HashMap;
5+
6+
#[derive(Default)]
7+
struct Iter {
8+
iter: std::iter::Empty<usize>,
9+
}
10+
11+
fn main() {
12+
// Do lint.
13+
let _ = std::iter::Empty::<usize>::default();
14+
let _ = std::iter::Empty::<HashMap<usize, usize>>::default();
15+
let _foo: std::iter::Empty<usize> = std::iter::Empty::default();
16+
17+
// Do not lint.
18+
let _ = Vec::<usize>::default();
19+
let _ = String::default();
20+
let _ = Iter::default();
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: `std::iter::empty()` is the more idiomatic way
2+
--> $DIR/default_instead_of_iter_empty.rs:13:13
3+
|
4+
LL | let _ = std::iter::Empty::<usize>::default();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty::<usize>()`
6+
|
7+
= note: `-D clippy::default-instead-of-iter-empty` implied by `-D warnings`
8+
9+
error: `std::iter::empty()` is the more idiomatic way
10+
--> $DIR/default_instead_of_iter_empty.rs:14:13
11+
|
12+
LL | let _ = std::iter::Empty::<HashMap<usize, usize>>::default();
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty::<HashMap<usize, usize>>()`
14+
15+
error: `std::iter::empty()` is the more idiomatic way
16+
--> $DIR/default_instead_of_iter_empty.rs:15:41
17+
|
18+
LL | let _foo: std::iter::Empty<usize> = std::iter::Empty::default();
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()`
20+
21+
error: aborting due to 3 previous errors
22+

0 commit comments

Comments
 (0)