mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-30 16:39:26 +00:00
Fix #9958
This commit is contained in:
parent
6d0b4e3a09
commit
7a0f0c0e8b
4 changed files with 153 additions and 21 deletions
|
@ -1,13 +1,13 @@
|
||||||
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
|
||||||
use clippy_utils::source::snippet_with_applicability;
|
use clippy_utils::source::snippet_with_applicability;
|
||||||
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed};
|
use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, peel_ref_operators};
|
||||||
use if_chain::if_chain;
|
use if_chain::if_chain;
|
||||||
use rustc_ast::ast::LitKind;
|
use rustc_ast::ast::LitKind;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def_id::DefIdSet;
|
use rustc_hir::def_id::DefIdSet;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
|
def_id::DefId, AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, ImplItem, ImplItemKind, ImplicitSelfKind, Item,
|
||||||
ItemKind, Mutability, Node, TraitItemRef, TyKind,
|
ItemKind, Mutability, Node, TraitItemRef, TyKind, UnOp,
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
|
||||||
|
@ -16,6 +16,7 @@ use rustc_span::{
|
||||||
source_map::{Span, Spanned, Symbol},
|
source_map::{Span, Spanned, Symbol},
|
||||||
symbol::sym,
|
symbol::sym,
|
||||||
};
|
};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
declare_clippy_lint! {
|
declare_clippy_lint! {
|
||||||
/// ### What it does
|
/// ### What it does
|
||||||
|
@ -428,16 +429,23 @@ fn check_len(
|
||||||
fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
|
fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Expr<'_>, op: &str) {
|
||||||
if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
|
if (is_empty_array(lit2) || is_empty_string(lit2)) && has_is_empty(cx, lit1) {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
|
|
||||||
|
let lit1 = peel_ref_operators(cx, lit1);
|
||||||
|
let mut lit_str = snippet_with_applicability(cx, lit1.span, "_", &mut applicability);
|
||||||
|
|
||||||
|
// Wrap the expression in parentheses if it's a deref expression. Otherwise operator precedence will
|
||||||
|
// cause the code to dereference boolean(won't compile).
|
||||||
|
if let ExprKind::Unary(UnOp::Deref, _) = lit1.kind {
|
||||||
|
lit_str = Cow::from(format!("({lit_str})"));
|
||||||
|
}
|
||||||
|
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
COMPARISON_TO_EMPTY,
|
COMPARISON_TO_EMPTY,
|
||||||
span,
|
span,
|
||||||
"comparison to empty slice",
|
"comparison to empty slice",
|
||||||
&format!("using `{op}is_empty` is clearer and more explicit"),
|
&format!("using `{op}is_empty` is clearer and more explicit"),
|
||||||
format!(
|
format!("{op}{lit_str}.is_empty()"),
|
||||||
"{op}{}.is_empty()",
|
|
||||||
snippet_with_applicability(cx, lit1.span, "_", &mut applicability)
|
|
||||||
),
|
|
||||||
applicability,
|
applicability,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#![warn(clippy::len_zero)]
|
#![warn(clippy::len_zero)]
|
||||||
#![allow(dead_code, unused, clippy::len_without_is_empty)]
|
#![allow(dead_code, unused, clippy::len_without_is_empty)]
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
|
use core::ops::Deref;
|
||||||
|
|
||||||
pub struct One;
|
pub struct One;
|
||||||
struct Wither;
|
struct Wither;
|
||||||
|
|
||||||
|
@ -56,6 +59,26 @@ impl WithIsEmpty for Wither {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DerefToDerefToString;
|
||||||
|
|
||||||
|
impl Deref for DerefToDerefToString {
|
||||||
|
type Target = DerefToString;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&DerefToString {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DerefToString;
|
||||||
|
|
||||||
|
impl Deref for DerefToString {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
"Hello, world!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = [1, 2];
|
let x = [1, 2];
|
||||||
if x.is_empty() {
|
if x.is_empty() {
|
||||||
|
@ -64,6 +87,23 @@ fn main() {
|
||||||
|
|
||||||
if "".is_empty() {}
|
if "".is_empty() {}
|
||||||
|
|
||||||
|
let s = "Hello, world!";
|
||||||
|
let s1 = &s;
|
||||||
|
let s2 = &s1;
|
||||||
|
let s3 = &s2;
|
||||||
|
let s4 = &s3;
|
||||||
|
let s5 = &s4;
|
||||||
|
let s6 = &s5;
|
||||||
|
println!("{}", s1.is_empty());
|
||||||
|
println!("{}", s2.is_empty());
|
||||||
|
println!("{}", s3.is_empty());
|
||||||
|
println!("{}", s4.is_empty());
|
||||||
|
println!("{}", s5.is_empty());
|
||||||
|
println!("{}", (s6).is_empty());
|
||||||
|
|
||||||
|
let d2s = DerefToDerefToString {};
|
||||||
|
println!("{}", (**d2s).is_empty());
|
||||||
|
|
||||||
let y = One;
|
let y = One;
|
||||||
if y.len() == 0 {
|
if y.len() == 0 {
|
||||||
// No error; `One` does not have `.is_empty()`.
|
// No error; `One` does not have `.is_empty()`.
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
#![warn(clippy::len_zero)]
|
#![warn(clippy::len_zero)]
|
||||||
#![allow(dead_code, unused, clippy::len_without_is_empty)]
|
#![allow(dead_code, unused, clippy::len_without_is_empty)]
|
||||||
|
|
||||||
|
extern crate core;
|
||||||
|
use core::ops::Deref;
|
||||||
|
|
||||||
pub struct One;
|
pub struct One;
|
||||||
struct Wither;
|
struct Wither;
|
||||||
|
|
||||||
|
@ -56,6 +59,26 @@ impl WithIsEmpty for Wither {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DerefToDerefToString;
|
||||||
|
|
||||||
|
impl Deref for DerefToDerefToString {
|
||||||
|
type Target = DerefToString;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&DerefToString {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DerefToString;
|
||||||
|
|
||||||
|
impl Deref for DerefToString {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
"Hello, world!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let x = [1, 2];
|
let x = [1, 2];
|
||||||
if x.len() == 0 {
|
if x.len() == 0 {
|
||||||
|
@ -64,6 +87,23 @@ fn main() {
|
||||||
|
|
||||||
if "".len() == 0 {}
|
if "".len() == 0 {}
|
||||||
|
|
||||||
|
let s = "Hello, world!";
|
||||||
|
let s1 = &s;
|
||||||
|
let s2 = &s1;
|
||||||
|
let s3 = &s2;
|
||||||
|
let s4 = &s3;
|
||||||
|
let s5 = &s4;
|
||||||
|
let s6 = &s5;
|
||||||
|
println!("{}", *s1 == "");
|
||||||
|
println!("{}", **s2 == "");
|
||||||
|
println!("{}", ***s3 == "");
|
||||||
|
println!("{}", ****s4 == "");
|
||||||
|
println!("{}", *****s5 == "");
|
||||||
|
println!("{}", ******(s6) == "");
|
||||||
|
|
||||||
|
let d2s = DerefToDerefToString {};
|
||||||
|
println!("{}", &**d2s == "");
|
||||||
|
|
||||||
let y = One;
|
let y = One;
|
||||||
if y.len() == 0 {
|
if y.len() == 0 {
|
||||||
// No error; `One` does not have `.is_empty()`.
|
// No error; `One` does not have `.is_empty()`.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:61:8
|
--> $DIR/len_zero.rs:84:8
|
||||||
|
|
|
|
||||||
LL | if x.len() == 0 {
|
LL | if x.len() == 0 {
|
||||||
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
|
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `x.is_empty()`
|
||||||
|
@ -7,82 +7,126 @@ LL | if x.len() == 0 {
|
||||||
= note: `-D clippy::len-zero` implied by `-D warnings`
|
= note: `-D clippy::len-zero` implied by `-D warnings`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:65:8
|
--> $DIR/len_zero.rs:88:8
|
||||||
|
|
|
|
||||||
LL | if "".len() == 0 {}
|
LL | if "".len() == 0 {}
|
||||||
| ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
|
| ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()`
|
||||||
|
|
||||||
|
error: comparison to empty slice
|
||||||
|
--> $DIR/len_zero.rs:97:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", *s1 == "");
|
||||||
|
| ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::comparison-to-empty` implied by `-D warnings`
|
||||||
|
|
||||||
|
error: comparison to empty slice
|
||||||
|
--> $DIR/len_zero.rs:98:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", **s2 == "");
|
||||||
|
| ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()`
|
||||||
|
|
||||||
|
error: comparison to empty slice
|
||||||
|
--> $DIR/len_zero.rs:99:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", ***s3 == "");
|
||||||
|
| ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()`
|
||||||
|
|
||||||
|
error: comparison to empty slice
|
||||||
|
--> $DIR/len_zero.rs:100:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", ****s4 == "");
|
||||||
|
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()`
|
||||||
|
|
||||||
|
error: comparison to empty slice
|
||||||
|
--> $DIR/len_zero.rs:101:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", *****s5 == "");
|
||||||
|
| ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()`
|
||||||
|
|
||||||
|
error: comparison to empty slice
|
||||||
|
--> $DIR/len_zero.rs:102:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", ******(s6) == "");
|
||||||
|
| ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()`
|
||||||
|
|
||||||
|
error: comparison to empty slice
|
||||||
|
--> $DIR/len_zero.rs:105:20
|
||||||
|
|
|
||||||
|
LL | println!("{}", &**d2s == "");
|
||||||
|
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:80:8
|
--> $DIR/len_zero.rs:120:8
|
||||||
|
|
|
|
||||||
LL | if has_is_empty.len() == 0 {
|
LL | if has_is_empty.len() == 0 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:83:8
|
--> $DIR/len_zero.rs:123:8
|
||||||
|
|
|
|
||||||
LL | if has_is_empty.len() != 0 {
|
LL | if has_is_empty.len() != 0 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:86:8
|
--> $DIR/len_zero.rs:126:8
|
||||||
|
|
|
|
||||||
LL | if has_is_empty.len() > 0 {
|
LL | if has_is_empty.len() > 0 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to one
|
error: length comparison to one
|
||||||
--> $DIR/len_zero.rs:89:8
|
--> $DIR/len_zero.rs:129:8
|
||||||
|
|
|
|
||||||
LL | if has_is_empty.len() < 1 {
|
LL | if has_is_empty.len() < 1 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to one
|
error: length comparison to one
|
||||||
--> $DIR/len_zero.rs:92:8
|
--> $DIR/len_zero.rs:132:8
|
||||||
|
|
|
|
||||||
LL | if has_is_empty.len() >= 1 {
|
LL | if has_is_empty.len() >= 1 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:103:8
|
--> $DIR/len_zero.rs:143:8
|
||||||
|
|
|
|
||||||
LL | if 0 == has_is_empty.len() {
|
LL | if 0 == has_is_empty.len() {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:106:8
|
--> $DIR/len_zero.rs:146:8
|
||||||
|
|
|
|
||||||
LL | if 0 != has_is_empty.len() {
|
LL | if 0 != has_is_empty.len() {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:109:8
|
--> $DIR/len_zero.rs:149:8
|
||||||
|
|
|
|
||||||
LL | if 0 < has_is_empty.len() {
|
LL | if 0 < has_is_empty.len() {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to one
|
error: length comparison to one
|
||||||
--> $DIR/len_zero.rs:112:8
|
--> $DIR/len_zero.rs:152:8
|
||||||
|
|
|
|
||||||
LL | if 1 <= has_is_empty.len() {
|
LL | if 1 <= has_is_empty.len() {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to one
|
error: length comparison to one
|
||||||
--> $DIR/len_zero.rs:115:8
|
--> $DIR/len_zero.rs:155:8
|
||||||
|
|
|
|
||||||
LL | if 1 > has_is_empty.len() {
|
LL | if 1 > has_is_empty.len() {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:129:8
|
--> $DIR/len_zero.rs:169:8
|
||||||
|
|
|
|
||||||
LL | if with_is_empty.len() == 0 {
|
LL | if with_is_empty.len() == 0 {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> $DIR/len_zero.rs:142:8
|
--> $DIR/len_zero.rs:182:8
|
||||||
|
|
|
|
||||||
LL | if b.len() != 0 {}
|
LL | if b.len() != 0 {}
|
||||||
| ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
|
| ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
|
||||||
|
|
||||||
error: aborting due to 14 previous errors
|
error: aborting due to 21 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue