@@ -16,8 +16,7 @@ declare_clippy_lint! {
16
16
/// Checks that common macros are used with consistent bracing.
17
17
///
18
18
/// ### 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.
21
20
///
22
21
/// ### Example
23
22
/// ```no_run
@@ -33,8 +32,8 @@ declare_clippy_lint! {
33
32
"check consistent use of braces in macro"
34
33
}
35
34
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 ) ;
38
37
39
38
pub struct MacroBraces {
40
39
macro_braces : FxHashMap < String , ( char , char ) > ,
@@ -54,29 +53,33 @@ impl_lint_pass!(MacroBraces => [NONSTANDARD_MACRO_BRACES]);
54
53
55
54
impl EarlyLintPass for MacroBraces {
56
55
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 ) ;
59
58
self . done . insert ( span) ;
60
59
}
61
60
}
62
61
63
62
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, 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) ;
66
69
self . done . insert ( span) ;
67
70
}
68
71
}
69
72
70
73
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 ) ;
73
76
self . done . insert ( span) ;
74
77
}
75
78
}
76
79
77
80
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 ) ;
80
83
self . done . insert ( span) ;
81
84
}
82
85
}
@@ -97,32 +100,32 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace
97
100
&& let Some ( snip) = span_call_site. get_source_text ( cx)
98
101
// we must check only invocation sites
99
102
// 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
101
106
&& unnested_or_local ( )
102
- // make formatting consistent
103
- && let c = snip. replace ( ' ' , "" )
104
- && !c. starts_with ( & format ! ( "{name}!{}" , braces. 0 ) )
105
107
&& !mac_braces. done . contains ( & span_call_site)
106
108
{
107
- Some ( ( span_call_site, braces, snip) )
109
+ Some ( ( span_call_site, old_open_brace , braces, snip) )
108
110
} else {
109
111
None
110
112
}
111
113
}
112
114
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 { "" } ;
114
117
if let Some ( ( macro_name, macro_args_str) ) = snip. split_once ( '!' ) {
115
118
let mut macro_args = macro_args_str. trim ( ) . to_string ( ) ;
116
119
// now remove the wrong braces
117
- macro_args. remove ( 0 ) ;
118
120
macro_args. pop ( ) ;
121
+ macro_args. remove ( 0 ) ;
119
122
span_lint_and_sugg (
120
123
cx,
121
124
NONSTANDARD_MACRO_BRACES ,
122
125
span,
123
126
format ! ( "use of irregular braces for `{macro_name}!` macro" ) ,
124
127
"consider writing" ,
125
- format ! ( "{macro_name}!{open}{macro_args}{close}" ) ,
128
+ format ! ( "{macro_name}!{open}{macro_args}{close}{semi} " ) ,
126
129
Applicability :: MachineApplicable ,
127
130
) ;
128
131
}
0 commit comments