Skip to content

Commit

Permalink
new lint needless_raw_string + refactor a bit
Browse files Browse the repository at this point in the history
Thanks, #112373, for the snippet at line 75!
  • Loading branch information
Centri3 committed Jun 8, 2023
1 parent 3ba8a5a commit 915096b
Show file tree
Hide file tree
Showing 26 changed files with 272 additions and 155 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5016,6 +5016,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
Expand Down
3 changes: 2 additions & 1 deletion clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,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,
Expand Down Expand Up @@ -534,6 +533,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,
Expand Down
9 changes: 7 additions & 2 deletions clippy_lints/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,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;
Expand Down Expand Up @@ -259,6 +258,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;
Expand Down Expand Up @@ -1017,7 +1017,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(endian_bytes::EndianBytes));
store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations));
store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync));
store.register_early_pass(|| Box::new(needless_raw_string_hashes::NeedlessRawStringHashes));
let needless_raw_string_hashes_allow_one = conf.allow_one_hash_in_raw_string;
store.register_early_pass(move || {
Box::new(raw_strings::RawStrings {
needless_raw_string_hashes_allow_one,
})
});
// add lints here, do not remove this comment, it's used in `new_lint`
}

Expand Down
73 changes: 0 additions & 73 deletions clippy_lints/src/needless_raw_string_hashes.rs

This file was deleted.

109 changes: 109 additions & 0 deletions clippy_lints/src/raw_strings.rs
Original file line number Diff line number Diff line change
@@ -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,
);
}
}
}
}
4 changes: 4 additions & 0 deletions clippy_lints/src/utils/conf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,10 @@ define_Conf! {
///
/// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
(unnecessary_box_size: u64 = 128),
/// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>...]
Expand Down
30 changes: 15 additions & 15 deletions tests/lint_message_convention.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
});
Expand All @@ -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()
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//@compile-flags: --crate-name conf_disallowed_methods

#![allow(clippy::needless_raw_string)]
#![warn(clippy::disallowed_methods)]
#![allow(clippy::useless_vec)]

Expand Down
Loading

0 comments on commit 915096b

Please sign in to comment.