Auto merge of #11029 - Centri3:empty_slice, r=Jarcho

Make `comparison_to_empty` work on `if let`/`let` chains

This adds `LetChain` to `clippy_utils::higher`, other lints may benefit from such a change as well :D

changelog: Enhancement: [`comparison_to_empty`]: Now lints on `if let`
This commit is contained in:
bors 2023-07-23 05:10:32 +00:00
commit 356768b317
4 changed files with 84 additions and 10 deletions

View file

@ -7,11 +7,10 @@ use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
ImplicitSelfKind, Item, ItemKind, Mutability, Node, PathSegment, PrimTy, QPath, TraitItemRef, TyKind,
TypeBindingKind,
ImplicitSelfKind, Item, ItemKind, LangItem, Mutability, Node, PatKind, PathSegment, PrimTy, QPath, TraitItemRef,
TyKind, TypeBindingKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
@ -168,6 +167,31 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
return;
}
if let ExprKind::Let(lt) = expr.kind
&& has_is_empty(cx, lt.init)
&& match lt.pat.kind {
PatKind::Slice([], None, []) => true,
PatKind::Lit(lit) if is_empty_string(lit) => true,
_ => false,
}
{
let mut applicability = Applicability::MachineApplicable;
let lit1 = peel_ref_operators(cx, lt.init);
let lit_str =
Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par();
span_lint_and_sugg(
cx,
COMPARISON_TO_EMPTY,
lt.span,
"comparison to empty slice using `if let`",
"using `is_empty` is clearer and more explicit",
format!("{lit_str}.is_empty()"),
applicability,
);
}
if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
// expr.span might contains parenthesis, see issue #10529
let actual_span = left.span.with_hi(right.span.hi());

View file

@ -1,7 +1,8 @@
//@run-rustfix
#![warn(clippy::comparison_to_empty)]
#![allow(clippy::useless_vec)]
#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
#![feature(let_chains)]
fn main() {
// Disallow comparisons to empty
@ -12,6 +13,11 @@ fn main() {
let v = vec![0];
let _ = v.is_empty();
let _ = !v.is_empty();
if (*v).is_empty() {}
let s = [0].as_slice();
if s.is_empty() {}
if s.is_empty() {}
if s.is_empty() && s.is_empty() {}
// Allow comparisons to non-empty
let s = String::new();
@ -21,4 +27,8 @@ fn main() {
let v = vec![0];
let _ = v == [0];
let _ = v != [0];
if let [0] = &*v {}
let s = [0].as_slice();
if let [0] = s {}
if let [0] = &*s && s == [0] {}
}

View file

@ -1,7 +1,8 @@
//@run-rustfix
#![warn(clippy::comparison_to_empty)]
#![allow(clippy::useless_vec)]
#![allow(clippy::borrow_deref_ref, clippy::needless_if, clippy::useless_vec)]
#![feature(let_chains)]
fn main() {
// Disallow comparisons to empty
@ -12,6 +13,11 @@ fn main() {
let v = vec![0];
let _ = v == [];
let _ = v != [];
if let [] = &*v {}
let s = [0].as_slice();
if let [] = s {}
if let [] = &*s {}
if let [] = &*s && s == [] {}
// Allow comparisons to non-empty
let s = String::new();
@ -21,4 +27,8 @@ fn main() {
let v = vec![0];
let _ = v == [0];
let _ = v != [0];
if let [0] = &*v {}
let s = [0].as_slice();
if let [0] = s {}
if let [0] = &*s && s == [0] {}
}

View file

@ -1,5 +1,5 @@
error: comparison to empty slice
--> $DIR/comparison_to_empty.rs:9:13
--> $DIR/comparison_to_empty.rs:10:13
|
LL | let _ = s == "";
| ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
@ -7,22 +7,52 @@ LL | let _ = s == "";
= note: `-D clippy::comparison-to-empty` implied by `-D warnings`
error: comparison to empty slice
--> $DIR/comparison_to_empty.rs:10:13
--> $DIR/comparison_to_empty.rs:11:13
|
LL | let _ = s != "";
| ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()`
error: comparison to empty slice
--> $DIR/comparison_to_empty.rs:13:13
--> $DIR/comparison_to_empty.rs:14:13
|
LL | let _ = v == [];
| ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()`
error: comparison to empty slice
--> $DIR/comparison_to_empty.rs:14:13
--> $DIR/comparison_to_empty.rs:15:13
|
LL | let _ = v != [];
| ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()`
error: aborting due to 4 previous errors
error: comparison to empty slice using `if let`
--> $DIR/comparison_to_empty.rs:16:8
|
LL | if let [] = &*v {}
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()`
error: comparison to empty slice using `if let`
--> $DIR/comparison_to_empty.rs:18:8
|
LL | if let [] = s {}
| ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
error: comparison to empty slice using `if let`
--> $DIR/comparison_to_empty.rs:19:8
|
LL | if let [] = &*s {}
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
error: comparison to empty slice using `if let`
--> $DIR/comparison_to_empty.rs:20:8
|
LL | if let [] = &*s && s == [] {}
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
error: comparison to empty slice
--> $DIR/comparison_to_empty.rs:20:24
|
LL | if let [] = &*s && s == [] {}
| ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
error: aborting due to 9 previous errors