8000 fix `nonstandard_macro_braces`: suggest trailing semicolon when needed · rust-lang/rust-clippy@0234675 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0234675

Browse files
committed
fix nonstandard_macro_braces: suggest trailing semicolon when needed
1 parent 7fd0b9e commit 0234675

File tree

4 files changed

+46
-21
lines changed

4 files changed

+46
-21
lines changed

clippy_lints/src/nonstandard_macro_braces.rs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ declare_clippy_lint! {
1616
/// Checks that common macros are used with consistent bracing.
1717
///
1818
/// ### Why is this bad?
19-
/// This is mostly a consistency lint although using () or []
20-
/// doesn't give you a semicolon in item position, which can be unexpected.
19+
/// This is mostly a consistency lint.
2120
///
2221
/// ### Example
2322
/// ```no_run
@@ -33,8 +32,8 @@ declare_clippy_lint! {
3332
"check consistent use of braces in macro"
3433
}
3534

36-
/// The (callsite span, (open brace, close brace), source snippet)
37-
type MacroInfo = (Span, (char, char), SourceText);
35+
/// The (callsite span, old open brace, (open brace, close brace), source snippet)
36+
type MacroInfo = (Span, char, (char, char), SourceText);
3837

3938
pub struct MacroBraces {
4039
macro_braces: FxHashMap<String, (char, char)>,
@@ -54,29 +53,33 @@ impl_lint_pass!(MacroBraces => [NONSTANDARD_MACRO_BRACES]);
5453

5554
impl EarlyLintPass for MacroBraces {
5655
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
57-
if let Some((span, braces, snip)) = is_offending_macro(cx, item.span, self) {
58-
emit_help(cx, &snip, braces, span);
56+
if let Some((span, _, braces, snip)) = is_offending_macro(cx, item.span, self) {
57+
emit_help(cx, &snip, braces, span, false);
5958
self.done.insert(span);
6059
}
6160
}
6261

6362
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
64-
if let Some((span, braces, snip)) = is_offending_macro(cx, stmt.span, self) {
65-
emit_help(cx, &snip, braces, 8000 span);
63+
if let Some((span, old_open_brace, braces, snip)) = is_offending_macro(cx, stmt.span, self) {
64+
// if we turn `macro!{}` into `macro!()`/`macro![]`, we'll no longer get the implicit
65+
// trailing semicolon, see #9913
66+
// NOTE: `stmt.kind != StmtKind::MacCall` because `EarlyLintPass` happens after macro expansion
67+
let add_semi = matches!(stmt.kind, ast::StmtKind::Expr(..)) && old_open_brace == '{';
68+
emit_help(cx, &snip, braces, span, add_semi);
6669
self.done.insert(span);
6770
}
6871
}
6972

7073
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
71-
if let Some((span, braces, snip)) = is_offending_macro(cx, expr.span, self) {
72-
emit_help(cx, &snip, braces, span);
74+
if let Some((span, _, braces, snip)) = is_offending_macro(cx, expr.span, self) {
75+
emit_help(cx, &snip, braces, span, false);
7376
self.done.insert(span);
7477
}
7578
}
7679

7780
fn check_ty(&mut self, cx: &EarlyContext<'_>, ty: &ast::Ty) {
78-
if let Some((span, braces, snip)) = is_offending_macro(cx, ty.span, self) {
79-
emit_help(cx, &snip, braces, span);
81+
if let Some((span, _, braces, snip)) = is_offending_macro(cx, ty.span, self) {
82+
emit_help(cx, &snip, braces, span, false);
8083
self.done.insert(span);
8184
}
8285
}
@@ -97,32 +100,32 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace
97100
&& let Some(snip) = span_call_site.get_source_text(cx)
98101
// we must check only invocation sites
99102
// https://github.com/rust-lang/rust-clippy/issues/7422
100-
&& snip.starts_with(&format!("{name}!"))
103+
&& let Some(macro_args_str) = snip.strip_prefix(name).and_then(|snip| snip.strip_prefix('!'))
104+
&& let Some(old_open_brace @ ('{' | '(' | '[')) = macro_args_str.trim_start().chars().next()
105+
&& old_open_brace != braces.0
101106
&& unnested_or_local()
102-
// make formatting consistent
103-
&& let c = snip.replace(' ', "")
104-
&& !c.starts_with(&format!("{name}!{}", braces.0))
105107
&& !mac_braces.done.contains(&span_call_site)
106108
{
107-
Some((span_call_site, braces, snip))
109+
Some((span_call_site, old_open_brace, braces, snip))
108110
} else {
109111
None
110112
}
111113
}
112114

113-
fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), span: Span) {
115+
fn emit_help(cx: &EarlyContext<'_>, snip: &str, (open, close): (char, char), span: Span, add_semi: bool) {
116+
let semi = if add_semi { ";" } else { "" };
114117
if let Some((macro_name, macro_args_str)) = snip.split_once('!') {
115118
let mut macro_args = macro_args_str.trim().to_string();
116119
// now remove the wrong braces
117-
macro_args.remove(0);
118120
macro_args.pop();
121+
macro_args.remove(0);
119122
span_lint_and_sugg(
120123
cx,
121124
NONSTANDARD_MACRO_BRACES,
122125
span,
123126
format!("use of irregular braces for `{macro_name}!` macro"),
124127
"consider writing",
125-
format!("{macro_name}!{open}{macro_args}{close}"),
128+
format!("{macro_name}!{open}{macro_args}{close}{semi}"),
126129
Applicability::MachineApplicable,
127130
);
128131
}

tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,11 @@ fn main() {
6767

6868
printlnfoo!["test if printlnfoo is triggered by println"];
6969
}
70+
71+
#[rustfmt::skip]
72+
#[expect(clippy::no_effect)]
73+
fn issue9913() {
74+
println!("hello world");
75+
[0]; // separate statement, not indexing into the result of println.
76+
//~^^ nonstandard_macro_braces
77+
}

tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,11 @@ fn main() {
6767

6868
printlnfoo!["test if printlnfoo is triggered by println"];
6969
}
70+
71+
#[rustfmt::skip]
72+
#[expect(clippy::no_effect)]
73+
fn issue9913() {
74+
println! {"hello world"}
75+
[0]; // separate statement, not indexing into the result of println.
76+
//~^^ nonstandard_macro_braces
77+
}

tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,11 @@ error: use of irregular braces for `eprint!` macro
5454
LL | eprint!("test if user config overrides defaults");
5555
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `eprint!["test if user config overrides defaults"]`
5656

57-
error: aborting due to 8 previous errors
57+
error: use of irregular braces for `println!` macro
58+
--> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:74:5
59+
|
60+
LL | println! {"hello world"}
61+
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `println!("hello world");`
62+
63+
error: aborting due to 9 previous errors
5864

0 commit comments

Comments
 (0)
0