Auto merge of #10155 - TheNeikos:feature/add_byte_char_slice_lint, r=Manishearth
Add new lint for byte char slices This patch adds a new lint that checks for potentially harder to read byte char slices: `&[b'a', b'b']` and suggests to replace them with the easier to read `b"ab"` form. Fixes #10147 --- changelog: new lint: [`byte_char_slices`] [#10155](https://github.com/rust-lang/rust-clippy/pull/10155) <!-- changelog_checked -->
This commit is contained in:
commit
2b01d69212
@ -5236,6 +5236,7 @@ Released 2018-09-13
|
|||||||
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
|
[`boxed_local`]: https://rust-lang.github.io/rust-clippy/master/index.html#boxed_local
|
||||||
[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
|
[`branches_sharing_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#branches_sharing_code
|
||||||
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
|
[`builtin_type_shadow`]: https://rust-lang.github.io/rust-clippy/master/index.html#builtin_type_shadow
|
||||||
|
[`byte_char_slices`]: https://rust-lang.github.io/rust-clippy/master/index.html#byte_char_slices
|
||||||
[`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len
|
[`bytes_count_to_len`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_count_to_len
|
||||||
[`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth
|
[`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
|
[`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata
|
||||||
|
80
clippy_lints/src/byte_char_slices.rs
Normal file
80
clippy_lints/src/byte_char_slices.rs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||||
|
use rustc_ast::ast::{BorrowKind, Expr, ExprKind, Mutability};
|
||||||
|
use rustc_ast::token::{Lit, LitKind};
|
||||||
|
use rustc_errors::Applicability;
|
||||||
|
use rustc_lint::{EarlyContext, EarlyLintPass};
|
||||||
|
use rustc_session::declare_lint_pass;
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for hard to read slices of byte characters, that could be more easily expressed as a
|
||||||
|
/// byte string.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
///
|
||||||
|
/// Potentially makes the string harder to read.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```ignore
|
||||||
|
/// &[b'H', b'e', b'l', b'l', b'o'];
|
||||||
|
/// ```
|
||||||
|
/// Use instead:
|
||||||
|
/// ```ignore
|
||||||
|
/// b"Hello"
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.68.0"]
|
||||||
|
pub BYTE_CHAR_SLICES,
|
||||||
|
style,
|
||||||
|
"hard to read byte char slice"
|
||||||
|
}
|
||||||
|
declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]);
|
||||||
|
|
||||||
|
impl EarlyLintPass for ByteCharSlice {
|
||||||
|
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
|
||||||
|
if let Some(slice) = is_byte_char_slices(expr)
|
||||||
|
&& !expr.span.from_expansion()
|
||||||
|
{
|
||||||
|
span_lint_and_sugg(
|
||||||
|
cx,
|
||||||
|
BYTE_CHAR_SLICES,
|
||||||
|
expr.span,
|
||||||
|
"can be more succinctly written as a byte str",
|
||||||
|
"try",
|
||||||
|
format!("b\"{slice}\""),
|
||||||
|
Applicability::MaybeIncorrect,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_byte_char_slices(expr: &Expr) -> Option<String> {
|
||||||
|
if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind {
|
||||||
|
match &expr.kind {
|
||||||
|
ExprKind::Array(members) => {
|
||||||
|
if members.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
members
|
||||||
|
.iter()
|
||||||
|
.map(|member| match &member.kind {
|
||||||
|
ExprKind::Lit(Lit {
|
||||||
|
kind: LitKind::Byte,
|
||||||
|
symbol,
|
||||||
|
..
|
||||||
|
}) => Some(symbol.as_str()),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
.map(|maybe_quote| match maybe_quote {
|
||||||
|
Some("\"") => Some("\\\""),
|
||||||
|
Some("\\'") => Some("'"),
|
||||||
|
other => other,
|
||||||
|
})
|
||||||
|
.collect::<Option<String>>()
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
@ -73,6 +73,7 @@
|
|||||||
crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
|
crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
|
||||||
crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
|
crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
|
||||||
crate::box_default::BOX_DEFAULT_INFO,
|
crate::box_default::BOX_DEFAULT_INFO,
|
||||||
|
crate::byte_char_slices::BYTE_CHAR_SLICES_INFO,
|
||||||
crate::cargo::CARGO_COMMON_METADATA_INFO,
|
crate::cargo::CARGO_COMMON_METADATA_INFO,
|
||||||
crate::cargo::LINT_GROUPS_PRIORITY_INFO,
|
crate::cargo::LINT_GROUPS_PRIORITY_INFO,
|
||||||
crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
|
crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
|
||||||
|
@ -89,6 +89,7 @@
|
|||||||
mod booleans;
|
mod booleans;
|
||||||
mod borrow_deref_ref;
|
mod borrow_deref_ref;
|
||||||
mod box_default;
|
mod box_default;
|
||||||
|
mod byte_char_slices;
|
||||||
mod cargo;
|
mod cargo;
|
||||||
mod casts;
|
mod casts;
|
||||||
mod checked_conversions;
|
mod checked_conversions;
|
||||||
@ -1174,6 +1175,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||||||
store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
|
store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
|
||||||
store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
|
store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
|
||||||
store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
|
store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
|
||||||
|
store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice));
|
||||||
// add lints here, do not remove this comment, it's used in `new_lint`
|
// add lints here, do not remove this comment, it's used in `new_lint`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
tests/ui/byte_char_slices.fixed
Normal file
13
tests/ui/byte_char_slices.fixed
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#![allow(unused)]
|
||||||
|
#![warn(clippy::byte_char_slices)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let bad = b"abc";
|
||||||
|
let quotes = b"\"Hi";
|
||||||
|
let quotes = b"'Sup";
|
||||||
|
let escapes = b"\x42Esc";
|
||||||
|
|
||||||
|
let good = &[b'a', 0x42];
|
||||||
|
let good = [b'a', b'a'];
|
||||||
|
let good: u8 = [b'a', b'c'].into_iter().sum();
|
||||||
|
}
|
13
tests/ui/byte_char_slices.rs
Normal file
13
tests/ui/byte_char_slices.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#![allow(unused)]
|
||||||
|
#![warn(clippy::byte_char_slices)]
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let bad = &[b'a', b'b', b'c'];
|
||||||
|
let quotes = &[b'"', b'H', b'i'];
|
||||||
|
let quotes = &[b'\'', b'S', b'u', b'p'];
|
||||||
|
let escapes = &[b'\x42', b'E', b's', b'c'];
|
||||||
|
|
||||||
|
let good = &[b'a', 0x42];
|
||||||
|
let good = vec![b'a', b'a'];
|
||||||
|
let good: u8 = [b'a', b'c'].into_iter().sum();
|
||||||
|
}
|
38
tests/ui/byte_char_slices.stderr
Normal file
38
tests/ui/byte_char_slices.stderr
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
error: can be more succinctly written as a byte str
|
||||||
|
--> tests/ui/byte_char_slices.rs:5:15
|
||||||
|
|
|
||||||
|
LL | let bad = &[b'a', b'b', b'c'];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ help: try: `b"abc"`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::byte-char-slices` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]`
|
||||||
|
|
||||||
|
error: can be more succinctly written as a byte str
|
||||||
|
--> tests/ui/byte_char_slices.rs:6:18
|
||||||
|
|
|
||||||
|
LL | let quotes = &[b'"', b'H', b'i'];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"`
|
||||||
|
|
||||||
|
error: can be more succinctly written as a byte str
|
||||||
|
--> tests/ui/byte_char_slices.rs:7:18
|
||||||
|
|
|
||||||
|
LL | let quotes = &[b'\'', b'S', b'u', b'p'];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"`
|
||||||
|
|
||||||
|
error: can be more succinctly written as a byte str
|
||||||
|
--> tests/ui/byte_char_slices.rs:8:19
|
||||||
|
|
|
||||||
|
LL | let escapes = &[b'\x42', b'E', b's', b'c'];
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"`
|
||||||
|
|
||||||
|
error: useless use of `vec!`
|
||||||
|
--> tests/ui/byte_char_slices.rs:11:16
|
||||||
|
|
|
||||||
|
LL | let good = vec![b'a', b'a'];
|
||||||
|
| ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']`
|
||||||
|
|
|
||||||
|
= note: `-D clippy::useless-vec` implied by `-D warnings`
|
||||||
|
= help: to override `-D warnings` add `#[allow(clippy::useless_vec)]`
|
||||||
|
|
||||||
|
error: aborting due to 5 previous errors
|
||||||
|
|
Loading…
Reference in New Issue
Block a user