@@ -3,16 +3,17 @@ use std::{
3
3
hash:: { Hash , Hasher } ,
4
4
} ;
5
5
6
- use clippy_utils:: diagnostics:: span_lint_and_help ;
6
+ use clippy_utils:: diagnostics:: span_lint_and_sugg ;
7
7
use clippy_utils:: source:: snippet_opt;
8
8
use if_chain:: if_chain;
9
9
use rustc_ast:: ast;
10
10
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
11
+ use rustc_errors:: Applicability ;
11
12
use rustc_hir:: def_id:: DefId ;
12
13
use rustc_lint:: { EarlyContext , EarlyLintPass } ;
13
14
use rustc_session:: { declare_tool_lint, impl_lint_pass} ;
14
15
use rustc_span:: hygiene:: { ExpnKind , MacroKind } ;
15
- use rustc_span:: { Span , Symbol } ;
16
+ use rustc_span:: Span ;
16
17
use serde:: { de, Deserialize } ;
17
18
18
19
declare_clippy_lint ! {
@@ -39,8 +40,8 @@ declare_clippy_lint! {
39
40
40
41
const BRACES : & [ ( & str , & str ) ] = & [ ( "(" , ")" ) , ( "{" , "}" ) , ( "[" , "]" ) ] ;
41
42
42
- /// The (name , (open brace, close brace), source snippet)
43
- type MacroInfo < ' a > = ( Symbol , & ' a ( String , String ) , String ) ;
43
+ /// The (callsite span , (open brace, close brace), source snippet)
44
+ type MacroInfo < ' a > = ( Span , & ' a ( String , String ) , String ) ;
44
45
45
46
#[ derive( Clone , Debug , Default ) ]
46
47
pub struct MacroBraces {
@@ -62,33 +63,29 @@ impl_lint_pass!(MacroBraces => [NONSTANDARD_MACRO_BRACES]);
62
63
63
64
impl EarlyLintPass for MacroBraces {
64
65
fn check_item ( & mut self , cx : & EarlyContext < ' _ > , item : & ast:: Item ) {
65
- if let Some ( ( name, braces, snip) ) = is_offending_macro ( cx, item. span , self ) {
66
- let span = item. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
67
- emit_help ( cx, snip, braces, name, span) ;
66
+ if let Some ( ( span, braces, snip) ) = is_offending_macro ( cx, item. span , self ) {
67
+ emit_help ( cx, & snip, braces, span) ;
68
68
self . done . insert ( span) ;
69
69
}
70
70
}
71
71
72
72
fn check_stmt ( & mut self , cx : & EarlyContext < ' _ > , stmt : & ast:: Stmt ) {
73
- if let Some ( ( name, braces, snip) ) = is_offending_macro ( cx, stmt. span , self ) {
74
- let span = stmt. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
75
- emit_help ( cx, snip, braces, name, span) ;
73
+ if let Some ( ( span, braces, snip) ) = is_offending_macro ( cx, stmt. span , self ) {
74
+ emit_help ( cx, & snip, braces, span) ;
76
75
self . done . insert ( span) ;
77
76
}
78
77
}
79
78
80
79
fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , expr : & ast:: Expr ) {
81
- if let Some ( ( name, braces, snip) ) = is_offending_macro ( cx, expr. span , self ) {
82
- let span = expr. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
83
- emit_help ( cx, snip, braces, name, span) ;
80
+ if let Some ( ( span, braces, snip) ) = is_offending_macro ( cx, expr. span , self ) {
81
+ emit_help ( cx, & snip, braces, span) ;
84
82
self . done . insert ( span) ;
85
83
}
86
84
}
87
85
88
86
fn check_ty ( & mut self , cx : & EarlyContext < ' _ > , ty : & ast:: Ty ) {
89
- if let Some ( ( name, braces, snip) ) = is_offending_macro ( cx, ty. span , self ) {
90
- let span = ty. span . ctxt ( ) . outer_expn_data ( ) . call_site ;
91
- emit_help ( cx, snip, braces, name, span) ;
87
+ if let Some ( ( span, braces, snip) ) = is_offending_macro ( cx, ty. span , self ) {
88
+ emit_help ( cx, & snip, braces, span) ;
92
89
self . done . insert ( span) ;
93
90
}
94
91
}
@@ -102,48 +99,44 @@ fn is_offending_macro<'a>(cx: &EarlyContext<'_>, span: Span, mac_braces: &'a Mac
102
99
. last ( )
103
100
. map_or ( false , |e| e. macro_def_id . map_or ( false , DefId :: is_local) )
104
101
} ;
102
+ let span_call_site = span. ctxt ( ) . outer_expn_data ( ) . call_site ;
105
103
if_chain ! {
106
104
if let ExpnKind :: Macro ( MacroKind :: Bang , mac_name) = span. ctxt( ) . outer_expn_data( ) . kind;
107
105
let name = mac_name. as_str( ) ;
108
106
if let Some ( braces) = mac_braces. macro_braces. get( name) ;
109
- if let Some ( snip) = snippet_opt( cx, span . ctxt ( ) . outer_expn_data ( ) . call_site ) ;
107
+ if let Some ( snip) = snippet_opt( cx, span_call_site ) ;
110
108
// we must check only invocation sites
111
109
// https://github.com/rust-lang/rust-clippy/issues/7422
112
110
if snip. starts_with( & format!( "{}!" , name) ) ;
113
111
if unnested_or_local( ) ;
114
112
// make formatting consistent
115
113
let c = snip. replace( ' ' , "" ) ;
116
114
if !c. starts_with( & format!( "{}!{}" , name, braces. 0 ) ) ;
117
- if !mac_braces. done. contains( & span . ctxt ( ) . outer_expn_data ( ) . call_site ) ;
115
+ if !mac_braces. done. contains( & span_call_site ) ;
118
116
then {
119
- Some ( ( mac_name , braces, snip) )
117
+ Some ( ( span_call_site , braces, snip) )
120
118
} else {
121
119
None
122
120
}
123
121
}
124
122
}
125
123
126
- fn emit_help ( cx : & EarlyContext < ' _ > , snip : String , braces : & ( String , String ) , name : Symbol , span : Span ) {
127
- let with_space = & format ! ( "! {}" , braces. 0 ) ;
128
- let without_space = & format ! ( "!{}" , braces. 0 ) ;
129
- let mut help = snip;
130
- for b in BRACES . iter ( ) . filter ( |b| b. 0 != braces. 0 ) {
131
- help = help. replace ( b. 0 , & braces. 0 ) . replace ( b. 1 , & braces. 1 ) ;
132
- // Only `{` traditionally has space before the brace
133
- if braces. 0 != "{" && help. contains ( with_space) {
134
- help = help. replace ( with_space, without_space) ;
135
- } else if braces. 0 == "{" && help. contains ( without_space) {
136
- help = help. replace ( without_space, with_space) ;
137
- }
124
+ fn emit_help ( cx : & EarlyContext < ' _ > , snip : & str , braces : & ( String , String ) , span : Span ) {
125
+ if let Some ( ( macro_name, macro_args_str) ) = snip. split_once ( '!' ) {
126
+ let mut macro_args = macro_args_str. trim ( ) . to_string ( ) ;
127
+ // now remove the wrong braces
128
+ macro_args. remove ( 0 ) ;
129
+ macro_args. pop ( ) ;
130
+ span_lint_and_sugg (
131
+ cx,
132
+ NONSTANDARD_MACRO_BRACES ,
133
+ span,
134
+ & format ! ( "use of irregular braces for `{}!` macro" , macro_name) ,
135
+ "consider writing" ,
136
+ format ! ( "{}!{}{}{}" , macro_name, braces. 0 , macro_args, braces. 1 ) ,
137
+ Applicability :: MachineApplicable ,
138
+ ) ;
138
139
}
139
- span_lint_and_help (
140
- cx,
141
- NONSTANDARD_MACRO_BRACES ,
142
- span,
143
- & format ! ( "use of irregular braces for `{}!` macro" , name) ,
144
- Some ( span) ,
145
- & format ! ( "consider writing `{}`" , help) ,
146
- ) ;
147
140
}
148
141
149
142
fn macro_braces ( conf : FxHashSet < MacroMatcher > ) -> FxHashMap < String , ( String , String ) > {
0 commit comments