Add new useless_concat lint
This commit is contained in:
parent
2ce5451850
commit
a8679816dc
4 changed files with 112 additions and 0 deletions
|
|
@ -6438,6 +6438,7 @@ Released 2018-09-13
|
|||
[`used_underscore_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items
|
||||
[`useless_asref`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_asref
|
||||
[`useless_attribute`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_attribute
|
||||
[`useless_concat`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_concat
|
||||
[`useless_conversion`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
|
||||
[`useless_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_format
|
||||
[`useless_let_if_seq`]: https://rust-lang.github.io/rust-clippy/master/index.html#useless_let_if_seq
|
||||
|
|
|
|||
|
|
@ -762,6 +762,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
|
|||
crate::unwrap_in_result::UNWRAP_IN_RESULT_INFO,
|
||||
crate::upper_case_acronyms::UPPER_CASE_ACRONYMS_INFO,
|
||||
crate::use_self::USE_SELF_INFO,
|
||||
crate::useless_concat::USELESS_CONCAT_INFO,
|
||||
crate::useless_conversion::USELESS_CONVERSION_INFO,
|
||||
crate::vec::USELESS_VEC_INFO,
|
||||
crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
|
||||
|
|
|
|||
|
|
@ -392,6 +392,7 @@ mod unwrap;
|
|||
mod unwrap_in_result;
|
||||
mod upper_case_acronyms;
|
||||
mod use_self;
|
||||
mod useless_concat;
|
||||
mod useless_conversion;
|
||||
mod vec;
|
||||
mod vec_init_then_push;
|
||||
|
|
@ -936,6 +937,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
|
|||
store.register_late_pass(|_| Box::new(unnecessary_literal_bound::UnnecessaryLiteralBound));
|
||||
store.register_early_pass(|| Box::new(empty_line_after::EmptyLineAfter::new()));
|
||||
store.register_late_pass(move |_| Box::new(arbitrary_source_item_ordering::ArbitrarySourceItemOrdering::new(conf)));
|
||||
store.register_late_pass(|_| Box::new(useless_concat::UselessConcat));
|
||||
store.register_late_pass(|_| Box::new(unneeded_struct_pattern::UnneededStructPattern));
|
||||
store.register_late_pass(|_| Box::<unnecessary_semicolon::UnnecessarySemicolon>::default());
|
||||
store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf)));
|
||||
|
|
|
|||
108
clippy_lints/src/useless_concat.rs
Normal file
108
clippy_lints/src/useless_concat.rs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
use clippy_utils::diagnostics::span_lint_and_sugg;
|
||||
use clippy_utils::macros::macro_backtrace;
|
||||
use clippy_utils::source::snippet_opt;
|
||||
use clippy_utils::{match_def_path, tokenize_with_text};
|
||||
use rustc_ast::LitKind;
|
||||
use rustc_errors::Applicability;
|
||||
use rustc_hir::{Expr, ExprKind};
|
||||
use rustc_lexer::TokenKind;
|
||||
use rustc_lint::{LateContext, LateLintPass};
|
||||
use rustc_session::declare_lint_pass;
|
||||
|
||||
declare_clippy_lint! {
|
||||
/// ### What it does
|
||||
/// Checks that the `concat!` macro has at least two arguments.
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// If there are less than 2 arguments, then calling the macro is doing nothing.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```no_run
|
||||
/// let x = concat!("a");
|
||||
/// ```
|
||||
/// Use instead:
|
||||
/// ```no_run
|
||||
/// let x = "a";
|
||||
/// ```
|
||||
#[clippy::version = "1.85.0"]
|
||||
pub USELESS_CONCAT,
|
||||
complexity,
|
||||
"checks that the `concat` macro has at least two arguments"
|
||||
}
|
||||
|
||||
declare_lint_pass!(UselessConcat => [USELESS_CONCAT]);
|
||||
|
||||
impl LateLintPass<'_> for UselessConcat {
|
||||
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
|
||||
// Check that the expression is generated by a macro.
|
||||
if expr.span.from_expansion()
|
||||
// Check that it's a string literal.
|
||||
&& let ExprKind::Lit(lit) = expr.kind
|
||||
&& let LitKind::Str(_, _) = lit.node
|
||||
// Get the direct parent of the expression.
|
||||
&& let Some(macro_call) = macro_backtrace(expr.span).next()
|
||||
// Check if the `concat` macro from the `core` library.
|
||||
&& match_def_path(cx, macro_call.def_id, &["core", "macros", "builtin", "concat"])
|
||||
// We get the original code to parse it.
|
||||
&& let Some(original_code) = snippet_opt(cx, macro_call.span)
|
||||
// This check allows us to ensure that the code snippet:
|
||||
// 1. Doesn't come from proc-macro expansion.
|
||||
// 2. Doesn't come from foreign macro expansion.
|
||||
//
|
||||
// It works as follows: if the snippet we get doesn't contain `concat!(`, then it
|
||||
// means it's not code written in the current crate so we shouldn't lint.
|
||||
&& let mut parts = original_code.split('!')
|
||||
&& parts.next().is_some_and(|p| p.trim() == "concat")
|
||||
&& parts.next().is_some_and(|p| p.trim().starts_with('('))
|
||||
{
|
||||
let mut literal = None;
|
||||
let mut nb_commas = 0;
|
||||
let mut nb_idents = 0;
|
||||
for (token_kind, token_s, _) in tokenize_with_text(&original_code) {
|
||||
match token_kind {
|
||||
TokenKind::Eof => break,
|
||||
TokenKind::Literal { .. } => {
|
||||
if literal.is_some() {
|
||||
return;
|
||||
}
|
||||
literal = Some(token_s);
|
||||
},
|
||||
TokenKind::Ident => nb_idents += 1,
|
||||
TokenKind::Comma => {
|
||||
nb_commas += 1;
|
||||
if nb_commas > 1 {
|
||||
return;
|
||||
}
|
||||
},
|
||||
// We're inside a macro definition and we are manipulating something we likely
|
||||
// shouldn't, so aborting.
|
||||
TokenKind::Dollar => return,
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
let literal = match literal {
|
||||
Some(lit) => {
|
||||
// Literals can also be number, so we need to check this case too.
|
||||
if lit.starts_with('"') {
|
||||
lit.to_string()
|
||||
} else {
|
||||
format!("\"{lit}\"")
|
||||
}
|
||||
},
|
||||
None => "\"\"".to_string(),
|
||||
};
|
||||
// There should always be the ident of the `concat` macro.
|
||||
if nb_idents == 1 {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
USELESS_CONCAT,
|
||||
macro_call.span,
|
||||
"unneeded use of `concat!` macro",
|
||||
"replace with",
|
||||
literal,
|
||||
Applicability::MachineApplicable,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue