New lint needless_as_bytes
This commit is contained in:
parent
73bad368f2
commit
62c4daf358
@ -5761,6 +5761,7 @@ Released 2018-09-13
|
|||||||
[`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
|
[`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer
|
||||||
[`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
|
[`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount
|
||||||
[`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
|
[`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type
|
||||||
|
[`needless_as_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_as_bytes
|
||||||
[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
|
[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool
|
||||||
[`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
|
[`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool
|
||||||
[`needless_bool_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign
|
[`needless_bool_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign
|
||||||
|
@ -424,6 +424,7 @@
|
|||||||
crate::methods::MAP_UNWRAP_OR_INFO,
|
crate::methods::MAP_UNWRAP_OR_INFO,
|
||||||
crate::methods::MUT_MUTEX_LOCK_INFO,
|
crate::methods::MUT_MUTEX_LOCK_INFO,
|
||||||
crate::methods::NAIVE_BYTECOUNT_INFO,
|
crate::methods::NAIVE_BYTECOUNT_INFO,
|
||||||
|
crate::methods::NEEDLESS_AS_BYTES_INFO,
|
||||||
crate::methods::NEEDLESS_CHARACTER_ITERATION_INFO,
|
crate::methods::NEEDLESS_CHARACTER_ITERATION_INFO,
|
||||||
crate::methods::NEEDLESS_COLLECT_INFO,
|
crate::methods::NEEDLESS_COLLECT_INFO,
|
||||||
crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO,
|
crate::methods::NEEDLESS_OPTION_AS_DEREF_INFO,
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
mod map_identity;
|
mod map_identity;
|
||||||
mod map_unwrap_or;
|
mod map_unwrap_or;
|
||||||
mod mut_mutex_lock;
|
mod mut_mutex_lock;
|
||||||
|
mod needless_as_bytes;
|
||||||
mod needless_character_iteration;
|
mod needless_character_iteration;
|
||||||
mod needless_collect;
|
mod needless_collect;
|
||||||
mod needless_option_as_deref;
|
mod needless_option_as_deref;
|
||||||
@ -4166,6 +4167,31 @@
|
|||||||
"calling `.first().is_some()` or `.first().is_none()` instead of `.is_empty()`"
|
"calling `.first().is_some()` or `.first().is_none()` instead of `.is_empty()`"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// It detects useless calls to `str::as_bytes()` before calling `len()` or `is_empty()`.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// The `len()` and `is_empty()` methods are also directly available on strings, and they
|
||||||
|
/// return identical results. In particular, `len()` on a string returns the number of
|
||||||
|
/// bytes.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```
|
||||||
|
/// let len = "some string".as_bytes().len();
|
||||||
|
/// let b = "some string".as_bytes().is_empty();
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```
|
||||||
|
/// let len = "some string".len();
|
||||||
|
/// let b = "some string".is_empty();
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.84.0"]
|
||||||
|
pub NEEDLESS_AS_BYTES,
|
||||||
|
complexity,
|
||||||
|
"detect useless calls to `as_bytes()`"
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Methods {
|
pub struct Methods {
|
||||||
avoid_breaking_exported_api: bool,
|
avoid_breaking_exported_api: bool,
|
||||||
msrv: Msrv,
|
msrv: Msrv,
|
||||||
@ -4327,6 +4353,7 @@ pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
|
|||||||
NEEDLESS_CHARACTER_ITERATION,
|
NEEDLESS_CHARACTER_ITERATION,
|
||||||
MANUAL_INSPECT,
|
MANUAL_INSPECT,
|
||||||
UNNECESSARY_MIN_OR_MAX,
|
UNNECESSARY_MIN_OR_MAX,
|
||||||
|
NEEDLESS_AS_BYTES,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/// Extracts a method call name, args, and `Span` of the method name.
|
/// Extracts a method call name, args, and `Span` of the method name.
|
||||||
@ -4764,8 +4791,14 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||||||
unit_hash::check(cx, expr, recv, arg);
|
unit_hash::check(cx, expr, recv, arg);
|
||||||
},
|
},
|
||||||
("is_empty", []) => {
|
("is_empty", []) => {
|
||||||
if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
|
match method_call(recv) {
|
||||||
|
Some(("as_bytes", prev_recv, [], _, _)) => {
|
||||||
|
needless_as_bytes::check(cx, "is_empty", recv, prev_recv, expr.span);
|
||||||
|
},
|
||||||
|
Some(("as_str", recv, [], as_str_span, _)) => {
|
||||||
redundant_as_str::check(cx, expr, recv, as_str_span, span);
|
redundant_as_str::check(cx, expr, recv, as_str_span, span);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
}
|
}
|
||||||
is_empty::check(cx, expr, recv);
|
is_empty::check(cx, expr, recv);
|
||||||
},
|
},
|
||||||
@ -4795,6 +4828,11 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
("len", []) => {
|
||||||
|
if let Some(("as_bytes", prev_recv, [], _, _)) = method_call(recv) {
|
||||||
|
needless_as_bytes::check(cx, "len", recv, prev_recv, expr.span);
|
||||||
|
}
|
||||||
|
},
|
||||||
("lock", []) => {
|
("lock", []) => {
|
||||||
mut_mutex_lock::check(cx, expr, recv, span);
|
mut_mutex_lock::check(cx, expr, recv, span);
|
||||||
},
|
},
|
||||||
|
28
clippy_lints/src/methods/needless_as_bytes.rs
Normal file
28
clippy_lints/src/methods/needless_as_bytes.rs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use clippy_utils::sugg::Sugg;
|
||||||
|
use clippy_utils::ty::is_type_lang_item;
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_hir::{Expr, LangItem};
|
||||||
|
use rustc_lint::LateContext;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
use super::NEEDLESS_AS_BYTES;
|
||||||
|
|
||||||
|
pub fn check(cx: &LateContext<'_>, method: &str, recv: &Expr<'_>, prev_recv: &Expr<'_>, span: Span) {
|
||||||
|
if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
|
||||||
|
&& let ty1 = cx.typeck_results().expr_ty_adjusted(prev_recv).peel_refs()
|
||||||
|
&& (is_type_lang_item(cx, ty1, LangItem::String) || ty1.is_str())
|
||||||
|
{
|
||||||
|
let mut app = Applicability::MachineApplicable;
|
||||||
|
let sugg = Sugg::hir_with_context(cx, prev_recv, span.ctxt(), "..", &mut app);
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
NEEDLESS_AS_BYTES,
|
||||||
|
span,
|
||||||
|
"needless call to `as_bytes()`",
|
||||||
|
format!("`{method}()` can be called directly on strings"),
|
||||||
|
format!("{sugg}.{method}()"),
|
||||||
|
app,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
50
tests/ui/needless_as_bytes.fixed
Normal file
50
tests/ui/needless_as_bytes.fixed
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#![warn(clippy::needless_as_bytes)]
|
||||||
|
#![allow(clippy::const_is_empty)]
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
fn as_bytes(&self) -> &[u8] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if "some string".is_empty() {
|
||||||
|
//~^ needless_as_bytes
|
||||||
|
println!("len = {}", "some string".len());
|
||||||
|
//~^ needless_as_bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
let s = String::from("yet another string");
|
||||||
|
if s.is_empty() {
|
||||||
|
//~^ needless_as_bytes
|
||||||
|
println!("len = {}", s.len());
|
||||||
|
//~^ needless_as_bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not lint
|
||||||
|
let _ = S.as_bytes().is_empty();
|
||||||
|
let _ = S.as_bytes().len();
|
||||||
|
let _ = (&String::new() as &dyn AsBytes).as_bytes().len();
|
||||||
|
macro_rules! m {
|
||||||
|
(1) => {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
(2) => {
|
||||||
|
"".as_bytes()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
m!(1).as_bytes().len();
|
||||||
|
m!(2).len();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AsBytes {
|
||||||
|
fn as_bytes(&self) -> &[u8];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsBytes for String {
|
||||||
|
fn as_bytes(&self) -> &[u8] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
50
tests/ui/needless_as_bytes.rs
Normal file
50
tests/ui/needless_as_bytes.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#![warn(clippy::needless_as_bytes)]
|
||||||
|
#![allow(clippy::const_is_empty)]
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl S {
|
||||||
|
fn as_bytes(&self) -> &[u8] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
if "some string".as_bytes().is_empty() {
|
||||||
|
//~^ needless_as_bytes
|
||||||
|
println!("len = {}", "some string".as_bytes().len());
|
||||||
|
//~^ needless_as_bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
let s = String::from("yet another string");
|
||||||
|
if s.as_bytes().is_empty() {
|
||||||
|
//~^ needless_as_bytes
|
||||||
|
println!("len = {}", s.as_bytes().len());
|
||||||
|
//~^ needless_as_bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not lint
|
||||||
|
let _ = S.as_bytes().is_empty();
|
||||||
|
let _ = S.as_bytes().len();
|
||||||
|
let _ = (&String::new() as &dyn AsBytes).as_bytes().len();
|
||||||
|
macro_rules! m {
|
||||||
|
(1) => {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
(2) => {
|
||||||
|
"".as_bytes()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
m!(1).as_bytes().len();
|
||||||
|
m!(2).len();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AsBytes {
|
||||||
|
fn as_bytes(&self) -> &[u8];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsBytes for String {
|
||||||
|
fn as_bytes(&self) -> &[u8] {
|
||||||
|
&[]
|
||||||
|
}
|
||||||
|
}
|
29
tests/ui/needless_as_bytes.stderr
Normal file
29
tests/ui/needless_as_bytes.stderr
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
error: needless call to `as_bytes()`
|
||||||
|
--> tests/ui/needless_as_bytes.rs:13:8
|
||||||
|
|
|
||||||
|
LL | if "some string".as_bytes().is_empty() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `"some string".is_empty()`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::needless-as-bytes` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::needless_as_bytes)]`
|
||||||
|
|
||||||
|
error: needless call to `as_bytes()`
|
||||||
|
--> tests/ui/needless_as_bytes.rs:15:30
|
||||||
|
|
|
||||||
|
LL | println!("len = {}", "some string".as_bytes().len());
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `"some string".len()`
|
||||||
|
|
||||||
|
error: needless call to `as_bytes()`
|
||||||
|
--> tests/ui/needless_as_bytes.rs:20:8
|
||||||
|
|
|
||||||
|
LL | if s.as_bytes().is_empty() {
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `s.is_empty()`
|
||||||
|
|
||||||
|
error: needless call to `as_bytes()`
|
||||||
|
--> tests/ui/needless_as_bytes.rs:22:30
|
||||||
|
|
|
||||||
|
LL | println!("len = {}", s.as_bytes().len());
|
||||||
|
| ^^^^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `s.len()`
|
||||||
|
|
||||||
|
error: aborting due to 4 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user