Skip to content

Commit 7f7faa1

Browse files
committed
Move implementation into len_zero.rs
1 parent de5a6d3 commit 7f7faa1

File tree

3 files changed

+86
-161
lines changed

3 files changed

+86
-161
lines changed

clippy_lints/src/comparison_to_empty.rs

Lines changed: 0 additions & 155 deletions
This file was deleted.

clippy_lints/src/len_zero.rs

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,45 @@ declare_clippy_lint! {
6868
"traits or impls with a public `len` method but no corresponding `is_empty` method"
6969
}
7070

71-
declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY]);
71+
declare_clippy_lint! {
72+
/// **What it does:** Checks for comparing to an empty slice such as "" or [],`
73+
/// and suggests using `.is_empty()` where applicable.
74+
///
75+
/// **Why is this bad?** Some structures can answer `.is_empty()` much faster
76+
/// than checking for equality. So it is good to get into the habit of using
77+
/// `.is_empty()`, and having it is cheap.
78+
/// Besides, it makes the intent clearer than a manual comparison in some contexts.
79+
///
80+
/// **Known problems:** None.
81+
///
82+
/// **Example:**
83+
///
84+
/// ```ignore
85+
/// if s == "" {
86+
/// ..
87+
/// }
88+
89+
/// if arr == [] {
90+
/// ..
91+
/// }
92+
/// ```
93+
/// Use instead:
94+
/// ```ignore
95+
/// if s.is_empty() {
96+
/// ..
97+
/// }
98+
99+
/// if arr.is_empty() {
100+
/// ..
101+
/// }
102+
/// ```
103+
pub COMPARISON_TO_EMPTY,
104+
style,
105+
"default lint description"
106+
}
107+
108+
109+
declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMPTY]);
72110

73111
impl<'tcx> LateLintPass<'tcx> for LenZero {
74112
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
@@ -221,6 +259,8 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
221259
}
222260

223261
check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to)
262+
} else {
263+
check_empty_expr(cx, span, method, lit, op)
224264
}
225265
}
226266

@@ -258,6 +298,48 @@ fn check_len(
258298
}
259299
}
260300

301+
fn check_empty_expr(
302+
cx: &LateContext<'_>,
303+
span: Span,
304+
lit1: &Expr<'_>,
305+
lit2: &Expr<'_>,
306+
op: &str
307+
) {
308+
if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
309+
let mut applicability = Applicability::MachineApplicable;
310+
span_lint_and_sugg(
311+
cx,
312+
COMPARISON_TO_EMPTY,
313+
span,
314+
&format!("comparison to empty slice"),
315+
&format!("using `{}is_empty` is clearer and more explicit", op),
316+
format!(
317+
"{}{}.is_empty()",
318+
op,
319+
snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
320+
),
321+
applicability,
322+
);
323+
}
324+
}
325+
326+
fn is_empty_string(expr: &Expr<'_>) -> bool {
327+
if let ExprKind::Lit(ref lit) = expr.kind {
328+
if let LitKind::Str(lit, _) = lit.node {
329+
let lit = lit.as_str();
330+
return lit == "";
331+
}
332+
}
333+
false
334+
}
335+
336+
fn is_empty_array(expr: &Expr<'_>) -> bool {
337+
if let ExprKind::Array(ref arr) = expr.kind {
338+
return arr.is_empty();
339+
}
340+
false
341+
}
342+
261343
/// Checks if this type has an `is_empty` method.
262344
fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
263345
/// Gets an `AssocItem` and return true if it matches `is_empty(self)`.

clippy_lints/src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,6 @@ mod checked_conversions;
171171
mod cognitive_complexity;
172172
mod collapsible_if;
173173
mod comparison_chain;
174-
mod comparison_to_empty;
175174
mod copies;
176175
mod copy_iterator;
177176
mod create_dir;
@@ -524,7 +523,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
524523
&cognitive_complexity::COGNITIVE_COMPLEXITY,
525524
&collapsible_if::COLLAPSIBLE_IF,
526525
&comparison_chain::COMPARISON_CHAIN,
527-
&comparison_to_empty::COMPARISON_TO_EMPTY,
526+
&len_zero::COMPARISON_TO_EMPTY,
528527
&copies::IFS_SAME_COND,
529528
&copies::IF_SAME_THEN_ELSE,
530529
&copies::MATCH_SAME_ARMS,
@@ -1141,7 +1140,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
11411140
store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods));
11421141
store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax);
11431142
store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax);
1144-
store.register_late_pass(|| box comparison_to_empty::ComparisonToEmpty);
11451143

11461144

11471145
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![
@@ -1302,7 +1300,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13021300
LintId::of(&bytecount::NAIVE_BYTECOUNT),
13031301
LintId::of(&collapsible_if::COLLAPSIBLE_IF),
13041302
LintId::of(&comparison_chain::COMPARISON_CHAIN),
1305-
LintId::of(&comparison_to_empty::COMPARISON_TO_EMPTY),
1303+
LintId::of(&len_zero::COMPARISON_TO_EMPTY),
13061304
LintId::of(&copies::IFS_SAME_COND),
13071305
LintId::of(&copies::IF_SAME_THEN_ELSE),
13081306
LintId::of(&derive::DERIVE_HASH_XOR_EQ),
@@ -1559,7 +1557,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15591557
LintId::of(&blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
15601558
LintId::of(&collapsible_if::COLLAPSIBLE_IF),
15611559
LintId::of(&comparison_chain::COMPARISON_CHAIN),
1562-
LintId::of(&comparison_to_empty::COMPARISON_TO_EMPTY),
1560+
LintId::of(&len_zero::COMPARISON_TO_EMPTY),
15631561
LintId::of(&doc::MISSING_SAFETY_DOC),
15641562
LintId::of(&doc::NEEDLESS_DOCTEST_MAIN),
15651563
LintId::of(&enum_variants::ENUM_VARIANT_NAMES),

0 commit comments

Comments
 (0)