Skip to content

Commit c1e2a7f

Browse files
Improve code and apply suggestions
1 parent 7b06d2b commit c1e2a7f

File tree

5 files changed

+159
-12
lines changed

5 files changed

+159
-12
lines changed

clippy_lints/src/useless_concat.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::macros::macro_backtrace;
33
use clippy_utils::paths::CONCAT;
44
use clippy_utils::source::snippet_opt;
5-
use clippy_utils::{match_def_path, tokenize_with_text};
5+
use clippy_utils::tokenize_with_text;
66
use rustc_ast::LitKind;
77
use rustc_errors::Applicability;
88
use rustc_hir::{Expr, ExprKind};
@@ -43,7 +43,7 @@ impl LateLintPass<'_> for UselessConcat {
4343
// Get the direct parent of the expression.
4444
&& let Some(macro_call) = macro_backtrace(expr.span).next()
4545
// Check if the `concat` macro from the `core` library.
46-
&& match_def_path(cx, macro_call.def_id, &CONCAT)
46+
&& CONCAT.matches(cx, macro_call.def_id)
4747
// We get the original code to parse it.
4848
&& let Some(original_code) = snippet_opt(cx, macro_call.span)
4949
// This check allows us to ensure that the code snippet:
@@ -68,7 +68,13 @@ impl LateLintPass<'_> for UselessConcat {
6868
}
6969
literal = Some(token_s);
7070
},
71-
TokenKind::Ident => nb_idents += 1,
71+
TokenKind::Ident => {
72+
if token_s == "true" || token_s == "false" {
73+
literal = Some(token_s);
74+
} else {
75+
nb_idents += 1;
76+
}
77+
},
7278
TokenKind::Comma => {
7379
nb_commas += 1;
7480
if nb_commas > 1 {
@@ -82,12 +88,49 @@ impl LateLintPass<'_> for UselessConcat {
8288
}
8389
}
8490
let literal = match literal {
85-
Some(lit) => {
91+
Some(original_lit) => {
8692
// Literals can also be number, so we need to check this case too.
93+
let lit = original_lit.strip_prefix("r").unwrap_or(original_lit);
94+
let lit = lit.trim_start_matches('#');
8795
if lit.starts_with('"') {
88-
lit.to_string()
96+
// It's a string, nothing to be done.
97+
original_lit.to_string()
98+
} else if original_lit.starts_with('\'') {
99+
if original_lit == "'\"'" {
100+
// If it's a double quote, we need to escape it.
101+
"\"\\\"\"".to_string()
102+
} else {
103+
format!(
104+
"\"{}\"",
105+
original_lit
106+
.strip_prefix('\'')
107+
.and_then(|l| l.strip_suffix('\''))
108+
.unwrap_or(original_lit)
109+
)
110+
}
111+
} else if original_lit == "true" || original_lit == "false" {
112+
// It's a boolean so nothing else to be done.
113+
format!("\"{original_lit}\"")
89114
} else {
90-
format!("\"{lit}\"")
115+
let lit = original_lit
116+
.strip_suffix("f16")
117+
.or_else(|| original_lit.strip_suffix("f32"))
118+
.or_else(|| original_lit.strip_suffix("f64"))
119+
.or_else(|| original_lit.strip_suffix("128")) // We never know?
120+
.or_else(|| original_lit.strip_suffix("u8"))
121+
.or_else(|| original_lit.strip_suffix("u16"))
122+
.or_else(|| original_lit.strip_suffix("u32"))
123+
.or_else(|| original_lit.strip_suffix("u64"))
124+
.or_else(|| original_lit.strip_suffix("u128"))
125+
.or_else(|| original_lit.strip_suffix("usize"))
126+
.or_else(|| original_lit.strip_suffix("i8"))
127+
.or_else(|| original_lit.strip_suffix("i16"))
128+
.or_else(|| original_lit.strip_suffix("i32"))
129+
.or_else(|| original_lit.strip_suffix("i64"))
130+
.or_else(|| original_lit.strip_suffix("i128"))
131+
.or_else(|| original_lit.strip_suffix("isize"))
132+
.unwrap_or(original_lit);
133+
format!("\"{}\"", lit.strip_suffix('_').unwrap_or(lit))
91134
}
92135
},
93136
None => "\"\"".to_string(),

clippy_utils/src/paths.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,14 @@ path_macros! {
129129
// Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items.
130130
pub static ALIGN_OF: PathLookup = value_path!(core::mem::align_of);
131131
pub static CHAR_TO_DIGIT: PathLookup = value_path!(char::to_digit);
132-
pub static CONCAT: PathLookup = value_path!(core::macros::builtin::concat);
133132
pub static IO_ERROR_NEW: PathLookup = value_path!(std::io::Error::new);
134133
pub static IO_ERRORKIND_OTHER_CTOR: PathLookup = value_path!(std::io::ErrorKind::Other);
135134
pub static ITER_STEP: PathLookup = type_path!(core::iter::Step);
136135
pub static SLICE_FROM_REF: PathLookup = value_path!(core::slice::from_ref);
137136

137+
// This path is wrongly computed when using `PathLookup`.
138+
pub static CONCAT: PathLookup = macro_path!(core::concat);
139+
138140
// Paths in external crates
139141
pub static FUTURES_IO_ASYNCREADEXT: PathLookup = type_path!(futures_util::AsyncReadExt);
140142
pub static FUTURES_IO_ASYNCWRITEEXT: PathLookup = type_path!(futures_util::AsyncWriteExt);

tests/ui/useless_concat.fixed

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
//@aux-build:proc_macros.rs
2+
13
#![warn(clippy::useless_concat)]
24
#![allow(clippy::print_literal)]
35

6+
extern crate proc_macros;
7+
use proc_macros::{external, with_span};
8+
49
macro_rules! my_concat {
510
($fmt:literal $(, $e:expr)*) => {
611
println!(concat!("ERROR: ", $fmt), $($e,)*);
@@ -9,12 +14,28 @@ macro_rules! my_concat {
914

1015
fn main() {
1116
let x = ""; //~ useless_concat
17+
let x = "c"; //~ useless_concat
18+
let x = "\""; //~ useless_concat
19+
let x = "true"; //~ useless_concat
20+
let x = "1"; //~ useless_concat
21+
let x = "1.0000"; //~ useless_concat
22+
let x = "1"; //~ useless_concat
23+
let x = "1"; //~ useless_concat
24+
let x = "1.0000"; //~ useless_concat
25+
let x = "1.0000"; //~ useless_concat
1226
let x = "a"; //~ useless_concat
27+
let x = r##"a"##; //~ useless_concat
1328
let x = "1"; //~ useless_concat
1429
println!("b: {}", "a"); //~ useless_concat
1530
// Should not lint.
1631
let x = concat!("a", "b");
1732
let local_i32 = 1;
1833
my_concat!("{}", local_i32);
1934
let x = concat!(file!(), "#L", line!());
35+
36+
external! { concat!(); }
37+
with_span! {
38+
span
39+
concat!();
40+
}
2041
}

tests/ui/useless_concat.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
//@aux-build:proc_macros.rs
2+
13
#![warn(clippy::useless_concat)]
24
#![allow(clippy::print_literal)]
35

6+
extern crate proc_macros;
7+
use proc_macros::{external, with_span};
8+
49
macro_rules! my_concat {
510
($fmt:literal $(, $e:expr)*) => {
611
println!(concat!("ERROR: ", $fmt), $($e,)*);
@@ -9,12 +14,28 @@ macro_rules! my_concat {
914

1015
fn main() {
1116
let x = concat!(); //~ useless_concat
17+
let x = concat!('c'); //~ useless_concat
18+
let x = concat!('"'); //~ useless_concat
19+
let x = concat!(true); //~ useless_concat
20+
let x = concat!(1f32); //~ useless_concat
21+
let x = concat!(1.0000f32); //~ useless_concat
22+
let x = concat!(1_f32); //~ useless_concat
23+
let x = concat!(1_); //~ useless_concat
24+
let x = concat!(1.0000_f32); //~ useless_concat
25+
let x = concat!(1.0000_); //~ useless_concat
1226
let x = concat!("a"); //~ useless_concat
27+
let x = concat!(r##"a"##); //~ useless_concat
1328
let x = concat!(1); //~ useless_concat
1429
println!("b: {}", concat!("a")); //~ useless_concat
1530
// Should not lint.
1631
let x = concat!("a", "b");
1732
let local_i32 = 1;
1833
my_concat!("{}", local_i32);
1934
let x = concat!(file!(), "#L", line!());
35+
36+
external! { concat!(); }
37+
with_span! {
38+
span
39+
concat!();
40+
}
2041
}

tests/ui/useless_concat.stderr

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: unneeded use of `concat!` macro
2-
--> tests/ui/useless_concat.rs:11:13
2+
--> tests/ui/useless_concat.rs:16:13
33
|
44
LL | let x = concat!();
55
| ^^^^^^^^^ help: replace with: `""`
@@ -8,22 +8,82 @@ LL | let x = concat!();
88
= help: to override `-D warnings` add `#[allow(clippy::useless_concat)]`
99

1010
error: unneeded use of `concat!` macro
11-
--> tests/ui/useless_concat.rs:12:13
11+
--> tests/ui/useless_concat.rs:17:13
12+
|
13+
LL | let x = concat!('c');
14+
| ^^^^^^^^^^^^ help: replace with: `"c"`
15+
16+
error: unneeded use of `concat!` macro
17+
--> tests/ui/useless_concat.rs:18:13
18+
|
19+
LL | let x = concat!('"');
20+
| ^^^^^^^^^^^^ help: replace with: `"\""`
21+
22+
error: unneeded use of `concat!` macro
23+
--> tests/ui/useless_concat.rs:19:13
24+
|
25+
LL | let x = concat!(true);
26+
| ^^^^^^^^^^^^^ help: replace with: `"true"`
27+
28+
error: unneeded use of `concat!` macro
29+
--> tests/ui/useless_concat.rs:20:13
30+
|
31+
LL | let x = concat!(1f32);
32+
| ^^^^^^^^^^^^^ help: replace with: `"1"`
33+
34+
error: unneeded use of `concat!` macro
35+
--> tests/ui/useless_concat.rs:21:13
36+
|
37+
LL | let x = concat!(1.0000f32);
38+
| ^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
39+
40+
error: unneeded use of `concat!` macro
41+
--> tests/ui/useless_concat.rs:22:13
42+
|
43+
LL | let x = concat!(1_f32);
44+
| ^^^^^^^^^^^^^^ help: replace with: `"1"`
45+
46+
error: unneeded use of `concat!` macro
47+
--> tests/ui/useless_concat.rs:23:13
48+
|
49+
LL | let x = concat!(1_);
50+
| ^^^^^^^^^^^ help: replace with: `"1"`
51+
52+
error: unneeded use of `concat!` macro
53+
--> tests/ui/useless_concat.rs:24:13
54+
|
55+
LL | let x = concat!(1.0000_f32);
56+
| ^^^^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
57+
58+
error: unneeded use of `concat!` macro
59+
--> tests/ui/useless_concat.rs:25:13
60+
|
61+
LL | let x = concat!(1.0000_);
62+
| ^^^^^^^^^^^^^^^^ help: replace with: `"1.0000"`
63+
64+
error: unneeded use of `concat!` macro
65+
--> tests/ui/useless_concat.rs:26:13
1266
|
1367
LL | let x = concat!("a");
1468
| ^^^^^^^^^^^^ help: replace with: `"a"`
1569

1670
error: unneeded use of `concat!` macro
17-
--> tests/ui/useless_concat.rs:13:13
71+
--> tests/ui/useless_concat.rs:27:13
72+
|
73+
LL | let x = concat!(r##"a"##);
74+
| ^^^^^^^^^^^^^^^^^ help: replace with: `r##"a"##`
75+
76+
error: unneeded use of `concat!` macro
77+
--> tests/ui/useless_concat.rs:28:13
1878
|
1979
LL | let x = concat!(1);
2080
| ^^^^^^^^^^ help: replace with: `"1"`
2181

2282
error: unneeded use of `concat!` macro
23-
--> tests/ui/useless_concat.rs:14:23
83+
--> tests/ui/useless_concat.rs:29:23
2484
|
2585
LL | println!("b: {}", concat!("a"));
2686
| ^^^^^^^^^^^^ help: replace with: `"a"`
2787

28-
error: aborting due to 4 previous errors
88+
error: aborting due to 14 previous errors
2989

0 commit comments

Comments
 (0)