diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7cb820b0c43..5b17072df40 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`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string
 [`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
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 8753bcee5ce..c67ed14b3b0 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -469,7 +469,6 @@ 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,
@@ -541,6 +540,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::ranges::RANGE_MINUS_ONE_INFO,
     crate::ranges::RANGE_PLUS_ONE_INFO,
     crate::ranges::REVERSED_EMPTY_RANGES_INFO,
+    crate::raw_strings::NEEDLESS_RAW_STRING_INFO,
+    crate::raw_strings::NEEDLESS_RAW_STRING_HASHES_INFO,
     crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
     crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
     crate::redundant_async_block::REDUNDANT_ASYNC_BLOCK_INFO,
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index aadba6581a1..e1a7eedd93e 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -230,7 +230,6 @@ 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;
@@ -263,6 +262,7 @@ mod pub_use;
 mod question_mark;
 mod question_mark_used;
 mod ranges;
+mod raw_strings;
 mod rc_clone_in_vec_init;
 mod read_zero_byte_vec;
 mod redundant_async_block;
diff --git a/clippy_lints/src/needless_raw_string_hashes.rs b/clippy_lints/src/needless_raw_string_hashes.rs
deleted file mode 100644
index 85dffa5613d..00000000000
--- a/clippy_lints/src/needless_raw_string_hashes.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-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/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs
new file mode 100644
index 00000000000..52814693f3c
--- /dev/null
+++ b/clippy_lints/src/raw_strings.rs
@@ -0,0 +1,109 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet};
+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_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for raw string literals where a string literal can be used instead.
+    ///
+    /// ### Why is this bad?
+    /// It's just unnecessary.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let r = r"Hello, world!";
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let r = "Hello, world!";
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub NEEDLESS_RAW_STRING,
+    complexity,
+    "suggests using a string literal when a raw string literal is unnecessary"
+}
+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"
+}
+impl_lint_pass!(RawStrings => [NEEDLESS_RAW_STRING, NEEDLESS_RAW_STRING_HASHES]);
+
+pub struct RawStrings {
+    pub needless_raw_string_hashes_allow_one: bool,
+}
+
+impl EarlyLintPass for RawStrings {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if !in_external_macro(cx.sess(), expr.span)
+            && let ExprKind::Lit(lit) = expr.kind
+            && let LitKind::StrRaw(num) | LitKind::ByteStrRaw(num) | LitKind::CStrRaw(num) = lit.kind
+        {
+            let prefix = match lit.kind {
+                LitKind::StrRaw(..) => "r",
+                LitKind::ByteStrRaw(..) => "br",
+                LitKind::CStrRaw(..) => "cr",
+                _ => unreachable!(),
+            };
+            if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) {
+                return;
+            }
+
+            #[allow(clippy::cast_possible_truncation)]
+            let req = lit.symbol.as_str().as_bytes()
+                .split(|&b| b == b'"')
+                .skip(1)
+                .map(|bs| 1 + bs.iter().take_while(|&&b| b == b'#').count() as u8)
+                .max()
+                .unwrap_or(0);
+
+            if req < num {
+                let hashes = "#".repeat(req as usize);
+
+                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,
+                );
+            }
+
+            if !lit.symbol.as_str().contains(['\\', '"']) {
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_RAW_STRING,
+                    expr.span,
+                    "unnecessary raw string literal",
+                    "try",
+                    format!("{}\"{}\"", prefix.replace('r', ""), lit.symbol),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 12197666b30..9f88960f7ce 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -543,10 +543,14 @@ define_Conf! {
     ///
     /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
     (accept_comment_above_statement: bool = false),
-        /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
+    /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
     ///
     /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
     (accept_comment_above_attributes: bool = false),
+    /// Lint: UNNECESSARY_RAW_STRING_HASHES.
+    ///
+    /// Whether to allow `r#""#` when `r""` can be used
+    (allow_one_hash_in_raw_string: bool = false),
 }
 
 /// Search for the configuration file.
diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
index e4cb5316a98..570a88a0ed2 100644
--- a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
+++ b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
@@ -35,7 +35,7 @@ struct StandardFormulations<'a> {
 impl AlmostStandardFormulation {
     pub fn new() -> Self {
         let standard_formulations = vec![StandardFormulations {
-            wrong_pattern: Regex::new(r"^(Check for|Detects? uses?)").unwrap(),
+            wrong_pattern: Regex::new("^(Check for|Detects? uses?)").unwrap(),
             correction: "Checks for",
         }];
         Self { standard_formulations }
diff --git a/src/main.rs b/src/main.rs
index fd0da5a170b..cdc85cb33ca 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 = "Checks a package to catch common mistakes and improve your Rust code.
 
 Usage:
     cargo clippy [options] [--] [<opts>...]
diff --git a/tests/lint_message_convention.rs b/tests/lint_message_convention.rs
index 8feea800fdb..15e5cdd6992 100644
--- a/tests/lint_message_convention.rs
+++ b/tests/lint_message_convention.rs
@@ -20,16 +20,16 @@ impl Message {
         // also no punctuation (except for "?" ?) at the end of a line
         static REGEX_SET: LazyLock<RegexSet> = LazyLock::new(|| {
             RegexSet::new([
-                r"error: [A-Z]",
-                r"help: [A-Z]",
-                r"warning: [A-Z]",
-                r"note: [A-Z]",
-                r"try this: [A-Z]",
-                r"error: .*[.!]$",
-                r"help: .*[.!]$",
-                r"warning: .*[.!]$",
-                r"note: .*[.!]$",
-                r"try this: .*[.!]$",
+                "error: [A-Z]",
+                "help: [A-Z]",
+                "warning: [A-Z]",
+                "note: [A-Z]",
+                "try this: [A-Z]",
+                "error: .*[.!]$",
+                "help: .*[.!]$",
+                "warning: .*[.!]$",
+                "note: .*[.!]$",
+                "try this: .*[.!]$",
             ])
             .unwrap()
         });
@@ -39,11 +39,11 @@ impl Message {
         static EXCEPTIONS_SET: LazyLock<RegexSet> = LazyLock::new(|| {
             RegexSet::new([
                 r"\.\.\.$",
-                r".*C-like enum variant discriminant is not portable to 32-bit targets",
-                r".*Intel x86 assembly syntax used",
-                r".*AT&T x86 assembly syntax used",
-                r"note: Clippy version: .*",
-                r"the compiler unexpectedly panicked. this is a bug.",
+                ".*C-like enum variant discriminant is not portable to 32-bit targets",
+                ".*Intel x86 assembly syntax used",
+                ".*AT&T x86 assembly syntax used",
+                "note: Clippy version: .*",
+                "the compiler unexpectedly panicked. this is a bug.",
             ])
             .unwrap()
         });
diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
index ebbc7fea328..d26bc72787b 100644
--- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
+++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
@@ -1,5 +1,6 @@
 //@compile-flags: --crate-name conf_disallowed_methods
 
+#![allow(clippy::needless_raw_string)]
 #![warn(clippy::disallowed_methods)]
 #![allow(clippy::useless_vec)]
 
diff --git a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
index 3dc83a40780..fc137c225d8 100644
--- a/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
+++ b/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
@@ -1,5 +1,5 @@
 error: use of a disallowed method `regex::Regex::new`
-  --> $DIR/conf_disallowed_methods.rs:34:14
+  --> $DIR/conf_disallowed_methods.rs:35:14
    |
 LL |     let re = Regex::new(r"ab.*c").unwrap();
    |              ^^^^^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     let re = Regex::new(r"ab.*c").unwrap();
    = note: `-D clippy::disallowed-methods` implied by `-D warnings`
 
 error: use of a disallowed method `regex::Regex::is_match`
-  --> $DIR/conf_disallowed_methods.rs:35:5
+  --> $DIR/conf_disallowed_methods.rs:36:5
    |
 LL |     re.is_match("abc");
    |     ^^^^^^^^^^^^^^^^^^
@@ -15,73 +15,73 @@ LL |     re.is_match("abc");
    = note: no matching allowed (from clippy.toml)
 
 error: use of a disallowed method `std::iter::Iterator::sum`
-  --> $DIR/conf_disallowed_methods.rs:38:5
+  --> $DIR/conf_disallowed_methods.rs:39:5
    |
 LL |     a.iter().sum::<i32>();
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `slice::sort_unstable`
-  --> $DIR/conf_disallowed_methods.rs:40:5
+  --> $DIR/conf_disallowed_methods.rs:41:5
    |
 LL |     a.sort_unstable();
    |     ^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> $DIR/conf_disallowed_methods.rs:42:13
+  --> $DIR/conf_disallowed_methods.rs:43:13
    |
 LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> $DIR/conf_disallowed_methods.rs:45:61
+  --> $DIR/conf_disallowed_methods.rs:46:61
    |
 LL |     let indirect: fn(&str) -> Result<Regex, regex::Error> = Regex::new;
    |                                                             ^^^^^^^^^^
 
 error: use of a disallowed method `f32::clamp`
-  --> $DIR/conf_disallowed_methods.rs:48:28
+  --> $DIR/conf_disallowed_methods.rs:49:28
    |
 LL |     let in_call = Box::new(f32::clamp);
    |                            ^^^^^^^^^^
 
 error: use of a disallowed method `regex::Regex::new`
-  --> $DIR/conf_disallowed_methods.rs:49:53
+  --> $DIR/conf_disallowed_methods.rs:50:53
    |
 LL |     let in_method_call = ["^", "$"].into_iter().map(Regex::new);
    |                                                     ^^^^^^^^^^
 
 error: use of a disallowed method `futures::stream::select_all`
-  --> $DIR/conf_disallowed_methods.rs:52:31
+  --> $DIR/conf_disallowed_methods.rs:53:31
    |
 LL |     let same_name_as_module = select_all(vec![empty::<()>()]);
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_fn`
-  --> $DIR/conf_disallowed_methods.rs:54:5
+  --> $DIR/conf_disallowed_methods.rs:55:5
    |
 LL |     local_fn();
    |     ^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::local_mod::f`
-  --> $DIR/conf_disallowed_methods.rs:55:5
+  --> $DIR/conf_disallowed_methods.rs:56:5
    |
 LL |     local_mod::f();
    |     ^^^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Struct::method`
-  --> $DIR/conf_disallowed_methods.rs:57:5
+  --> $DIR/conf_disallowed_methods.rs:58:5
    |
 LL |     s.method();
    |     ^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method`
-  --> $DIR/conf_disallowed_methods.rs:58:5
+  --> $DIR/conf_disallowed_methods.rs:59:5
    |
 LL |     s.provided_method();
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method`
-  --> $DIR/conf_disallowed_methods.rs:59:5
+  --> $DIR/conf_disallowed_methods.rs:60:5
    |
 LL |     s.implemented_method();
    |     ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 69678057917..8724dc29d29 100644
--- a/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -4,6 +4,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
            allow-dbg-in-tests
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
+           allow-one-hash-in-raw-string
            allow-print-in-tests
            allow-private-module-inception
            allow-unwrap-in-tests
@@ -72,6 +73,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
            allow-dbg-in-tests
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
+           allow-one-hash-in-raw-string
            allow-print-in-tests
            allow-private-module-inception
            allow-unwrap-in-tests
diff --git a/tests/ui/format.stderr b/tests/ui/format.stderr
index f456c11924e..78a11a3354f 100644
--- a/tests/ui/format.stderr
+++ b/tests/ui/format.stderr
@@ -1,5 +1,5 @@
 error: useless use of `format!`
-  --> $DIR/format.rs:20:5
+  --> $DIR/format.rs:21:5
    |
 LL |     format!("foo");
    |     ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
@@ -7,19 +7,19 @@ LL |     format!("foo");
    = note: `-D clippy::useless-format` implied by `-D warnings`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:21:5
+  --> $DIR/format.rs:22:5
    |
 LL |     format!("{{}}");
    |     ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:22:5
+  --> $DIR/format.rs:23:5
    |
 LL |     format!("{{}} abc {{}}");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:23:5
+  --> $DIR/format.rs:24:5
    |
 LL | /     format!(
 LL | |         r##"foo {{}}
@@ -34,67 +34,67 @@ LL ~ " bar"##.to_string();
    |
 
 error: useless use of `format!`
-  --> $DIR/format.rs:28:13
+  --> $DIR/format.rs:29:13
    |
 LL |     let _ = format!("");
    |             ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:30:5
+  --> $DIR/format.rs:31:5
    |
 LL |     format!("{}", "foo");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:38:5
+  --> $DIR/format.rs:39:5
    |
 LL |     format!("{}", arg);
    |     ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:68:5
+  --> $DIR/format.rs:69:5
    |
 LL |     format!("{}", 42.to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:70:5
+  --> $DIR/format.rs:71:5
    |
 LL |     format!("{}", x.display().to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:74:18
+  --> $DIR/format.rs:75:18
    |
 LL |     let _ = Some(format!("{}", a + "bar"));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:78:22
+  --> $DIR/format.rs:79:22
    |
 LL |     let _s: String = format!("{}", &*v.join("/n"));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:84:13
+  --> $DIR/format.rs:85:13
    |
 LL |     let _ = format!("{x}");
    |             ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:86:13
+  --> $DIR/format.rs:87:13
    |
 LL |     let _ = format!("{y}", y = x);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:90:13
+  --> $DIR/format.rs:91:13
    |
 LL |     let _ = format!("{abc}");
    |             ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:92:13
+  --> $DIR/format.rs:93:13
    |
 LL |     let _ = format!("{xx}");
    |             ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()`
diff --git a/tests/ui/needless_raw_string.fixed b/tests/ui/needless_raw_string.fixed
new file mode 100644
index 00000000000..ffc1644335d
--- /dev/null
+++ b/tests/ui/needless_raw_string.fixed
@@ -0,0 +1,16 @@
+//@run-rustfix
+#![allow(clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
+#![warn(clippy::needless_raw_string)]
+#![feature(c_str_literals)]
+
+fn main() {
+    "aaa";
+    r#""aaa""#;
+    r#"\s"#;
+    b"aaa";
+    br#""aaa""#;
+    br#"\s"#;
+    c"aaa";
+    cr#""aaa""#;
+    cr#"\s"#;
+}
diff --git a/tests/ui/needless_raw_string.rs b/tests/ui/needless_raw_string.rs
new file mode 100644
index 00000000000..b06b9a0ec85
--- /dev/null
+++ b/tests/ui/needless_raw_string.rs
@@ -0,0 +1,16 @@
+//@run-rustfix
+#![allow(clippy::needless_raw_string_hashes, clippy::no_effect, unused)]
+#![warn(clippy::needless_raw_string)]
+#![feature(c_str_literals)]
+
+fn main() {
+    r#"aaa"#;
+    r#""aaa""#;
+    r#"\s"#;
+    br#"aaa"#;
+    br#""aaa""#;
+    br#"\s"#;
+    cr#"aaa"#;
+    cr#""aaa""#;
+    cr#"\s"#;
+}
diff --git a/tests/ui/needless_raw_string.stderr b/tests/ui/needless_raw_string.stderr
new file mode 100644
index 00000000000..3eb699dea36
--- /dev/null
+++ b/tests/ui/needless_raw_string.stderr
@@ -0,0 +1,22 @@
+error: unnecessary raw string literal
+  --> $DIR/needless_raw_string.rs:7:5
+   |
+LL |     r#"aaa"#;
+   |     ^^^^^^^^ help: try: `"aaa"`
+   |
+   = note: `-D clippy::needless-raw-string` implied by `-D warnings`
+
+error: unnecessary raw string literal
+  --> $DIR/needless_raw_string.rs:10:5
+   |
+LL |     br#"aaa"#;
+   |     ^^^^^^^^^ help: try: `b"aaa"`
+
+error: unnecessary raw string literal
+  --> $DIR/needless_raw_string.rs:13:5
+   |
+LL |     cr#"aaa"#;
+   |     ^^^^^^^^^ help: try: `c"aaa"`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/needless_raw_string_hashes.fixed b/tests/ui/needless_raw_string_hashes.fixed
index 43616860a2e..1bfb573719d 100644
--- a/tests/ui/needless_raw_string_hashes.fixed
+++ b/tests/ui/needless_raw_string_hashes.fixed
@@ -1,5 +1,5 @@
 //@run-rustfix
-#![allow(clippy::no_effect, unused)]
+#![allow(clippy::needless_raw_string, clippy::no_effect, unused)]
 #![warn(clippy::needless_raw_string_hashes)]
 #![feature(c_str_literals)]
 
diff --git a/tests/ui/needless_raw_string_hashes.rs b/tests/ui/needless_raw_string_hashes.rs
index e2d85c52e78..dedd774ea0a 100644
--- a/tests/ui/needless_raw_string_hashes.rs
+++ b/tests/ui/needless_raw_string_hashes.rs
@@ -1,5 +1,5 @@
 //@run-rustfix
-#![allow(clippy::no_effect, unused)]
+#![allow(clippy::needless_raw_string, clippy::no_effect, unused)]
 #![warn(clippy::needless_raw_string_hashes)]
 #![feature(c_str_literals)]
 
diff --git a/tests/ui/regex.rs b/tests/ui/regex.rs
index 3b208651946..850c9813462 100644
--- a/tests/ui/regex.rs
+++ b/tests/ui/regex.rs
@@ -1,4 +1,9 @@
-#![allow(unused, clippy::needless_raw_string_hashes, clippy::needless_borrow)]
+#![allow(
+    unused,
+    clippy::needless_raw_string,
+    clippy::needless_raw_string_hashes,
+    clippy::needless_borrow
+)]
 #![warn(clippy::invalid_regex, clippy::trivial_regex)]
 
 extern crate regex;
diff --git a/tests/ui/regex.stderr b/tests/ui/regex.stderr
index c74dc8108fe..21f1cb44460 100644
--- a/tests/ui/regex.stderr
+++ b/tests/ui/regex.stderr
@@ -1,5 +1,5 @@
 error: trivial regex
-  --> $DIR/regex.rs:13:45
+  --> $DIR/regex.rs:18:45
    |
 LL |     let pipe_in_wrong_position = Regex::new("|");
    |                                             ^^^
@@ -8,7 +8,7 @@ LL |     let pipe_in_wrong_position = Regex::new("|");
    = note: `-D clippy::trivial-regex` implied by `-D warnings`
 
 error: trivial regex
-  --> $DIR/regex.rs:14:60
+  --> $DIR/regex.rs:19:60
    |
 LL |     let pipe_in_wrong_position_builder = RegexBuilder::new("|");
    |                                                            ^^^
@@ -16,7 +16,7 @@ LL |     let pipe_in_wrong_position_builder = RegexBuilder::new("|");
    = help: the regex is unlikely to be useful as it is
 
 error: regex syntax error: invalid character class range, the start must be <= the end
-  --> $DIR/regex.rs:15:42
+  --> $DIR/regex.rs:20:42
    |
 LL |     let wrong_char_ranice = Regex::new("[z-a]");
    |                                          ^^^
@@ -24,7 +24,7 @@ LL |     let wrong_char_ranice = Regex::new("[z-a]");
    = note: `-D clippy::invalid-regex` implied by `-D warnings`
 
 error: regex syntax error: invalid character class range, the start must be <= the end
-  --> $DIR/regex.rs:16:37
+  --> $DIR/regex.rs:21:37
    |
 LL |     let some_unicode = Regex::new("[é-è]");
    |                                     ^^^
@@ -33,13 +33,13 @@ error: regex parse error:
            (
            ^
        error: unclosed group
-  --> $DIR/regex.rs:18:33
+  --> $DIR/regex.rs:23:33
    |
 LL |     let some_regex = Regex::new(OPENING_PAREN);
    |                                 ^^^^^^^^^^^^^
 
 error: trivial regex
-  --> $DIR/regex.rs:20:53
+  --> $DIR/regex.rs:25:53
    |
 LL |     let binary_pipe_in_wrong_position = BRegex::new("|");
    |                                                     ^^^
@@ -50,7 +50,7 @@ error: regex parse error:
            (
            ^
        error: unclosed group
-  --> $DIR/regex.rs:21:41
+  --> $DIR/regex.rs:26:41
    |
 LL |     let some_binary_regex = BRegex::new(OPENING_PAREN);
    |                                         ^^^^^^^^^^^^^
@@ -59,7 +59,7 @@ error: regex parse error:
            (
            ^
        error: unclosed group
-  --> $DIR/regex.rs:22:56
+  --> $DIR/regex.rs:27:56
    |
 LL |     let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN);
    |                                                        ^^^^^^^^^^^^^
@@ -68,7 +68,7 @@ error: regex parse error:
            (
            ^
        error: unclosed group
-  --> $DIR/regex.rs:34:37
+  --> $DIR/regex.rs:39:37
    |
 LL |     let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
    |                                     ^^^^^^^^^^^^^
@@ -77,7 +77,7 @@ error: regex parse error:
            (
            ^
        error: unclosed group
-  --> $DIR/regex.rs:35:39
+  --> $DIR/regex.rs:40:39
    |
 LL |     let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
    |                                       ^^^^^^^^^^^^^
@@ -86,7 +86,7 @@ error: regex parse error:
            /b/c
              ^^
        error: unrecognized escape sequence
-  --> $DIR/regex.rs:42:42
+  --> $DIR/regex.rs:47:42
    |
 LL |     let escaped_string_span = Regex::new("//b//c");
    |                                          ^^^^^^^^
@@ -94,19 +94,19 @@ LL |     let escaped_string_span = Regex::new("//b//c");
    = help: consider using a raw string literal: `r".."`
 
 error: regex syntax error: duplicate flag
-  --> $DIR/regex.rs:44:34
+  --> $DIR/regex.rs:49:34
    |
 LL |     let aux_span = Regex::new("(?ixi)");
    |                                  ^ ^
 
 error: regex syntax error: pattern can match invalid UTF-8
-  --> $DIR/regex.rs:49:53
+  --> $DIR/regex.rs:54:53
    |
 LL |     let invalid_utf8_should_lint = Regex::new("(?-u).");
    |                                                     ^
 
 error: trivial regex
-  --> $DIR/regex.rs:53:33
+  --> $DIR/regex.rs:58:33
    |
 LL |     let trivial_eq = Regex::new("^foobar$");
    |                                 ^^^^^^^^^^
@@ -114,7 +114,7 @@ LL |     let trivial_eq = Regex::new("^foobar$");
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:55:48
+  --> $DIR/regex.rs:60:48
    |
 LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    |                                                ^^^^^^^^^^
@@ -122,7 +122,7 @@ LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:57:42
+  --> $DIR/regex.rs:62:42
    |
 LL |     let trivial_starts_with = Regex::new("^foobar");
    |                                          ^^^^^^^^^
@@ -130,7 +130,7 @@ LL |     let trivial_starts_with = Regex::new("^foobar");
    = help: consider using `str::starts_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:59:40
+  --> $DIR/regex.rs:64:40
    |
 LL |     let trivial_ends_with = Regex::new("foobar$");
    |                                        ^^^^^^^^^
@@ -138,7 +138,7 @@ LL |     let trivial_ends_with = Regex::new("foobar$");
    = help: consider using `str::ends_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:61:39
+  --> $DIR/regex.rs:66:39
    |
 LL |     let trivial_contains = Regex::new("foobar");
    |                                       ^^^^^^^^
@@ -146,7 +146,7 @@ LL |     let trivial_contains = Regex::new("foobar");
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:63:39
+  --> $DIR/regex.rs:68:39
    |
 LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    |                                       ^^^^^^^^^^^^^^^^
@@ -154,7 +154,7 @@ LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:65:40
+  --> $DIR/regex.rs:70:40
    |
 LL |     let trivial_backslash = Regex::new("a//.b");
    |                                        ^^^^^^^
@@ -162,7 +162,7 @@ LL |     let trivial_backslash = Regex::new("a//.b");
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:68:36
+  --> $DIR/regex.rs:73:36
    |
 LL |     let trivial_empty = Regex::new("");
    |                                    ^^
@@ -170,7 +170,7 @@ LL |     let trivial_empty = Regex::new("");
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:70:36
+  --> $DIR/regex.rs:75:36
    |
 LL |     let trivial_empty = Regex::new("^");
    |                                    ^^^
@@ -178,7 +178,7 @@ LL |     let trivial_empty = Regex::new("^");
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:72:36
+  --> $DIR/regex.rs:77:36
    |
 LL |     let trivial_empty = Regex::new("^$");
    |                                    ^^^^
@@ -186,7 +186,7 @@ LL |     let trivial_empty = Regex::new("^$");
    = help: consider using `str::is_empty`
 
 error: trivial regex
-  --> $DIR/regex.rs:74:44
+  --> $DIR/regex.rs:79:44
    |
 LL |     let binary_trivial_empty = BRegex::new("^$");
    |                                            ^^^^
diff --git a/tests/ui/single_char_add_str.fixed b/tests/ui/single_char_add_str.fixed
index 2d4c0841219..ee0177776bf 100644
--- a/tests/ui/single_char_add_str.fixed
+++ b/tests/ui/single_char_add_str.fixed
@@ -1,6 +1,6 @@
 //@run-rustfix
 #![warn(clippy::single_char_add_str)]
-#![allow(clippy::needless_raw_string_hashes)]
+#![allow(clippy::needless_raw_string, 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 463b19da09e..e3b7d8597c2 100644
--- a/tests/ui/single_char_add_str.rs
+++ b/tests/ui/single_char_add_str.rs
@@ -1,6 +1,6 @@
 //@run-rustfix
 #![warn(clippy::single_char_add_str)]
-#![allow(clippy::needless_raw_string_hashes)]
+#![allow(clippy::needless_raw_string, clippy::needless_raw_string_hashes)]
 
 macro_rules! get_string {
     () => {
diff --git a/tests/ui/single_char_pattern.fixed b/tests/ui/single_char_pattern.fixed
index f1dc3ea9894..920d43318ae 100644
--- a/tests/ui/single_char_pattern.fixed
+++ b/tests/ui/single_char_pattern.fixed
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![allow(clippy::needless_raw_string_hashes, unused_must_use)]
+#![allow(clippy::needless_raw_string, 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 00b38498001..3a53084e30b 100644
--- a/tests/ui/single_char_pattern.rs
+++ b/tests/ui/single_char_pattern.rs
@@ -1,6 +1,6 @@
 //@run-rustfix
 
-#![allow(clippy::needless_raw_string_hashes, unused_must_use)]
+#![allow(clippy::needless_raw_string, clippy::needless_raw_string_hashes, unused_must_use)]
 
 use std::collections::HashSet;
 
diff --git a/tests/ui/write_literal_2.rs b/tests/ui/write_literal_2.rs
index 55a11daa1d3..1d9b9603bd8 100644
--- a/tests/ui/write_literal_2.rs
+++ b/tests/ui/write_literal_2.rs
@@ -1,5 +1,5 @@
 #![allow(unused_must_use)]
-#![warn(clippy::write_literal)]
+#![warn(clippy::needless_raw_string, clippy::write_literal)]
 
 use std::io::Write;
 
diff --git a/tests/ui/write_literal_2.stderr b/tests/ui/write_literal_2.stderr
index bf22738480d..a69d031b011 100644
--- a/tests/ui/write_literal_2.stderr
+++ b/tests/ui/write_literal_2.stderr
@@ -1,3 +1,11 @@
+error: unnecessary raw string literal
+  --> $DIR/write_literal_2.rs:10:24
+   |
+LL |     writeln!(v, r"{}", r"{hello}");
+   |                        ^^^^^^^^^^ help: try: `"{hello}"`
+   |
+   = note: `-D clippy::needless-raw-string` implied by `-D warnings`
+
 error: literal with an empty format string
   --> $DIR/write_literal_2.rs:9:23
    |
@@ -186,5 +194,5 @@ error: literal with an empty format string
 LL |     writeln!(v, r#"{}{}"#, '#', '"'); // hard mode
    |                                 ^^^
 
-error: aborting due to 17 previous errors
+error: aborting due to 18 previous errors