Skip to content

Commit 1bf74fc

Browse files
committed
add needless_raw_string_hashes lint
add semicolon in doctest
1 parent ecdea8c commit 1bf74fc

18 files changed

+216
-22
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5048,6 +5048,7 @@ Released 2018-09-13
50485048
[`needless_pass_by_value`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_value
50495049
[`needless_question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark
50505050
[`needless_range_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_range_loop
5051+
[`needless_raw_string_hashes`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes
50515052
[`needless_return`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_return
50525053
[`needless_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_splitn
50535054
[`needless_update`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_update

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
469469
crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
470470
crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
471471
crate::needless_question_mark::NEEDLESS_QUESTION_MARK_INFO,
472+
crate::needless_raw_string_hashes::NEEDLESS_RAW_STRING_HASHES_INFO,
472473
crate::needless_update::NEEDLESS_UPDATE_INFO,
473474
crate::neg_cmp_op_on_partial_ord::NEG_CMP_OP_ON_PARTIAL_ORD_INFO,
474475
crate::neg_multiply::NEG_MULTIPLY_INFO,

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ mod needless_late_init;
230230
mod needless_parens_on_range_literals;
231231
mod needless_pass_by_value;
232232
mod needless_question_mark;
233+
mod needless_raw_string_hashes;
233234
mod needless_update;
234235
mod neg_cmp_op_on_partial_ord;
235236
mod neg_multiply;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use rustc_ast::{
3+
ast::{Expr, ExprKind},
4+
token::LitKind,
5+
};
6+
use rustc_errors::Applicability;
7+
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
8+
use rustc_middle::lint::in_external_macro;
9+
use rustc_session::{declare_lint_pass, declare_tool_lint};
10+
11+
declare_clippy_lint! {
12+
/// ### What it does
13+
/// Checks for raw string literals with an unnecessary amount of hashes around them.
14+
///
15+
/// ### Why is this bad?
16+
/// It's just unnecessary, and makes it look like there's more escaping needed than is actually
17+
/// necessary.
18+
///
19+
/// ### Example
20+
/// ```rust
21+
/// let r = r###"Hello, "world"!"###;
22+
/// ```
23+
/// Use instead:
24+
/// ```rust
25+
/// let r = r#"Hello, "world"!"#;
26+
/// ```
27+
#[clippy::version = "1.72.0"]
28+
pub NEEDLESS_RAW_STRING_HASHES,
29+
complexity,
30+
"suggests reducing the number of hashes around a raw string literal"
31+
}
32+
declare_lint_pass!(NeedlessRawStringHashes => [NEEDLESS_RAW_STRING_HASHES]);
33+
34+
impl EarlyLintPass for NeedlessRawStringHashes {
35+
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
36+
if_chain! {
37+
if !in_external_macro(cx.sess(), expr.span);
38+
if let ExprKind::Lit(lit) = expr.kind;
39+
if let LitKind::StrRaw(num) | LitKind::ByteStrRaw(num) | LitKind::CStrRaw(num) = lit.kind;
40+
then {
41+
let str = lit.symbol.as_str();
42+
let mut lowest = 0;
43+
44+
for i in (0..num).rev() {
45+
if str.contains(&format!("\"{}", "#".repeat(i as usize))) {
46+
lowest = i + 1;
47+
break;
48+
}
49+
}
50+
51+
if lowest < num {
52+
let hashes = "#".repeat(lowest as usize);
53+
let prefix = match lit.kind {
54+
LitKind::StrRaw(..) => "r",
55+
LitKind::ByteStrRaw(..) => "br",
56+
LitKind::CStrRaw(..) => "cr",
57+
_ => unreachable!(),
58+
};
59+
60+
span_lint_and_sugg(
61+
cx,
62+
NEEDLESS_RAW_STRING_HASHES,
63+
expr.span,
64+
"unnecessary hashes around raw string literal",
65+
"try",
66+
format!(r#"{prefix}{hashes}"{}"{hashes}"#, lit.symbol),
67+
Applicability::MachineApplicable,
68+
);
69+
}
70+
}
71+
}
72+
}
73+
}

src/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::env;
66
use std::path::PathBuf;
77
use std::process::{self, Command};
88

9-
const CARGO_CLIPPY_HELP: &str = r#"Checks a package to catch common mistakes and improve your Rust code.
9+
const CARGO_CLIPPY_HELP: &str = r"Checks a package to catch common mistakes and improve your Rust code.
1010
1111
Usage:
1212
cargo clippy [options] [--] [<opts>...]
@@ -31,7 +31,7 @@ with:
3131
You can use tool lints to allow or deny lints from your code, e.g.:
3232
3333
#[allow(clippy::needless_lifetimes)]
34-
"#;
34+
";
3535

3636
fn show_help() {
3737
println!("{CARGO_CLIPPY_HELP}");

tests/ui/format.fixed

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
clippy::to_string_in_format_args,
88
clippy::needless_borrow,
99
clippy::uninlined_format_args,
10+
clippy::needless_raw_string_hashes,
1011
clippy::useless_vec
1112
)]
1213

tests/ui/format.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
clippy::to_string_in_format_args,
88
clippy::needless_borrow,
99
clippy::uninlined_format_args,
10+
clippy::needless_raw_string_hashes,
1011
clippy::useless_vec
1112
)]
1213

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@run-rustfix
2+
#![allow(clippy::no_effect, unused)]
3+
#![warn(clippy::needless_raw_string_hashes)]
4+
#![feature(c_str_literals)]
5+
6+
fn main() {
7+
r"aaa";
8+
r#"Hello "world"!"#;
9+
r####" "### "## "# "####;
10+
r###" "aa" "# "## "###;
11+
br"aaa";
12+
br#"Hello "world"!"#;
13+
br####" "### "## "# "####;
14+
br###" "aa" "# "## "###;
15+
cr"aaa";
16+
cr#"Hello "world"!"#;
17+
cr####" "### "## "# "####;
18+
cr###" "aa" "# "## "###;
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@run-rustfix
2+
#![allow(clippy::no_effect, unused)]
3+
#![warn(clippy::needless_raw_string_hashes)]
4+
#![feature(c_str_literals)]
5+
6+
fn main() {
7+
r#"aaa"#;
8+
r##"Hello "world"!"##;
9+
r######" "### "## "# "######;
10+
r######" "aa" "# "## "######;
11+
br#"aaa"#;
12+
br##"Hello "world"!"##;
13+
br######" "### "## "# "######;
14+
br######" "aa" "# "## "######;
15+
cr#"aaa"#;
16+
cr##"Hello "world"!"##;
17+
cr######" "### "## "# "######;
18+
cr######" "aa" "# "## "######;
19+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
error: unnecessary hashes around raw string literal
2+
--> $DIR/needless_raw_string_hashes.rs:7:5
3+
|
4+
LL | r#"aaa"#;
5+
| ^^^^^^^^ help: try: `r"aaa"`
6+
|
7+
= note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings`
8+
9+
error: unnecessary hashes around raw string literal
10+
--> $DIR/needless_raw_string_hashes.rs:8:5
11+
|
12+
LL | r##"Hello "world"!"##;
13+
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `r#"Hello "world"!"#`
14+
15+
error: unnecessary hashes around raw string literal
16+
--> $DIR/needless_raw_string_hashes.rs:9:5
17+
|
18+
LL | r######" "### "## "# "######;
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r####" "### "## "# "####`
20+
21+
error: unnecessary hashes around raw string literal
22+
--> $DIR/needless_raw_string_hashes.rs:10:5
23+
|
24+
LL | r######" "aa" "# "## "######;
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `r###" "aa" "# "## "###`
26+
27+
error: unnecessary hashes around raw string literal
28+
--> $DIR/needless_raw_string_hashes.rs:11:5
29+
|
30+
LL | br#"aaa"#;
31+
| ^^^^^^^^^ help: try: `br"aaa"`
32+
33+
error: unnecessary hashes around raw string literal
34+
--> $DIR/needless_raw_string_hashes.rs:12:5
35+
|
36+
LL | br##"Hello "world"!"##;
37+
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `br#"Hello "world"!"#`
38+
39+
error: unnecessary hashes around raw string literal
40+
--> $DIR/needless_raw_string_hashes.rs:13:5
41+
|
42+
LL | br######" "### "## "# "######;
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br####" "### "## "# "####`
44+
45+
error: unnecessary hashes around raw string literal
46+
--> $DIR/needless_raw_string_hashes.rs:14:5
47+
|
48+
LL | br######" "aa" "# "## "######;
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `br###" "aa" "# "## "###`
50+
51+
error: unnecessary hashes around raw string literal
52+
--> $DIR/needless_raw_string_hashes.rs:15:5
53+
|
54+
LL | cr#"aaa"#;
55+
| ^^^^^^^^^ help: try: `cr"aaa"`
56+
57+
error: unnecessary hashes around raw string literal
58+
--> $DIR/needless_raw_string_hashes.rs:16:5
59+
|
60+
LL | cr##"Hello "world"!"##;
61+
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr#"Hello "world"!"#`
62+
63+
error: unnecessary hashes around raw string literal
64+
--> $DIR/needless_raw_string_hashes.rs:17:5
65+
|
66+
LL | cr######" "### "## "# "######;
67+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr####" "### "## "# "####`
68+
69+
error: unnecessary hashes around raw string literal
70+
--> $DIR/needless_raw_string_hashes.rs:18:5
71+
|
72+
LL | cr######" "aa" "# "## "######;
73+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cr###" "aa" "# "## "###`
74+
75+
error: aborting due to 12 previous errors
76+

0 commit comments

Comments
 (0)