Auto merge of #12310 - samueltardieu:issue-12307, r=xFrednet
New lint `const_is_empty` This lint detects calls to `.is_empty()` on an entity initialized from a string literal and flag them as suspicious. To avoid triggering on macros called from generated code, it checks that the `.is_empty()` receiver, the call itself and the initialization come from the same context. Fixes #12307 changelog: [`const_is_empty`]: new lint
This commit is contained in:
commit
453242cbde
@ -5110,6 +5110,7 @@ Released 2018-09-13
|
|||||||
[`collection_is_never_read`]: https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
|
[`collection_is_never_read`]: https://rust-lang.github.io/rust-clippy/master/index.html#collection_is_never_read
|
||||||
[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
|
[`comparison_chain`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_chain
|
||||||
[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
|
[`comparison_to_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#comparison_to_empty
|
||||||
|
[`const_is_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_is_empty
|
||||||
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
|
[`const_static_lifetime`]: https://rust-lang.github.io/rust-clippy/master/index.html#const_static_lifetime
|
||||||
[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
|
[`copy_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#copy_iterator
|
||||||
[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
|
[`crate_in_macro_def`]: https://rust-lang.github.io/rust-clippy/master/index.html#crate_in_macro_def
|
||||||
|
@ -353,6 +353,7 @@
|
|||||||
crate::methods::CLONE_ON_COPY_INFO,
|
crate::methods::CLONE_ON_COPY_INFO,
|
||||||
crate::methods::CLONE_ON_REF_PTR_INFO,
|
crate::methods::CLONE_ON_REF_PTR_INFO,
|
||||||
crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
|
crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
|
||||||
|
crate::methods::CONST_IS_EMPTY_INFO,
|
||||||
crate::methods::DRAIN_COLLECT_INFO,
|
crate::methods::DRAIN_COLLECT_INFO,
|
||||||
crate::methods::ERR_EXPECT_INFO,
|
crate::methods::ERR_EXPECT_INFO,
|
||||||
crate::methods::EXPECT_FUN_CALL_INFO,
|
crate::methods::EXPECT_FUN_CALL_INFO,
|
||||||
|
49
clippy_lints/src/methods/is_empty.rs
Normal file
49
clippy_lints/src/methods/is_empty.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
use clippy_utils::consts::constant_is_empty;
|
||||||
|
use clippy_utils::diagnostics::span_lint;
|
||||||
|
use clippy_utils::{find_binding_init, path_to_local};
|
||||||
|
use rustc_hir::{Expr, HirId};
|
||||||
|
use rustc_lint::{LateContext, LintContext};
|
||||||
|
use rustc_middle::lint::in_external_macro;
|
||||||
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
use super::CONST_IS_EMPTY;
|
||||||
|
|
||||||
|
/// Expression whose initialization depend on a constant conditioned by a `#[cfg(…)]` directive will
|
||||||
|
/// not trigger the lint.
|
||||||
|
pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_>) {
|
||||||
|
if in_external_macro(cx.sess(), expr.span) || !receiver.span.eq_ctxt(expr.span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let init_expr = expr_or_init(cx, receiver);
|
||||||
|
if !receiver.span.eq_ctxt(init_expr.span) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some(init_is_empty) = constant_is_empty(cx, init_expr) {
|
||||||
|
span_lint(
|
||||||
|
cx,
|
||||||
|
CONST_IS_EMPTY,
|
||||||
|
expr.span,
|
||||||
|
&format!("this expression always evaluates to {init_is_empty:?}"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool {
|
||||||
|
cx.tcx
|
||||||
|
.hir()
|
||||||
|
.parent_id_iter(id)
|
||||||
|
.any(|id| cx.tcx.hir().attrs(id).iter().any(|attr| attr.has_name(sym::cfg)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization
|
||||||
|
/// value depends on a `#[cfg(…)]` directive.
|
||||||
|
fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr<'b>) -> &'a Expr<'b> {
|
||||||
|
while let Some(init) = path_to_local(expr)
|
||||||
|
.and_then(|id| find_binding_init(cx, id))
|
||||||
|
.filter(|init| cx.typeck_results().expr_adjustments(init).is_empty())
|
||||||
|
.filter(|init| !is_under_cfg(cx, init.hir_id))
|
||||||
|
{
|
||||||
|
expr = init;
|
||||||
|
}
|
||||||
|
expr
|
||||||
|
}
|
@ -36,6 +36,7 @@
|
|||||||
mod inspect_for_each;
|
mod inspect_for_each;
|
||||||
mod into_iter_on_ref;
|
mod into_iter_on_ref;
|
||||||
mod is_digit_ascii_radix;
|
mod is_digit_ascii_radix;
|
||||||
|
mod is_empty;
|
||||||
mod iter_cloned_collect;
|
mod iter_cloned_collect;
|
||||||
mod iter_count;
|
mod iter_count;
|
||||||
mod iter_filter;
|
mod iter_filter;
|
||||||
@ -4044,6 +4045,31 @@
|
|||||||
"calling `.get().is_some()` or `.get().is_none()` instead of `.contains()` or `.contains_key()`"
|
"calling `.get().is_some()` or `.get().is_none()` instead of `.contains()` or `.contains_key()`"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// It identifies calls to `.is_empty()` on constant values.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// String literals and constant values are known at compile time. Checking if they
|
||||||
|
/// are empty will always return the same value. This might not be the intention of
|
||||||
|
/// the expression.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```no_run
|
||||||
|
/// let value = "";
|
||||||
|
/// if value.is_empty() {
|
||||||
|
/// println!("the string is empty");
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```no_run
|
||||||
|
/// println!("the string is empty");
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.78.0"]
|
||||||
|
pub CONST_IS_EMPTY,
|
||||||
|
suspicious,
|
||||||
|
"is_empty() called on strings known at compile time"
|
||||||
|
}
|
||||||
pub struct Methods {
|
pub struct Methods {
|
||||||
avoid_breaking_exported_api: bool,
|
avoid_breaking_exported_api: bool,
|
||||||
msrv: Msrv,
|
msrv: Msrv,
|
||||||
@ -4092,6 +4118,7 @@ pub fn new(
|
|||||||
CLONE_ON_COPY,
|
CLONE_ON_COPY,
|
||||||
CLONE_ON_REF_PTR,
|
CLONE_ON_REF_PTR,
|
||||||
COLLAPSIBLE_STR_REPLACE,
|
COLLAPSIBLE_STR_REPLACE,
|
||||||
|
CONST_IS_EMPTY,
|
||||||
ITER_OVEREAGER_CLONED,
|
ITER_OVEREAGER_CLONED,
|
||||||
CLONED_INSTEAD_OF_COPIED,
|
CLONED_INSTEAD_OF_COPIED,
|
||||||
FLAT_MAP_OPTION,
|
FLAT_MAP_OPTION,
|
||||||
@ -4445,7 +4472,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||||||
("as_deref" | "as_deref_mut", []) => {
|
("as_deref" | "as_deref_mut", []) => {
|
||||||
needless_option_as_deref::check(cx, expr, recv, name);
|
needless_option_as_deref::check(cx, expr, recv, name);
|
||||||
},
|
},
|
||||||
("as_bytes" | "is_empty", []) => {
|
("as_bytes", []) => {
|
||||||
if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
|
if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
|
||||||
redundant_as_str::check(cx, expr, recv, as_str_span, span);
|
redundant_as_str::check(cx, expr, recv, as_str_span, span);
|
||||||
}
|
}
|
||||||
@ -4619,6 +4646,12 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||||||
("hash", [arg]) => {
|
("hash", [arg]) => {
|
||||||
unit_hash::check(cx, expr, recv, arg);
|
unit_hash::check(cx, expr, recv, arg);
|
||||||
},
|
},
|
||||||
|
("is_empty", []) => {
|
||||||
|
if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
|
||||||
|
redundant_as_str::check(cx, expr, recv, as_str_span, span);
|
||||||
|
}
|
||||||
|
is_empty::check(cx, expr, recv);
|
||||||
|
},
|
||||||
("is_file", []) => filetype_is_file::check(cx, expr, recv),
|
("is_file", []) => filetype_is_file::check(cx, expr, recv),
|
||||||
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv),
|
("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv),
|
||||||
("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false),
|
("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false),
|
||||||
|
@ -10,8 +10,10 @@
|
|||||||
use rustc_lexer::tokenize;
|
use rustc_lexer::tokenize;
|
||||||
use rustc_lint::LateContext;
|
use rustc_lint::LateContext;
|
||||||
use rustc_middle::mir::interpret::{alloc_range, Scalar};
|
use rustc_middle::mir::interpret::{alloc_range, Scalar};
|
||||||
|
use rustc_middle::mir::ConstValue;
|
||||||
use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy};
|
use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, IntTy, List, ScalarInt, Ty, TyCtxt, UintTy};
|
||||||
use rustc_middle::{bug, mir, span_bug};
|
use rustc_middle::{bug, mir, span_bug};
|
||||||
|
use rustc_span::def_id::DefId;
|
||||||
use rustc_span::symbol::{Ident, Symbol};
|
use rustc_span::symbol::{Ident, Symbol};
|
||||||
use rustc_span::SyntaxContext;
|
use rustc_span::SyntaxContext;
|
||||||
use rustc_target::abi::Size;
|
use rustc_target::abi::Size;
|
||||||
@ -307,6 +309,12 @@ pub fn is_local(&self) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to check whether the expression is a constant representing an empty slice, str, array,
|
||||||
|
/// etc…
|
||||||
|
pub fn constant_is_empty(lcx: &LateContext<'_>, e: &Expr<'_>) -> Option<bool> {
|
||||||
|
ConstEvalLateContext::new(lcx, lcx.typeck_results()).expr_is_empty(e)
|
||||||
|
}
|
||||||
|
|
||||||
/// Attempts to evaluate the expression as a constant.
|
/// Attempts to evaluate the expression as a constant.
|
||||||
pub fn constant<'tcx>(
|
pub fn constant<'tcx>(
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
@ -406,7 +414,13 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
|||||||
match e.kind {
|
match e.kind {
|
||||||
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
|
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr(self.lcx.tcx.hir().body(body).value),
|
||||||
ExprKind::DropTemps(e) => self.expr(e),
|
ExprKind::DropTemps(e) => self.expr(e),
|
||||||
ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)),
|
ExprKind::Path(ref qpath) => {
|
||||||
|
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
|
||||||
|
let result = mir_to_const(this.lcx, result)?;
|
||||||
|
this.source = ConstantSource::Constant;
|
||||||
|
Some(result)
|
||||||
|
})
|
||||||
|
},
|
||||||
ExprKind::Block(block, _) => self.block(block),
|
ExprKind::Block(block, _) => self.block(block),
|
||||||
ExprKind::Lit(lit) => {
|
ExprKind::Lit(lit) => {
|
||||||
if is_direct_expn_of(e.span, "cfg").is_some() {
|
if is_direct_expn_of(e.span, "cfg").is_some() {
|
||||||
@ -472,6 +486,49 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant<'tcx>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Simple constant folding to determine if an expression is an empty slice, str, array, …
|
||||||
|
/// `None` will be returned if the constness cannot be determined, or if the resolution
|
||||||
|
/// leaves the local crate.
|
||||||
|
pub fn expr_is_empty(&mut self, e: &Expr<'_>) -> Option<bool> {
|
||||||
|
match e.kind {
|
||||||
|
ExprKind::ConstBlock(ConstBlock { body, .. }) => self.expr_is_empty(self.lcx.tcx.hir().body(body).value),
|
||||||
|
ExprKind::DropTemps(e) => self.expr_is_empty(e),
|
||||||
|
ExprKind::Path(ref qpath) => {
|
||||||
|
if !self
|
||||||
|
.typeck_results
|
||||||
|
.qpath_res(qpath, e.hir_id)
|
||||||
|
.opt_def_id()
|
||||||
|
.is_some_and(DefId::is_local)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
self.fetch_path_and_apply(qpath, e.hir_id, self.typeck_results.expr_ty(e), |this, result| {
|
||||||
|
mir_is_empty(this.lcx, result)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
ExprKind::Lit(lit) => {
|
||||||
|
if is_direct_expn_of(e.span, "cfg").is_some() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
match &lit.node {
|
||||||
|
LitKind::Str(is, _) => Some(is.is_empty()),
|
||||||
|
LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => Some(s.is_empty()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ExprKind::Array(vec) => self.multi(vec).map(|v| v.is_empty()),
|
||||||
|
ExprKind::Repeat(..) => {
|
||||||
|
if let ty::Array(_, n) = self.typeck_results.expr_ty(e).kind() {
|
||||||
|
Some(n.try_eval_target_usize(self.lcx.tcx, self.lcx.param_env)? == 0)
|
||||||
|
} else {
|
||||||
|
span_bug!(e.span, "typeck error");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[expect(clippy::cast_possible_wrap)]
|
#[expect(clippy::cast_possible_wrap)]
|
||||||
fn constant_not(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tcx>> {
|
fn constant_not(&self, o: &Constant<'tcx>, ty: Ty<'_>) -> Option<Constant<'tcx>> {
|
||||||
use self::Constant::{Bool, Int};
|
use self::Constant::{Bool, Int};
|
||||||
@ -519,8 +576,11 @@ fn multi(&mut self, vec: &[Expr<'_>]) -> Option<Vec<Constant<'tcx>>> {
|
|||||||
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
|
vec.iter().map(|elem| self.expr(elem)).collect::<Option<_>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup a possibly constant expression from an `ExprKind::Path`.
|
/// Lookup a possibly constant expression from an `ExprKind::Path` and apply a function on it.
|
||||||
fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<Constant<'tcx>> {
|
fn fetch_path_and_apply<T, F>(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>, f: F) -> Option<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Self, rustc_middle::mir::Const<'tcx>) -> Option<T>,
|
||||||
|
{
|
||||||
let res = self.typeck_results.qpath_res(qpath, id);
|
let res = self.typeck_results.qpath_res(qpath, id);
|
||||||
match res {
|
match res {
|
||||||
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
Res::Def(DefKind::Const | DefKind::AssocConst, def_id) => {
|
||||||
@ -553,9 +613,7 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<C
|
|||||||
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
|
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
|
.map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
|
||||||
let result = mir_to_const(self.lcx, result)?;
|
f(self, result)
|
||||||
self.source = ConstantSource::Constant;
|
|
||||||
Some(result)
|
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -746,7 +804,6 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
|
pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
|
||||||
use rustc_middle::mir::ConstValue;
|
|
||||||
let mir::Const::Val(val, _) = result else {
|
let mir::Const::Val(val, _) = result else {
|
||||||
// We only work on evaluated consts.
|
// We only work on evaluated consts.
|
||||||
return None;
|
return None;
|
||||||
@ -794,6 +851,42 @@ pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mir_is_empty<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<bool> {
|
||||||
|
let mir::Const::Val(val, _) = result else {
|
||||||
|
// We only work on evaluated consts.
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
match (val, result.ty().kind()) {
|
||||||
|
(_, ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
|
||||||
|
ty::Str | ty::Slice(_) => {
|
||||||
|
if let ConstValue::Indirect { alloc_id, offset } = val {
|
||||||
|
// Get the length from the slice, using the same formula as
|
||||||
|
// [`ConstValue::try_get_slice_bytes_for_diagnostics`].
|
||||||
|
let a = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
|
||||||
|
let ptr_size = lcx.tcx.data_layout.pointer_size;
|
||||||
|
if a.size() < offset + 2 * ptr_size {
|
||||||
|
// (partially) dangling reference
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let len = a
|
||||||
|
.read_scalar(&lcx.tcx, alloc_range(offset + ptr_size, ptr_size), false)
|
||||||
|
.ok()?
|
||||||
|
.to_target_usize(&lcx.tcx)
|
||||||
|
.ok()?;
|
||||||
|
Some(len == 0)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ty::Array(_, len) => Some(len.try_to_target_usize(lcx.tcx)? == 0),
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
(ConstValue::Indirect { .. }, ty::Array(_, len)) => Some(len.try_to_target_usize(lcx.tcx)? == 0),
|
||||||
|
(ConstValue::ZeroSized, _) => Some(true),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn field_of_struct<'tcx>(
|
fn field_of_struct<'tcx>(
|
||||||
adt_def: ty::AdtDef<'tcx>,
|
adt_def: ty::AdtDef<'tcx>,
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![allow(unused, clippy::assertions_on_constants)]
|
#![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)]
|
||||||
#![warn(clippy::bool_assert_comparison)]
|
#![warn(clippy::bool_assert_comparison)]
|
||||||
|
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#![allow(unused, clippy::assertions_on_constants)]
|
#![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)]
|
||||||
#![warn(clippy::bool_assert_comparison)]
|
#![warn(clippy::bool_assert_comparison)]
|
||||||
|
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
|
174
tests/ui/const_is_empty.rs
Normal file
174
tests/ui/const_is_empty.rs
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#![feature(inline_const)]
|
||||||
|
#![warn(clippy::const_is_empty)]
|
||||||
|
#![allow(clippy::needless_late_init, unused_must_use)]
|
||||||
|
|
||||||
|
fn test_literal() {
|
||||||
|
if "".is_empty() {
|
||||||
|
//~^ERROR: this expression always evaluates to true
|
||||||
|
}
|
||||||
|
if "foobar".is_empty() {
|
||||||
|
//~^ERROR: this expression always evaluates to false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_byte_literal() {
|
||||||
|
if b"".is_empty() {
|
||||||
|
//~^ERROR: this expression always evaluates to true
|
||||||
|
}
|
||||||
|
if b"foobar".is_empty() {
|
||||||
|
//~^ERROR: this expression always evaluates to false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_no_mut() {
|
||||||
|
let mut empty = "";
|
||||||
|
if empty.is_empty() {
|
||||||
|
// No lint because it is mutable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_propagated() {
|
||||||
|
let empty = "";
|
||||||
|
let non_empty = "foobar";
|
||||||
|
let empty2 = empty;
|
||||||
|
let non_empty2 = non_empty;
|
||||||
|
if empty2.is_empty() {
|
||||||
|
//~^ERROR: this expression always evaluates to true
|
||||||
|
}
|
||||||
|
if non_empty2.is_empty() {
|
||||||
|
//~^ERROR: this expression always evaluates to false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const EMPTY_STR: &str = "";
|
||||||
|
const NON_EMPTY_STR: &str = "foo";
|
||||||
|
const EMPTY_BSTR: &[u8] = b"";
|
||||||
|
const NON_EMPTY_BSTR: &[u8] = b"foo";
|
||||||
|
const EMPTY_U8_SLICE: &[u8] = &[];
|
||||||
|
const NON_EMPTY_U8_SLICE: &[u8] = &[1, 2];
|
||||||
|
const EMPTY_SLICE: &[u32] = &[];
|
||||||
|
const NON_EMPTY_SLICE: &[u32] = &[1, 2];
|
||||||
|
const NON_EMPTY_SLICE_REPEAT: &[u32] = &[1; 2];
|
||||||
|
const EMPTY_ARRAY: [u32; 0] = [];
|
||||||
|
const EMPTY_ARRAY_REPEAT: [u32; 0] = [1; 0];
|
||||||
|
const NON_EMPTY_ARRAY: [u32; 2] = [1, 2];
|
||||||
|
const NON_EMPTY_ARRAY_REPEAT: [u32; 2] = [1; 2];
|
||||||
|
const EMPTY_REF_ARRAY: &[u32; 0] = &[];
|
||||||
|
const NON_EMPTY_REF_ARRAY: &[u32; 3] = &[1, 2, 3];
|
||||||
|
|
||||||
|
fn test_from_const() {
|
||||||
|
let _ = EMPTY_STR.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
let _ = NON_EMPTY_STR.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let _ = EMPTY_BSTR.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
let _ = NON_EMPTY_BSTR.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let _ = EMPTY_ARRAY.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
let _ = EMPTY_ARRAY_REPEAT.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
let _ = EMPTY_U8_SLICE.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
let _ = NON_EMPTY_U8_SLICE.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let _ = NON_EMPTY_ARRAY.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let _ = NON_EMPTY_ARRAY_REPEAT.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let _ = EMPTY_REF_ARRAY.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
let _ = NON_EMPTY_REF_ARRAY.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let _ = EMPTY_SLICE.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
let _ = NON_EMPTY_SLICE.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let _ = NON_EMPTY_SLICE_REPEAT.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let value = "foobar";
|
||||||
|
let _ = value.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let x = value;
|
||||||
|
let _ = x.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to false
|
||||||
|
let _ = "".is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
let _ = b"".is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn str_from_arg(var: &str) {
|
||||||
|
var.is_empty();
|
||||||
|
// Do not lint, we know nothiny about var
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_str() {
|
||||||
|
let mut value = "duck";
|
||||||
|
value = "penguin";
|
||||||
|
|
||||||
|
let _ = value.is_empty();
|
||||||
|
// Do not lint since value is mutable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn macros() {
|
||||||
|
// Content from Macro
|
||||||
|
let file = include_str!("const_is_empty.rs");
|
||||||
|
let _ = file.is_empty();
|
||||||
|
// No lint because initializer comes from a macro result
|
||||||
|
|
||||||
|
let var = env!("PATH");
|
||||||
|
let _ = var.is_empty();
|
||||||
|
// No lint because initializer comes from a macro result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn conditional_value() {
|
||||||
|
let value;
|
||||||
|
|
||||||
|
if true {
|
||||||
|
value = "hey";
|
||||||
|
} else {
|
||||||
|
value = "hej";
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = value.is_empty();
|
||||||
|
// Do not lint, current constant folding is too simple to detect this
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cfg_conditioned() {
|
||||||
|
#[cfg(test)]
|
||||||
|
let val = "";
|
||||||
|
#[cfg(not(test))]
|
||||||
|
let val = "foo";
|
||||||
|
|
||||||
|
let _ = val.is_empty();
|
||||||
|
// Do not lint, value depend on a #[cfg(…)] directive
|
||||||
|
}
|
||||||
|
|
||||||
|
fn not_cfg_conditioned() {
|
||||||
|
let val = "";
|
||||||
|
#[cfg(not(target_os = "inexistent"))]
|
||||||
|
let _ = val.is_empty();
|
||||||
|
//~^ ERROR: this expression always evaluates to true
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn const_rand() -> &'static str {
|
||||||
|
"17"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_expressions() {
|
||||||
|
let _ = const { if true { "1" } else { "2" } }.is_empty();
|
||||||
|
// Do not lint, we do not recurse into boolean expressions
|
||||||
|
|
||||||
|
let _ = const_rand().is_empty();
|
||||||
|
// Do not lint, we do not recurse into functions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constant_from_external_crate() {
|
||||||
|
let _ = std::env::consts::EXE_EXTENSION.is_empty();
|
||||||
|
// Do not lint, `exe_ext` comes from the `std` crate
|
||||||
|
}
|
161
tests/ui/const_is_empty.stderr
Normal file
161
tests/ui/const_is_empty.stderr
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:6:8
|
||||||
|
|
|
||||||
|
LL | if "".is_empty() {
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `-D clippy::const-is-empty` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::const_is_empty)]`
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:9:8
|
||||||
|
|
|
||||||
|
LL | if "foobar".is_empty() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:15:8
|
||||||
|
|
|
||||||
|
LL | if b"".is_empty() {
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:18:8
|
||||||
|
|
|
||||||
|
LL | if b"foobar".is_empty() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:35:8
|
||||||
|
|
|
||||||
|
LL | if empty2.is_empty() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:38:8
|
||||||
|
|
|
||||||
|
LL | if non_empty2.is_empty() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:60:13
|
||||||
|
|
|
||||||
|
LL | let _ = EMPTY_STR.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:62:13
|
||||||
|
|
|
||||||
|
LL | let _ = NON_EMPTY_STR.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:64:13
|
||||||
|
|
|
||||||
|
LL | let _ = EMPTY_BSTR.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:66:13
|
||||||
|
|
|
||||||
|
LL | let _ = NON_EMPTY_BSTR.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:68:13
|
||||||
|
|
|
||||||
|
LL | let _ = EMPTY_ARRAY.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:70:13
|
||||||
|
|
|
||||||
|
LL | let _ = EMPTY_ARRAY_REPEAT.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:72:13
|
||||||
|
|
|
||||||
|
LL | let _ = EMPTY_U8_SLICE.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:74:13
|
||||||
|
|
|
||||||
|
LL | let _ = NON_EMPTY_U8_SLICE.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:76:13
|
||||||
|
|
|
||||||
|
LL | let _ = NON_EMPTY_ARRAY.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:78:13
|
||||||
|
|
|
||||||
|
LL | let _ = NON_EMPTY_ARRAY_REPEAT.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:80:13
|
||||||
|
|
|
||||||
|
LL | let _ = EMPTY_REF_ARRAY.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:82:13
|
||||||
|
|
|
||||||
|
LL | let _ = NON_EMPTY_REF_ARRAY.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:84:13
|
||||||
|
|
|
||||||
|
LL | let _ = EMPTY_SLICE.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:86:13
|
||||||
|
|
|
||||||
|
LL | let _ = NON_EMPTY_SLICE.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:88:13
|
||||||
|
|
|
||||||
|
LL | let _ = NON_EMPTY_SLICE_REPEAT.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:94:13
|
||||||
|
|
|
||||||
|
LL | let _ = value.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to false
|
||||||
|
--> tests/ui/const_is_empty.rs:97:13
|
||||||
|
|
|
||||||
|
LL | let _ = x.is_empty();
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:99:13
|
||||||
|
|
|
||||||
|
LL | let _ = "".is_empty();
|
||||||
|
| ^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:101:13
|
||||||
|
|
|
||||||
|
LL | let _ = b"".is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: this expression always evaluates to true
|
||||||
|
--> tests/ui/const_is_empty.rs:155:13
|
||||||
|
|
|
||||||
|
LL | let _ = val.is_empty();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 26 previous errors
|
||||||
|
|
@ -1,5 +1,11 @@
|
|||||||
#![warn(clippy::len_zero)]
|
#![warn(clippy::len_zero)]
|
||||||
#![allow(dead_code, unused, clippy::needless_if, clippy::len_without_is_empty)]
|
#![allow(
|
||||||
|
dead_code,
|
||||||
|
unused,
|
||||||
|
clippy::needless_if,
|
||||||
|
clippy::len_without_is_empty,
|
||||||
|
clippy::const_is_empty
|
||||||
|
)]
|
||||||
|
|
||||||
extern crate core;
|
extern crate core;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
#![warn(clippy::len_zero)]
|
#![warn(clippy::len_zero)]
|
||||||
#![allow(dead_code, unused, clippy::needless_if, clippy::len_without_is_empty)]
|
#![allow(
|
||||||
|
dead_code,
|
||||||
|
unused,
|
||||||
|
clippy::needless_if,
|
||||||
|
clippy::len_without_is_empty,
|
||||||
|
clippy::const_is_empty
|
||||||
|
)]
|
||||||
|
|
||||||
extern crate core;
|
extern crate core;
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> tests/ui/len_zero.rs:82:8
|
--> tests/ui/len_zero.rs:88: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()`
|
||||||
@ -8,13 +8,13 @@ LL | if x.len() == 0 {
|
|||||||
= help: to override `-D warnings` add `#[allow(clippy::len_zero)]`
|
= help: to override `-D warnings` add `#[allow(clippy::len_zero)]`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> tests/ui/len_zero.rs:86:8
|
--> tests/ui/len_zero.rs:92: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
|
error: comparison to empty slice
|
||||||
--> tests/ui/len_zero.rs:95:20
|
--> tests/ui/len_zero.rs:101:20
|
||||||
|
|
|
|
||||||
LL | println!("{}", *s1 == "");
|
LL | println!("{}", *s1 == "");
|
||||||
| ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()`
|
| ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()`
|
||||||
@ -23,121 +23,121 @@ LL | println!("{}", *s1 == "");
|
|||||||
= help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]`
|
= help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]`
|
||||||
|
|
||||||
error: comparison to empty slice
|
error: comparison to empty slice
|
||||||
--> tests/ui/len_zero.rs:96:20
|
--> tests/ui/len_zero.rs:102:20
|
||||||
|
|
|
|
||||||
LL | println!("{}", **s2 == "");
|
LL | println!("{}", **s2 == "");
|
||||||
| ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()`
|
| ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()`
|
||||||
|
|
||||||
error: comparison to empty slice
|
error: comparison to empty slice
|
||||||
--> tests/ui/len_zero.rs:97:20
|
--> tests/ui/len_zero.rs:103:20
|
||||||
|
|
|
|
||||||
LL | println!("{}", ***s3 == "");
|
LL | println!("{}", ***s3 == "");
|
||||||
| ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()`
|
| ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()`
|
||||||
|
|
||||||
error: comparison to empty slice
|
error: comparison to empty slice
|
||||||
--> tests/ui/len_zero.rs:98:20
|
--> tests/ui/len_zero.rs:104:20
|
||||||
|
|
|
|
||||||
LL | println!("{}", ****s4 == "");
|
LL | println!("{}", ****s4 == "");
|
||||||
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()`
|
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()`
|
||||||
|
|
||||||
error: comparison to empty slice
|
error: comparison to empty slice
|
||||||
--> tests/ui/len_zero.rs:99:20
|
--> tests/ui/len_zero.rs:105:20
|
||||||
|
|
|
|
||||||
LL | println!("{}", *****s5 == "");
|
LL | println!("{}", *****s5 == "");
|
||||||
| ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()`
|
| ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()`
|
||||||
|
|
||||||
error: comparison to empty slice
|
error: comparison to empty slice
|
||||||
--> tests/ui/len_zero.rs:100:20
|
--> tests/ui/len_zero.rs:106:20
|
||||||
|
|
|
|
||||||
LL | println!("{}", ******(s6) == "");
|
LL | println!("{}", ******(s6) == "");
|
||||||
| ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()`
|
| ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()`
|
||||||
|
|
||||||
error: comparison to empty slice
|
error: comparison to empty slice
|
||||||
--> tests/ui/len_zero.rs:103:20
|
--> tests/ui/len_zero.rs:109:20
|
||||||
|
|
|
|
||||||
LL | println!("{}", &**d2s == "");
|
LL | println!("{}", &**d2s == "");
|
||||||
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
|
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
|
||||||
|
|
||||||
error: length comparison to zero
|
error: length comparison to zero
|
||||||
--> tests/ui/len_zero.rs:118:8
|
--> tests/ui/len_zero.rs:124: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
|
||||||
--> tests/ui/len_zero.rs:121:8
|
--> tests/ui/len_zero.rs:127: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
|
||||||
--> tests/ui/len_zero.rs:124:8
|
--> tests/ui/len_zero.rs:130: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
|
||||||
--> tests/ui/len_zero.rs:127:8
|
--> tests/ui/len_zero.rs:133: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
|
||||||
--> tests/ui/len_zero.rs:130:8
|
--> tests/ui/len_zero.rs:136: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
|
||||||
--> tests/ui/len_zero.rs:141:8
|
--> tests/ui/len_zero.rs:147: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
|
||||||
--> tests/ui/len_zero.rs:144:8
|
--> tests/ui/len_zero.rs:150: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
|
||||||
--> tests/ui/len_zero.rs:147:8
|
--> tests/ui/len_zero.rs:153: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
|
||||||
--> tests/ui/len_zero.rs:150:8
|
--> tests/ui/len_zero.rs:156: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
|
||||||
--> tests/ui/len_zero.rs:153:8
|
--> tests/ui/len_zero.rs:159: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
|
||||||
--> tests/ui/len_zero.rs:167:8
|
--> tests/ui/len_zero.rs:173: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
|
||||||
--> tests/ui/len_zero.rs:179:6
|
--> tests/ui/len_zero.rs:185:6
|
||||||
|
|
|
|
||||||
LL | (has_is_empty.len() > 0).then(|| println!("This can happen."));
|
LL | (has_is_empty.len() > 0).then(|| println!("This can happen."));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ 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
|
||||||
--> tests/ui/len_zero.rs:180:6
|
--> tests/ui/len_zero.rs:186:6
|
||||||
|
|
|
|
||||||
LL | (has_is_empty.len() == 0).then(|| println!("Or this!"));
|
LL | (has_is_empty.len() == 0).then(|| println!("Or this!"));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^ 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
|
||||||
--> tests/ui/len_zero.rs:184:8
|
--> tests/ui/len_zero.rs:190: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()`
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![warn(clippy::needless_bitwise_bool)]
|
#![warn(clippy::needless_bitwise_bool)]
|
||||||
|
#![allow(clippy::const_is_empty)]
|
||||||
|
|
||||||
fn returns_bool() -> bool {
|
fn returns_bool() -> bool {
|
||||||
true
|
true
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![warn(clippy::needless_bitwise_bool)]
|
#![warn(clippy::needless_bitwise_bool)]
|
||||||
|
#![allow(clippy::const_is_empty)]
|
||||||
|
|
||||||
fn returns_bool() -> bool {
|
fn returns_bool() -> bool {
|
||||||
true
|
true
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: use of bitwise operator instead of lazy operator between booleans
|
error: use of bitwise operator instead of lazy operator between booleans
|
||||||
--> tests/ui/needless_bitwise_bool.rs:22:8
|
--> tests/ui/needless_bitwise_bool.rs:23:8
|
||||||
|
|
|
|
||||||
LL | if y & !x {
|
LL | if y & !x {
|
||||||
| ^^^^^^ help: try: `y && !x`
|
| ^^^^^^ help: try: `y && !x`
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![warn(clippy::redundant_as_str)]
|
#![warn(clippy::redundant_as_str)]
|
||||||
|
#![allow(clippy::const_is_empty)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let string = "Hello, world!".to_owned();
|
let string = "Hello, world!".to_owned();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#![warn(clippy::redundant_as_str)]
|
#![warn(clippy::redundant_as_str)]
|
||||||
|
#![allow(clippy::const_is_empty)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let string = "Hello, world!".to_owned();
|
let string = "Hello, world!".to_owned();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too
|
error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too
|
||||||
--> tests/ui/redundant_as_str.rs:7:29
|
--> tests/ui/redundant_as_str.rs:8:29
|
||||||
|
|
|
|
||||||
LL | let _redundant = string.as_str().as_bytes();
|
LL | let _redundant = string.as_str().as_bytes();
|
||||||
| ^^^^^^^^^^^^^^^^^ help: try: `as_bytes`
|
| ^^^^^^^^^^^^^^^^^ help: try: `as_bytes`
|
||||||
@ -8,7 +8,7 @@ LL | let _redundant = string.as_str().as_bytes();
|
|||||||
= help: to override `-D warnings` add `#[allow(clippy::redundant_as_str)]`
|
= help: to override `-D warnings` add `#[allow(clippy::redundant_as_str)]`
|
||||||
|
|
||||||
error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too
|
error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too
|
||||||
--> tests/ui/redundant_as_str.rs:8:29
|
--> tests/ui/redundant_as_str.rs:9:29
|
||||||
|
|
|
|
||||||
LL | let _redundant = string.as_str().is_empty();
|
LL | let _redundant = string.as_str().is_empty();
|
||||||
| ^^^^^^^^^^^^^^^^^ help: try: `is_empty`
|
| ^^^^^^^^^^^^^^^^^ help: try: `is_empty`
|
||||||
|
Loading…
Reference in New Issue
Block a user