about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCentri3 <114838443+Centri3@users.noreply.github.com>2023-06-03 18:07:36 -0500
committerCatherine <114838443+Centri3@users.noreply.github.com>2023-06-27 05:12:00 -0500
commit1bf74fc303d77be3ceef5b030d9fd73ca6031298 (patch)
treedf451b8521f17b69c94a24b2af2d05259e16097f
parentecdea8cdd386260970dad617cae2a71b25a307f5 (diff)
downloadrust-1bf74fc303d77be3ceef5b030d9fd73ca6031298.tar.gz
rust-1bf74fc303d77be3ceef5b030d9fd73ca6031298.zip
add `needless_raw_string_hashes` lint
add semicolon in doctest
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/lib.rs1
-rw-r--r--clippy_lints/src/needless_raw_string_hashes.rs73
-rw-r--r--src/main.rs4
-rw-r--r--tests/ui/format.fixed1
-rw-r--r--tests/ui/format.rs1
-rw-r--r--tests/ui/needless_raw_string_hashes.fixed19
-rw-r--r--tests/ui/needless_raw_string_hashes.rs19
-rw-r--r--tests/ui/needless_raw_string_hashes.stderr76
-rw-r--r--tests/ui/regex.rs2
-rw-r--r--tests/ui/single_char_add_str.fixed1
-rw-r--r--tests/ui/single_char_add_str.rs1
-rw-r--r--tests/ui/single_char_add_str.stderr30
-rw-r--r--tests/ui/single_char_pattern.fixed2
-rw-r--r--tests/ui/single_char_pattern.rs2
-rw-r--r--tests/ui/string_lit_as_bytes.fixed2
-rw-r--r--tests/ui/string_lit_as_bytes.rs2
18 files changed, 216 insertions, 22 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 941efb1abff..7cb820b0c43 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5048,6 +5048,7 @@ Released 2018-09-13
 [`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
 [`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
 [`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
+[`needless_raw_string_hashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes
 [`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
 [`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
 [`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 0eec18a91bc..8753bcee5ce 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -469,6 +469,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
     crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
     crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
+    crate::needless_raw_string_hashes::NEEDLESS_RAW_STRING_HASHES_INFO,
     crate::needless_update::NEEDLESS_UPDATE_INFO,
     crate::neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD_INFO,
     crate::neg_multiply::NEG_MULTIPLY_INFO,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 6d77b828f14..aadba6581a1 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -230,6 +230,7 @@ mod needless_late_init;
 mod needless_parens_on_range_literals;
 mod needless_pass_by_value;
 mod needless_question_mark;
+mod needless_raw_string_hashes;
 mod needless_update;
 mod neg_cmp_op_on_partial_ord;
 mod neg_multiply;
diff --git a/clippy_lints/src/needless_raw_string_hashes.rs b/clippy_lints/src/needless_raw_string_hashes.rs
new file mode 100644
index 00000000000..85dffa5613d
--- /dev/null
+++ b/clippy_lints/src/needless_raw_string_hashes.rs
@@ -0,0 +1,73 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::{
+    ast::{Expr, ExprKind},
+    token::LitKind,
+};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for raw string literals with an unnecessary amount of hashes around them.
+    ///
+    /// ### Why is this bad?
+    /// It's just unnecessary, and makes it look like there's more escaping needed than is actually
+    /// necessary.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let r = r###"Hello, "world"!"###;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let r = r#"Hello, "world"!"#;
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub NEEDLESS_RAW_STRING_HASHES,
+    complexity,
+    "suggests reducing the number of hashes around a raw string literal"
+}
+declare_lint_pass!(NeedlessRawStringHashes => [NEEDLESS_RAW_STRING_HASHES]);
+
+impl EarlyLintPass for NeedlessRawStringHashes {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if_chain! {
+            if !in_external_macro(cx.sess(), expr.span);
+            if let ExprKind::Lit(lit) = expr.kind;
+            if let LitKind::StrRaw(num) | LitKind::ByteStrRaw(num) | LitKind::CStrRaw(num) = lit.kind;
+            then {
+                let str = lit.symbol.as_str();
+                let mut lowest = 0;
+
+                for i in (0..num).rev() {
+                    if str.contains(&format!("\"{}", "#".repeat(i as usize))) {
+                        lowest = i + 1;
+                        break;
+                    }
+                }
+
+                if lowest < num {
+                    let hashes = "#".repeat(lowest as usize);
+                    let prefix = match lit.kind {
+                        LitKind::StrRaw(..) => "r",
+                        LitKind::ByteStrRaw(..) => "br",
+                        LitKind::CStrRaw(..) => "cr",
+                        _ => unreachable!(),
+                    };
+
+                    span_lint_and_sugg(
+                        cx,
+                        NEEDLESS_RAW_STRING_HASHES,
+                        expr.span,
+                        "unnecessary hashes around raw string literal",
+                        "try",
+                        format!(r#"{prefix}{hashes}"{}"{hashes}"#, lit.symbol),
+                        Applicability::MachineApplicable,
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/src/main.rs b/src/main.rs
index 300c84a1442..fd0da5a170b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,7 +6,7 @@ use std::env;
 use std::path::PathBuf;
 use std::process::{self, Command};
 
-const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
+const CARGO_CLIPPY_HELP: &str = r"Checks a package to catch common mistakes and improve your Rust code.
 
 Usage:
     cargo clippy [options] [--] [<opts>...]
@@ -31,7 +31,7 @@ with:
 You can use tool lints to allow or deny lints from your code, e.g.:
 
     #[allow(clippy::needless_lifetimes)]
-"#;
+";
 
 fn show_help() {
     println!("{CARGO_CLIPPY_HELP}");
diff --git a/tests/ui/format.fixed b/tests/ui/format.fixed
index f214cabef67..2e24e07ea26 100644
--- a/tests/ui/format.fixed
+++ b/tests/ui/format.fixed
@@ -7,6 +7,7 @@
     clippy::to_string_in_format_args,
     clippy::needless_borrow,
     clippy::uninlined_format_args,
+    clippy::needless_raw_string_hashes,
     clippy::useless_vec
 )]
 
diff --git a/tests/ui/format.rs b/tests/ui/format.rs
index d9b28a4f7c0..0e64a310b01 100644
--- a/tests/ui/format.rs
+++ b/tests/ui/format.rs
@@ -7,6 +7,7 @@
     clippy::to_string_in_format_args,
     clippy::needless_borrow,
     clippy::uninlined_format_args,
+    clippy::needless_raw_string_hashes,
     clippy::useless_vec
 )]
 
diff --git a/tests/ui/needless_raw_string_hashes.fixed b/tests/ui/needless_raw_string_hashes.fixed
new file mode 100644
index 00000000000..43616860a2e
--- /dev/null
+++ b/tests/ui/needless_raw_string_hashes.fixed
@@ -0,0 +1,19 @@
+//@run-rustfix
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::needless_raw_string_hashes)]
+#![feature(c_str_literals)]
+
+fn main() {
+    r"aaa";
+    r#"Hello "world"!"#;
+    r####" "### "## "# "####;
+    r###" "aa" "# "## "###;
+    br"aaa";
+    br#"Hello "world"!"#;
+    br####" "### "## "# "####;
+    br###" "aa" "# "## "###;
+    cr"aaa";
+    cr#"Hello "world"!"#;
+    cr####" "### "## "# "####;
+    cr###" "aa" "# "## "###;
+}
diff --git a/tests/ui/needless_raw_string_hashes.rs b/tests/ui/needless_raw_string_hashes.rs
new file mode 100644
index 00000000000..e2d85c52e78
--- /dev/null
+++ b/tests/ui/needless_raw_string_hashes.rs
@@ -0,0 +1,19 @@
+//@run-rustfix
+#![allow(clippy::no_effect, unused)]
+#![warn(clippy::needless_raw_string_hashes)]
+#![feature(c_str_literals)]
+
+fn main() {
+    r#"aaa"#;
+    r##"Hello "world"!"##;
+    r######" "### "## "# "######;
+    r######" "aa" "# "## "######;
+    br#"aaa"#;
+    br##"Hello "world"!"##;
+    br######" "### "## "# "######;
+    br######" "aa" "# "## "######;
+    cr#"aaa"#;
+    cr##"Hello "world"!"##;
+    cr######" "### "## "# "######;
+    cr######" "aa" "# "## "######;
+}
diff --git a/tests/ui/needless_raw_string_hashes.stderr b/tests/ui/needless_raw_string_hashes.stderr
new file mode 100644
index 00000000000..44b878cec40
--- /dev/null
+++ b/tests/ui/needless_raw_string_hashes.stderr
@@ -0,0 +1,76 @@
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:7:5
+   |
+LL |     r#"aaa"#;
+   |     ^^^^^^^^ help: try: `r"aaa"`
+   |
+   = note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:8:5
+   |
+LL |     r##"Hello "world"!"##;
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: try: `r#"Hello "world"!"#`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:9:5
+   |
+LL |     r######" "### "## "# "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r####" "### "## "# "####`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:10:5
+   |
+LL |     r######" "aa" "# "## "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r###" "aa" "# "## "###`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:11:5
+   |
+LL |     br#"aaa"#;
+   |     ^^^^^^^^^ help: try: `br"aaa"`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:12:5
+   |
+LL |     br##"Hello "world"!"##;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `br#"Hello "world"!"#`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:13:5
+   |
+LL |     br######" "### "## "# "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br####" "### "## "# "####`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:14:5
+   |
+LL |     br######" "aa" "# "## "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br###" "aa" "# "## "###`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:15:5
+   |
+LL |     cr#"aaa"#;
+   |     ^^^^^^^^^ help: try: `cr"aaa"`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:16:5
+   |
+LL |     cr##"Hello "world"!"##;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr#"Hello "world"!"#`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:17:5
+   |
+LL |     cr######" "### "## "# "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr####" "### "## "# "####`
+
+error: unnecessary hashes around raw string literal
+  --> $DIR/needless_raw_string_hashes.rs:18:5
+   |
+LL |     cr######" "aa" "# "## "######;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr###" "aa" "# "## "###`
+
+error: aborting due to 12 previous errors
+
diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs
index 1c8e47ab594..3b208651946 100644
--- a/tests/ui/regex.rs
+++ b/tests/ui/regex.rs
@@ -1,4 +1,4 @@
-#![allow(unused, clippy::needless_borrow)]
+#![allow(unused, clippy::needless_raw_string_hashes, clippy::needless_borrow)]
 #![warn(clippy::invalid_regex, clippy::trivial_regex)]
 
 extern crate regex;
diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed
index cbcf1ab21c9..2d4c0841219 100644
--- a/tests/ui/single_char_add_str.fixed
+++ b/tests/ui/single_char_add_str.fixed
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::single_char_add_str)]
+#![allow(clippy::needless_raw_string_hashes)]
 
 macro_rules! get_string {
     () => {
diff --git a/tests/ui/single_char_add_str.rs b/tests/ui/single_char_add_str.rs
index a1f005cc833..463b19da09e 100644
--- a/tests/ui/single_char_add_str.rs
+++ b/tests/ui/single_char_add_str.rs
@@ -1,5 +1,6 @@
 //@run-rustfix
 #![warn(clippy::single_char_add_str)]
+#![allow(clippy::needless_raw_string_hashes)]
 
 macro_rules! get_string {
     () => {
diff --git a/tests/ui/single_char_add_str.stderr b/tests/ui/single_char_add_str.stderr
index 55d91583ad0..3f93c18470e 100644
--- a/tests/ui/single_char_add_str.stderr
+++ b/tests/ui/single_char_add_str.stderr
@@ -1,5 +1,5 @@
 error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:14:5
+  --> $DIR/single_char_add_str.rs:15:5
    |
 LL |     string.push_str("R");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('R')`
@@ -7,85 +7,85 @@ LL |     string.push_str("R");
    = note: `-D clippy::single-char-add-str` implied by `-D warnings`
 
 error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:15:5
+  --> $DIR/single_char_add_str.rs:16:5
    |
 LL |     string.push_str("'");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/'')`
 
 error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:20:5
+  --> $DIR/single_char_add_str.rs:21:5
    |
 LL |     string.push_str("/x52");
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/x52')`
 
 error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:21:5
+  --> $DIR/single_char_add_str.rs:22:5
    |
 LL |     string.push_str("/u{0052}");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('/u{0052}')`
 
 error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:22:5
+  --> $DIR/single_char_add_str.rs:23:5
    |
 LL |     string.push_str(r##"a"##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')`
 
 error: calling `push_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:24:5
+  --> $DIR/single_char_add_str.rs:25:5
    |
 LL |     get_string!().push_str("ö");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:29:5
+  --> $DIR/single_char_add_str.rs:30:5
    |
 LL |     string.insert_str(0, "R");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:30:5
+  --> $DIR/single_char_add_str.rs:31:5
    |
 LL |     string.insert_str(1, "'");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '/'')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:35:5
+  --> $DIR/single_char_add_str.rs:36:5
    |
 LL |     string.insert_str(0, "/x52");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/x52')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:36:5
+  --> $DIR/single_char_add_str.rs:37:5
    |
 LL |     string.insert_str(0, "/u{0052}");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '/u{0052}')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:38:5
+  --> $DIR/single_char_add_str.rs:39:5
    |
 LL |     string.insert_str(x, r##"a"##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:40:5
+  --> $DIR/single_char_add_str.rs:41:5
    |
 LL |     string.insert_str(Y, r##"a"##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:41:5
+  --> $DIR/single_char_add_str.rs:42:5
    |
 LL |     string.insert_str(Y, r##"""##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:42:5
+  --> $DIR/single_char_add_str.rs:43:5
    |
 LL |     string.insert_str(Y, r##"'"##);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '/'')`
 
 error: calling `insert_str()` using a single-character string literal
-  --> $DIR/single_char_add_str.rs:44:5
+  --> $DIR/single_char_add_str.rs:45:5
    |
 LL |     get_string!().insert_str(1, "?");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')`
diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed
index dba89872070..f1dc3ea9894 100644
--- a/tests/ui/single_char_pattern.fixed
+++ b/tests/ui/single_char_pattern.fixed
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![allow(unused_must_use)]
+#![allow(clippy::needless_raw_string_hashes, unused_must_use)]
 
 use std::collections::HashSet;
 
diff --git a/tests/ui/single_char_pattern.rs b/tests/ui/single_char_pattern.rs
index 6a145a14bfd..00b38498001 100644
--- a/tests/ui/single_char_pattern.rs
+++ b/tests/ui/single_char_pattern.rs
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![allow(unused_must_use)]
+#![allow(clippy::needless_raw_string_hashes, unused_must_use)]
 
 use std::collections::HashSet;
 
diff --git a/tests/ui/string_lit_as_bytes.fixed b/tests/ui/string_lit_as_bytes.fixed
index 3fc11b8b088..0edd81acc7a 100644
--- a/tests/ui/string_lit_as_bytes.fixed
+++ b/tests/ui/string_lit_as_bytes.fixed
@@ -1,7 +1,7 @@
 //@run-rustfix
 //@aux-build:macro_rules.rs
 
-#![allow(dead_code, unused_variables)]
+#![allow(clippy::needless_raw_string_hashes, dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
 #[macro_use]
diff --git a/tests/ui/string_lit_as_bytes.rs b/tests/ui/string_lit_as_bytes.rs
index 7d54acf630e..2647f02f0e9 100644
--- a/tests/ui/string_lit_as_bytes.rs
+++ b/tests/ui/string_lit_as_bytes.rs
@@ -1,7 +1,7 @@
 //@run-rustfix
 //@aux-build:macro_rules.rs
 
-#![allow(dead_code, unused_variables)]
+#![allow(clippy::needless_raw_string_hashes, dead_code, unused_variables)]
 #![warn(clippy::string_lit_as_bytes)]
 
 #[macro_use]