add a new lint bytes_nth

This commit is contained in:
Takayuki Maeda 2021-02-08 01:34:59 +09:00
parent c1ce78f0b2
commit 1c3033d5cf
7 changed files with 102 additions and 0 deletions

View file

@ -1877,6 +1877,7 @@ Released 2018-09-13
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
[`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons
[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless

View file

@ -734,6 +734,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
&mem_replace::MEM_REPLACE_WITH_DEFAULT,
&mem_replace::MEM_REPLACE_WITH_UNINIT,
&methods::BIND_INSTEAD_OF_MAP,
&methods::BYTES_NTH,
&methods::CHARS_LAST_CMP,
&methods::CHARS_NEXT_CMP,
&methods::CLONE_DOUBLE_REF,
@ -1531,6 +1532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
LintId::of(&methods::BIND_INSTEAD_OF_MAP),
LintId::of(&methods::BYTES_NTH),
LintId::of(&methods::CHARS_LAST_CMP),
LintId::of(&methods::CHARS_NEXT_CMP),
LintId::of(&methods::CLONE_DOUBLE_REF),
@ -1749,6 +1751,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
LintId::of(&matches::SINGLE_MATCH),
LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
LintId::of(&methods::BYTES_NTH),
LintId::of(&methods::CHARS_LAST_CMP),
LintId::of(&methods::CHARS_NEXT_CMP),
LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),

View file

@ -0,0 +1,39 @@
use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::sym;
use super::BYTES_NTH;
pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) {
if_chain! {
if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind;
let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs();
let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) {
Some("String")
} else if ty.is_str() {
Some("str")
} else {
None
};
if let Some(caller_type) = caller_type;
then {
let mut applicability = Applicability::MachineApplicable;
span_lint_and_sugg(
cx,
BYTES_NTH,
expr.span,
&format!("called `.byte().nth()` on a `{}`", caller_type),
"try calling `.as_bytes().get()`",
format!(
"{}.as_bytes().get({})",
snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability),
snippet_with_applicability(cx, args[1].span, "..", &mut applicability)
),
applicability,
);
}
}
}

View file

@ -1,4 +1,5 @@
mod bind_instead_of_map;
mod bytes_nth;
mod filter_map_identity;
mod inefficient_to_string;
mod inspect_for_each;
@ -1490,6 +1491,28 @@ declare_clippy_lint! {
"call to `filter_map` where `flatten` is sufficient"
}
declare_clippy_lint! {
/// **What it does:** Checks for the use of `.bytes().nth()`.
///
/// **Why is this bad?** `.as_bytes().get()` is more efficient and more
/// readable.
///
/// **Known problems:** None.
///
/// **Example:**
///
/// ```rust
/// // Bad
/// let _ = "Hello".bytes().nth(3);;
///
/// // Good
/// let _ = "Hello".as_bytes().get(3);
/// ```
pub BYTES_NTH,
style,
"replace `.bytes().nth()` with `.as_bytes().get()`"
}
pub struct Methods {
msrv: Option<RustcVersion>,
}
@ -1537,6 +1560,7 @@ impl_lint_pass!(Methods => [
ITER_NEXT_SLICE,
ITER_NTH,
ITER_NTH_ZERO,
BYTES_NTH,
ITER_SKIP_NEXT,
GET_UNWRAP,
STRING_EXTEND_CHARS,
@ -1614,6 +1638,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false),
["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true),
["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]),
["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]),
["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]),
["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]),

9
tests/ui/bytes_nth.fixed Normal file
View file

@ -0,0 +1,9 @@
// run-rustfix
#![warn(clippy::bytes_nth)]
fn main() {
let _ = "Hello".as_bytes().get(3);
let _ = String::from("Hello").as_bytes().get(3);
}

9
tests/ui/bytes_nth.rs Normal file
View file

@ -0,0 +1,9 @@
// run-rustfix
#![warn(clippy::bytes_nth)]
fn main() {
let _ = "Hello".bytes().nth(3);
let _ = String::from("Hello").bytes().nth(3);
}

16
tests/ui/bytes_nth.stderr Normal file
View file

@ -0,0 +1,16 @@
error: called `.byte().nth()` on a `str`
--> $DIR/bytes_nth.rs:6:13
|
LL | let _ = "Hello".bytes().nth(3);
| ^^^^^^^^^^^^^^^^^^^^^^ help: try calling `.as_bytes().get()`: `"Hello".as_bytes().get(3)`
|
= note: `-D clippy::bytes-nth` implied by `-D warnings`
error: called `.byte().nth()` on a `String`
--> $DIR/bytes_nth.rs:8:13
|
LL | let _ = String::from("Hello").bytes().nth(3);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try calling `.as_bytes().get()`: `String::from("Hello").as_bytes().get(3)`
error: aborting due to 2 previous errors