mirror of
https://github.com/rust-lang/rust-clippy
synced 2024-11-23 21:23:56 +00:00
Auto merge of #11852 - rust-lang:single-char-pattern-ascii-only, r=xFrednet
reduce `single_char_pattern` to only lint on ascii chars This should mostly fix the `single_char_pattern` lint, because with a single byte, the optimizer will usually see through the char-to-string-expansion and single loop iteration. This fixes #11675 and #8111. Update: As per the meeting on November 28th, 2023, we voted to also downgrade the lint to pedantic. --- changelog: downgrade [`single_char_pattern`] to `pedantic`
This commit is contained in:
commit
fc6dfeb1bf
8 changed files with 49 additions and 66 deletions
|
@ -1145,11 +1145,16 @@ declare_clippy_lint! {
|
||||||
/// `str` as an argument, e.g., `_.split("x")`.
|
/// `str` as an argument, e.g., `_.split("x")`.
|
||||||
///
|
///
|
||||||
/// ### Why is this bad?
|
/// ### Why is this bad?
|
||||||
/// Performing these methods using a `char` is faster than
|
/// While this can make a perf difference on some systems,
|
||||||
/// using a `str`.
|
/// benchmarks have proven inconclusive. But at least using a
|
||||||
|
/// char literal makes it clear that we are looking at a single
|
||||||
|
/// character.
|
||||||
///
|
///
|
||||||
/// ### Known problems
|
/// ### Known problems
|
||||||
/// Does not catch multi-byte unicode characters.
|
/// Does not catch multi-byte unicode characters. This is by
|
||||||
|
/// design, on many machines, splitting by a non-ascii char is
|
||||||
|
/// actually slower. Please do your own measurements instead of
|
||||||
|
/// relying solely on the results of this lint.
|
||||||
///
|
///
|
||||||
/// ### Example
|
/// ### Example
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
|
@ -1162,7 +1167,7 @@ declare_clippy_lint! {
|
||||||
/// ```
|
/// ```
|
||||||
#[clippy::version = "pre 1.29.0"]
|
#[clippy::version = "pre 1.29.0"]
|
||||||
pub SINGLE_CHAR_PATTERN,
|
pub SINGLE_CHAR_PATTERN,
|
||||||
perf,
|
pedantic,
|
||||||
"using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
|
"using a single-character str where a char could be used, e.g., `_.split(\"x\")`"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR;
|
||||||
/// lint for length-1 `str`s as argument for `insert_str`
|
/// lint for length-1 `str`s as argument for `insert_str`
|
||||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability) {
|
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[1], &mut applicability, false) {
|
||||||
let base_string_snippet =
|
let base_string_snippet =
|
||||||
snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
|
snippet_with_applicability(cx, receiver.span.source_callsite(), "_", &mut applicability);
|
||||||
let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
|
let pos_arg = snippet_with_applicability(cx, args[0].span, "..", &mut applicability);
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_span::symbol::Symbol;
|
||||||
|
|
||||||
use super::SINGLE_CHAR_PATTERN;
|
use super::SINGLE_CHAR_PATTERN;
|
||||||
|
|
||||||
const PATTERN_METHODS: [(&str, usize); 24] = [
|
const PATTERN_METHODS: [(&str, usize); 22] = [
|
||||||
("contains", 0),
|
("contains", 0),
|
||||||
("starts_with", 0),
|
("starts_with", 0),
|
||||||
("ends_with", 0),
|
("ends_with", 0),
|
||||||
|
@ -27,8 +27,6 @@ const PATTERN_METHODS: [(&str, usize); 24] = [
|
||||||
("rmatches", 0),
|
("rmatches", 0),
|
||||||
("match_indices", 0),
|
("match_indices", 0),
|
||||||
("rmatch_indices", 0),
|
("rmatch_indices", 0),
|
||||||
("strip_prefix", 0),
|
|
||||||
("strip_suffix", 0),
|
|
||||||
("trim_start_matches", 0),
|
("trim_start_matches", 0),
|
||||||
("trim_end_matches", 0),
|
("trim_end_matches", 0),
|
||||||
("replace", 0),
|
("replace", 0),
|
||||||
|
@ -50,7 +48,7 @@ pub(super) fn check(
|
||||||
&& args.len() > pos
|
&& args.len() > pos
|
||||||
&& let arg = &args[pos]
|
&& let arg = &args[pos]
|
||||||
&& let mut applicability = Applicability::MachineApplicable
|
&& let mut applicability = Applicability::MachineApplicable
|
||||||
&& let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability)
|
&& let Some(hint) = get_hint_if_single_char_arg(cx, arg, &mut applicability, true)
|
||||||
{
|
{
|
||||||
span_lint_and_sugg(
|
span_lint_and_sugg(
|
||||||
cx,
|
cx,
|
||||||
|
|
|
@ -10,7 +10,7 @@ use super::SINGLE_CHAR_ADD_STR;
|
||||||
/// lint for length-1 `str`s as argument for `push_str`
|
/// lint for length-1 `str`s as argument for `push_str`
|
||||||
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::Expr<'_>, args: &[hir::Expr<'_>]) {
|
||||||
let mut applicability = Applicability::MachineApplicable;
|
let mut applicability = Applicability::MachineApplicable;
|
||||||
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability) {
|
if let Some(extension_string) = get_hint_if_single_char_arg(cx, &args[0], &mut applicability, false) {
|
||||||
let base_string_snippet =
|
let base_string_snippet =
|
||||||
snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
|
snippet_with_applicability(cx, receiver.span.source_callsite(), "..", &mut applicability);
|
||||||
let sugg = format!("{base_string_snippet}.push({extension_string})");
|
let sugg = format!("{base_string_snippet}.push({extension_string})");
|
||||||
|
|
|
@ -52,11 +52,17 @@ pub(super) fn get_hint_if_single_char_arg(
|
||||||
cx: &LateContext<'_>,
|
cx: &LateContext<'_>,
|
||||||
arg: &Expr<'_>,
|
arg: &Expr<'_>,
|
||||||
applicability: &mut Applicability,
|
applicability: &mut Applicability,
|
||||||
|
ascii_only: bool,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
if let ExprKind::Lit(lit) = &arg.kind
|
if let ExprKind::Lit(lit) = &arg.kind
|
||||||
&& let ast::LitKind::Str(r, style) = lit.node
|
&& let ast::LitKind::Str(r, style) = lit.node
|
||||||
&& let string = r.as_str()
|
&& let string = r.as_str()
|
||||||
&& string.chars().count() == 1
|
&& let len = if ascii_only {
|
||||||
|
string.len()
|
||||||
|
} else {
|
||||||
|
string.chars().count()
|
||||||
|
}
|
||||||
|
&& len == 1
|
||||||
{
|
{
|
||||||
let snip = snippet_with_applicability(cx, arg.span, string, applicability);
|
let snip = snippet_with_applicability(cx, arg.span, string, applicability);
|
||||||
let ch = if let ast::StrStyle::Raw(nhash) = style {
|
let ch = if let ast::StrStyle::Raw(nhash) = style {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)]
|
#![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)]
|
||||||
|
#![warn(clippy::single_char_pattern)]
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -10,9 +10,9 @@ fn main() {
|
||||||
|
|
||||||
let y = "x";
|
let y = "x";
|
||||||
x.split(y);
|
x.split(y);
|
||||||
x.split('ß');
|
x.split("ß");
|
||||||
x.split('ℝ');
|
x.split("ℝ");
|
||||||
x.split('💣');
|
x.split("💣");
|
||||||
// Can't use this lint for unicode code points which don't fit in a char
|
// Can't use this lint for unicode code points which don't fit in a char
|
||||||
x.split("❤️");
|
x.split("❤️");
|
||||||
x.split_inclusive('x');
|
x.split_inclusive('x');
|
||||||
|
@ -34,8 +34,6 @@ fn main() {
|
||||||
x.rmatch_indices('x');
|
x.rmatch_indices('x');
|
||||||
x.trim_start_matches('x');
|
x.trim_start_matches('x');
|
||||||
x.trim_end_matches('x');
|
x.trim_end_matches('x');
|
||||||
x.strip_prefix('x');
|
|
||||||
x.strip_suffix('x');
|
|
||||||
x.replace('x', "y");
|
x.replace('x', "y");
|
||||||
x.replacen('x', "y", 3);
|
x.replacen('x', "y", 3);
|
||||||
// Make sure we escape characters correctly.
|
// Make sure we escape characters correctly.
|
||||||
|
@ -64,4 +62,8 @@ fn main() {
|
||||||
// Must escape backslash in raw strings when converting to char #8060
|
// Must escape backslash in raw strings when converting to char #8060
|
||||||
x.split('\\');
|
x.split('\\');
|
||||||
x.split('\\');
|
x.split('\\');
|
||||||
|
|
||||||
|
// should not warn, the char versions are actually slower in some cases
|
||||||
|
x.strip_prefix("x");
|
||||||
|
x.strip_suffix("x");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)]
|
#![allow(clippy::needless_raw_strings, clippy::needless_raw_string_hashes, unused_must_use)]
|
||||||
|
#![warn(clippy::single_char_pattern)]
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -34,8 +34,6 @@ fn main() {
|
||||||
x.rmatch_indices("x");
|
x.rmatch_indices("x");
|
||||||
x.trim_start_matches("x");
|
x.trim_start_matches("x");
|
||||||
x.trim_end_matches("x");
|
x.trim_end_matches("x");
|
||||||
x.strip_prefix("x");
|
|
||||||
x.strip_suffix("x");
|
|
||||||
x.replace("x", "y");
|
x.replace("x", "y");
|
||||||
x.replacen("x", "y", 3);
|
x.replacen("x", "y", 3);
|
||||||
// Make sure we escape characters correctly.
|
// Make sure we escape characters correctly.
|
||||||
|
@ -64,4 +62,8 @@ fn main() {
|
||||||
// Must escape backslash in raw strings when converting to char #8060
|
// Must escape backslash in raw strings when converting to char #8060
|
||||||
x.split(r#"\"#);
|
x.split(r#"\"#);
|
||||||
x.split(r"\");
|
x.split(r"\");
|
||||||
|
|
||||||
|
// should not warn, the char versions are actually slower in some cases
|
||||||
|
x.strip_prefix("x");
|
||||||
|
x.strip_suffix("x");
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,24 +7,6 @@ LL | x.split("x");
|
||||||
= note: `-D clippy::single-char-pattern` implied by `-D warnings`
|
= note: `-D clippy::single-char-pattern` implied by `-D warnings`
|
||||||
= help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]`
|
= help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
|
||||||
--> tests/ui/single_char_pattern.rs:13:13
|
|
||||||
|
|
|
||||||
LL | x.split("ß");
|
|
||||||
| ^^^ help: consider using a `char`: `'ß'`
|
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
|
||||||
--> tests/ui/single_char_pattern.rs:14:13
|
|
||||||
|
|
|
||||||
LL | x.split("ℝ");
|
|
||||||
| ^^^ help: consider using a `char`: `'ℝ'`
|
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
|
||||||
--> tests/ui/single_char_pattern.rs:15:13
|
|
||||||
|
|
|
||||||
LL | x.split("💣");
|
|
||||||
| ^^^^ help: consider using a `char`: `'💣'`
|
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:18:23
|
--> tests/ui/single_char_pattern.rs:18:23
|
||||||
|
|
|
|
||||||
|
@ -140,106 +122,94 @@ LL | x.trim_end_matches("x");
|
||||||
| ^^^ help: consider using a `char`: `'x'`
|
| ^^^ help: consider using a `char`: `'x'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:37:20
|
--> tests/ui/single_char_pattern.rs:37:15
|
||||||
|
|
|
||||||
LL | x.strip_prefix("x");
|
|
||||||
| ^^^ help: consider using a `char`: `'x'`
|
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
|
||||||
--> tests/ui/single_char_pattern.rs:38:20
|
|
||||||
|
|
|
||||||
LL | x.strip_suffix("x");
|
|
||||||
| ^^^ help: consider using a `char`: `'x'`
|
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
|
||||||
--> tests/ui/single_char_pattern.rs:39:15
|
|
||||||
|
|
|
|
||||||
LL | x.replace("x", "y");
|
LL | x.replace("x", "y");
|
||||||
| ^^^ help: consider using a `char`: `'x'`
|
| ^^^ help: consider using a `char`: `'x'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:40:16
|
--> tests/ui/single_char_pattern.rs:38:16
|
||||||
|
|
|
|
||||||
LL | x.replacen("x", "y", 3);
|
LL | x.replacen("x", "y", 3);
|
||||||
| ^^^ help: consider using a `char`: `'x'`
|
| ^^^ help: consider using a `char`: `'x'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:42:13
|
--> tests/ui/single_char_pattern.rs:40:13
|
||||||
|
|
|
|
||||||
LL | x.split("\n");
|
LL | x.split("\n");
|
||||||
| ^^^^ help: consider using a `char`: `'\n'`
|
| ^^^^ help: consider using a `char`: `'\n'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:43:13
|
--> tests/ui/single_char_pattern.rs:41:13
|
||||||
|
|
|
|
||||||
LL | x.split("'");
|
LL | x.split("'");
|
||||||
| ^^^ help: consider using a `char`: `'\''`
|
| ^^^ help: consider using a `char`: `'\''`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:44:13
|
--> tests/ui/single_char_pattern.rs:42:13
|
||||||
|
|
|
|
||||||
LL | x.split("\'");
|
LL | x.split("\'");
|
||||||
| ^^^^ help: consider using a `char`: `'\''`
|
| ^^^^ help: consider using a `char`: `'\''`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:46:13
|
--> tests/ui/single_char_pattern.rs:44:13
|
||||||
|
|
|
|
||||||
LL | x.split("\"");
|
LL | x.split("\"");
|
||||||
| ^^^^ help: consider using a `char`: `'"'`
|
| ^^^^ help: consider using a `char`: `'"'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:51:31
|
--> tests/ui/single_char_pattern.rs:49:31
|
||||||
|
|
|
|
||||||
LL | x.replace(';', ",").split(","); // issue #2978
|
LL | x.replace(';', ",").split(","); // issue #2978
|
||||||
| ^^^ help: consider using a `char`: `','`
|
| ^^^ help: consider using a `char`: `','`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:52:19
|
--> tests/ui/single_char_pattern.rs:50:19
|
||||||
|
|
|
|
||||||
LL | x.starts_with("\x03"); // issue #2996
|
LL | x.starts_with("\x03"); // issue #2996
|
||||||
| ^^^^^^ help: consider using a `char`: `'\x03'`
|
| ^^^^^^ help: consider using a `char`: `'\x03'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:59:13
|
--> tests/ui/single_char_pattern.rs:57:13
|
||||||
|
|
|
|
||||||
LL | x.split(r"a");
|
LL | x.split(r"a");
|
||||||
| ^^^^ help: consider using a `char`: `'a'`
|
| ^^^^ help: consider using a `char`: `'a'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:60:13
|
--> tests/ui/single_char_pattern.rs:58:13
|
||||||
|
|
|
|
||||||
LL | x.split(r#"a"#);
|
LL | x.split(r#"a"#);
|
||||||
| ^^^^^^ help: consider using a `char`: `'a'`
|
| ^^^^^^ help: consider using a `char`: `'a'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:61:13
|
--> tests/ui/single_char_pattern.rs:59:13
|
||||||
|
|
|
|
||||||
LL | x.split(r###"a"###);
|
LL | x.split(r###"a"###);
|
||||||
| ^^^^^^^^^^ help: consider using a `char`: `'a'`
|
| ^^^^^^^^^^ help: consider using a `char`: `'a'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:62:13
|
--> tests/ui/single_char_pattern.rs:60:13
|
||||||
|
|
|
|
||||||
LL | x.split(r###"'"###);
|
LL | x.split(r###"'"###);
|
||||||
| ^^^^^^^^^^ help: consider using a `char`: `'\''`
|
| ^^^^^^^^^^ help: consider using a `char`: `'\''`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:63:13
|
--> tests/ui/single_char_pattern.rs:61:13
|
||||||
|
|
|
|
||||||
LL | x.split(r###"#"###);
|
LL | x.split(r###"#"###);
|
||||||
| ^^^^^^^^^^ help: consider using a `char`: `'#'`
|
| ^^^^^^^^^^ help: consider using a `char`: `'#'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:65:13
|
--> tests/ui/single_char_pattern.rs:63:13
|
||||||
|
|
|
|
||||||
LL | x.split(r#"\"#);
|
LL | x.split(r#"\"#);
|
||||||
| ^^^^^^ help: consider using a `char`: `'\\'`
|
| ^^^^^^ help: consider using a `char`: `'\\'`
|
||||||
|
|
||||||
error: single-character string constant used as pattern
|
error: single-character string constant used as pattern
|
||||||
--> tests/ui/single_char_pattern.rs:66:13
|
--> tests/ui/single_char_pattern.rs:64:13
|
||||||
|
|
|
|
||||||
LL | x.split(r"\");
|
LL | x.split(r"\");
|
||||||
| ^^^^ help: consider using a `char`: `'\\'`
|
| ^^^^ help: consider using a `char`: `'\\'`
|
||||||
|
|
||||||
error: aborting due to 40 previous errors
|
error: aborting due to 35 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue