Skip to content

Commit f5cfac0

Browse files
committed
change category and refactor
Update raw_strings.rs Revert "new lints for visibility" This reverts commit 0e5a537. new lints for visibility
1 parent 4f4949e commit f5cfac0

File tree

4 files changed

+53
-15
lines changed

4 files changed

+53
-15
lines changed

clippy_lints/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,6 +1063,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
10631063
def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(),
10641064
})
10651065
});
1066+
let needless_raw_string_hashes_allow_one = conf.allow_one_hash_in_raw_string;
1067+
store.register_early_pass(move || {
1068+
Box::new(raw_strings::RawStrings {
1069+
needless_raw_string_hashes_allow_one,
1070+
})
1071+
});
10661072
// add lints here, do not remove this comment, it's used in `new_lint`
10671073
}
10681074

clippy_lints/src/raw_strings.rs

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::{iter::once, ops::ControlFlow};
2+
13
use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet};
24
use rustc_ast::{
35
ast::{Expr, ExprKind},
@@ -13,7 +15,8 @@ declare_clippy_lint! {
1315
/// Checks for raw string literals where a string literal can be used instead.
1416
///
1517
/// ### Why is this bad?
16-
/// It's just unnecessary.
18+
/// It's just unnecessary, but there are many cases where using a raw string literal is more
19+
/// idiomatic than a string literal, so it's opt-in.
1720
///
1821
/// ### Example
1922
/// ```rust
@@ -25,7 +28,7 @@ declare_clippy_lint! {
2528
/// ```
2629
#[clippy::version = "1.72.0"]
2730
pub NEEDLESS_RAW_STRING,
28-
complexity,
31+
restriction,
2932
"suggests using a string literal when a raw string literal is unnecessary"
3033
}
3134
declare_clippy_lint! {
@@ -46,7 +49,7 @@ declare_clippy_lint! {
4649
/// ```
4750
#[clippy::version = "1.72.0"]
4851
pub NEEDLESS_RAW_STRING_HASHES,
49-
complexity,
52+
style,
5053
"suggests reducing the number of hashes around a raw string literal"
5154
}
5255
impl_lint_pass!(RawStrings => [NEEDLESS_RAW_STRING, NEEDLESS_RAW_STRING_HASHES]);
@@ -59,8 +62,9 @@ impl EarlyLintPass for RawStrings {
5962
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
6063
if !in_external_macro(cx.sess(), expr.span)
6164
&& let ExprKind::Lit(lit) = expr.kind
62-
&& let LitKind::StrRaw(num) | LitKind::ByteStrRaw(num) | LitKind::CStrRaw(num) = lit.kind
65+
&& let LitKind::StrRaw(max) | LitKind::ByteStrRaw(max) | LitKind::CStrRaw(max) = lit.kind
6366
{
67+
let str = lit.symbol.as_str();
6468
let prefix = match lit.kind {
6569
LitKind::StrRaw(..) => "r",
6670
LitKind::ByteStrRaw(..) => "br",
@@ -71,7 +75,7 @@ impl EarlyLintPass for RawStrings {
7175
return;
7276
}
7377

74-
if !lit.symbol.as_str().contains(['\\', '"']) {
78+
if !str.contains(['\\', '"']) {
7579
span_lint_and_sugg(
7680
cx,
7781
NEEDLESS_RAW_STRING,
@@ -85,15 +89,43 @@ impl EarlyLintPass for RawStrings {
8589
return;
8690
}
8791

88-
#[expect(clippy::cast_possible_truncation)]
89-
let req = lit.symbol.as_str().as_bytes()
90-
.split(|&b| b == b'"')
91-
.skip(1)
92-
.map(|bs| 1 + bs.iter().take_while(|&&b| b == b'#').count() as u8)
93-
.max()
94-
.unwrap_or(0);
92+
let req = {
93+
let mut following_quote = false;
94+
let mut req = 0;
95+
// `once` so a raw string ending in hashes is still checked
96+
let num = str.as_bytes().iter().chain(once(&0)).try_fold(0u8, |acc, &b| {
97+
match b {
98+
b'"' => (following_quote, req) = (true, 1),
99+
// I'm a bit surprised the compiler didn't optimize this out, there's no
100+
// branch but it still ends up doing an unnecessary comparison, it's:
101+
// - cmp r9b,1h
102+
// - sbb cl,-1h
103+
// which will add 1 if it's true. With this change, it becomes:
104+
// - add cl,r9b
105+
// isn't that so much nicer?
106+
b'#' => req += u8::from(following_quote),
107+
_ => {
108+
if following_quote {
109+
following_quote = false;
110+
111+
if req == max {
112+
return ControlFlow::Break(req);
113+
}
114+
115+
return ControlFlow::Continue(acc.max(req));
116+
}
117+
},
118+
}
119+
120+
ControlFlow::Continue(acc)
121+
});
122+
123+
match num {
124+
ControlFlow::Continue(num) | ControlFlow::Break(num) => num,
125+
}
126+
};
95127

96-
if req < num {
128+
if req < max {
97129
let hashes = "#".repeat(req as usize);
98130

99131
span_lint_and_sugg(

tests/ui/needless_raw_string_hashes.fixed

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@run-rustfix
2-
#![allow(clippy::needless_raw_string, clippy::no_effect, unused)]
2+
#![allow(clippy::no_effect, unused)]
33
#![warn(clippy::needless_raw_string_hashes)]
44
#![feature(c_str_literals)]
55

tests/ui/needless_raw_string_hashes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//@run-rustfix
2-
#![allow(clippy::needless_raw_string, clippy::no_effect, unused)]
2+
#![allow(clippy::no_effect, unused)]
33
#![warn(clippy::needless_raw_string_hashes)]
44
#![feature(c_str_literals)]
55

0 commit comments

Comments
 (0)