Skip to content

Commit b5e4389

Browse files
committed
Auto merge of #6695 - TaKO8Ki:add-bytes-nth, r=phansch
New lint: `bytes_nth` This pull request adds a new lint named `bytes_nth`. --- closes: #6391 changelog: Added a new lint: `bytes_nth`
2 parents 9c0ae2a + 5996ae1 commit b5e4389

File tree

7 files changed

+112
-0
lines changed

7 files changed

+112
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,6 +1877,7 @@ Released 2018-09-13
18771877
[`box_vec`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_vec
18781878
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
18791879
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
1880+
[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
18801881
[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
18811882
[`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons
18821883
[`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless

clippy_lints/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
734734
&mem_replace::MEM_REPLACE_WITH_DEFAULT,
735735
&mem_replace::MEM_REPLACE_WITH_UNINIT,
736736
&methods::BIND_INSTEAD_OF_MAP,
737+
&methods::BYTES_NTH,
737738
&methods::CHARS_LAST_CMP,
738739
&methods::CHARS_NEXT_CMP,
739740
&methods::CLONE_DOUBLE_REF,
@@ -1531,6 +1532,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15311532
LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
15321533
LintId::of(&mem_replace::MEM_REPLACE_WITH_UNINIT),
15331534
LintId::of(&methods::BIND_INSTEAD_OF_MAP),
1535+
LintId::of(&methods::BYTES_NTH),
15341536
LintId::of(&methods::CHARS_LAST_CMP),
15351537
LintId::of(&methods::CHARS_NEXT_CMP),
15361538
LintId::of(&methods::CLONE_DOUBLE_REF),
@@ -1748,6 +1750,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
17481750
LintId::of(&matches::SINGLE_MATCH),
17491751
LintId::of(&mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
17501752
LintId::of(&mem_replace::MEM_REPLACE_WITH_DEFAULT),
1753+
LintId::of(&methods::BYTES_NTH),
17511754
LintId::of(&methods::CHARS_LAST_CMP),
17521755
LintId::of(&methods::CHARS_NEXT_CMP),
17531756
LintId::of(&methods::FROM_ITER_INSTEAD_OF_COLLECT),

clippy_lints/src/methods/bytes_nth.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg};
2+
use if_chain::if_chain;
3+
use rustc_errors::Applicability;
4+
use rustc_hir::{Expr, ExprKind};
5+
use rustc_lint::LateContext;
6+
use rustc_span::sym;
7+
8+
use super::BYTES_NTH;
9+
10+
pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) {
11+
if_chain! {
12+
if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind;
13+
let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs();
14+
let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) {
15+
Some("String")
16+
} else if ty.is_str() {
17+
Some("str")
18+
} else {
19+
None
20+
};
21+
if let Some(caller_type) = caller_type;
22+
then {
23+
let mut applicability = Applicability::MachineApplicable;
24+
span_lint_and_sugg(
25+
cx,
26+
BYTES_NTH,
27+
expr.span,
28+
&format!("called `.byte().nth()` on a `{}`", caller_type),
29+
"try",
30+
format!(
31+
"{}.as_bytes().get({})",
32+
snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability),
33+
snippet_with_applicability(cx, args[1].span, "..", &mut applicability)
34+
),
35+
applicability,
36+
);
37+
}
38+
}
39+
}

clippy_lints/src/methods/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod bind_instead_of_map;
2+
mod bytes_nth;
23
mod filter_map_identity;
34
mod inefficient_to_string;
45
mod inspect_for_each;
@@ -1490,6 +1491,28 @@ declare_clippy_lint! {
14901491
"call to `filter_map` where `flatten` is sufficient"
14911492
}
14921493

1494+
declare_clippy_lint! {
1495+
/// **What it does:** Checks for the use of `.bytes().nth()`.
1496+
///
1497+
/// **Why is this bad?** `.as_bytes().get()` is more efficient and more
1498+
/// readable.
1499+
///
1500+
/// **Known problems:** None.
1501+
///
1502+
/// **Example:**
1503+
///
1504+
/// ```rust
1505+
/// // Bad
1506+
/// let _ = "Hello".bytes().nth(3);;
1507+
///
1508+
/// // Good
1509+
/// let _ = "Hello".as_bytes().get(3);
1510+
/// ```
1511+
pub BYTES_NTH,
1512+
style,
1513+
"replace `.bytes().nth()` with `.as_bytes().get()`"
1514+
}
1515+
14931516
pub struct Methods {
14941517
msrv: Option<RustcVersion>,
14951518
}
@@ -1537,6 +1560,7 @@ impl_lint_pass!(Methods => [
15371560
ITER_NEXT_SLICE,
15381561
ITER_NTH,
15391562
ITER_NTH_ZERO,
1563+
BYTES_NTH,
15401564
ITER_SKIP_NEXT,
15411565
GET_UNWRAP,
15421566
STRING_EXTEND_CHARS,
@@ -1614,6 +1638,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
16141638
["extend", ..] => lint_extend(cx, expr, arg_lists[0]),
16151639
["nth", "iter"] => lint_iter_nth(cx, expr, &arg_lists, false),
16161640
["nth", "iter_mut"] => lint_iter_nth(cx, expr, &arg_lists, true),
1641+
["nth", "bytes"] => bytes_nth::lints(cx, expr, &arg_lists[1]),
16171642
["nth", ..] => lint_iter_nth_zero(cx, expr, arg_lists[0]),
16181643
["step_by", ..] => lint_step_by(cx, expr, arg_lists[0]),
16191644
["next", "skip"] => lint_iter_skip_next(cx, expr, arg_lists[1]),

tests/ui/bytes_nth.fixed

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-rustfix
2+
3+
#![allow(clippy::unnecessary_operation)]
4+
#![warn(clippy::bytes_nth)]
5+
6+
fn main() {
7+
let s = String::from("String");
8+
s.as_bytes().get(3);
9+
&s.as_bytes().get(3);
10+
s[..].as_bytes().get(3);
11+
}

tests/ui/bytes_nth.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// run-rustfix
2+
3+
#![allow(clippy::unnecessary_operation)]
4+
#![warn(clippy::bytes_nth)]
5+
6+
fn main() {
7+
let s = String::from("String");
8+
s.bytes().nth(3);
9+
&s.bytes().nth(3);
10+
s[..].bytes().nth(3);
11+
}

tests/ui/bytes_nth.stderr

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error: called `.byte().nth()` on a `String`
2+
--> $DIR/bytes_nth.rs:8:5
3+
|
4+
LL | s.bytes().nth(3);
5+
| ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
6+
|
7+
= note: `-D clippy::bytes-nth` implied by `-D warnings`
8+
9+
error: called `.byte().nth()` on a `String`
10+
--> $DIR/bytes_nth.rs:9:6
11+
|
12+
LL | &s.bytes().nth(3);
13+
| ^^^^^^^^^^^^^^^^ help: try: `s.as_bytes().get(3)`
14+
15+
error: called `.byte().nth()` on a `str`
16+
--> $DIR/bytes_nth.rs:10:5
17+
|
18+
LL | s[..].bytes().nth(3);
19+
| ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3)`
20+
21+
error: aborting due to 3 previous errors
22+

0 commit comments

Comments
 (0)