@@ -72,18 +72,38 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
72
72
// Find the span of the argument to `panic!()`, before expansion in the
73
73
// case of `panic!(some_macro!())`.
74
74
let mut arg_span = arg. span ;
75
+ let mut arg_macro = None ;
75
76
while !span. contains ( arg_span) {
76
77
let expn = arg_span. ctxt ( ) . outer_expn_data ( ) ;
77
78
if expn. is_root ( ) {
78
79
break ;
79
80
}
81
+ arg_macro = expn. macro_def_id ;
80
82
arg_span = expn. call_site ;
81
83
}
82
84
83
85
cx. struct_span_lint ( NON_FMT_PANIC , arg_span, |lint| {
84
86
let mut l = lint. build ( "panic message is not a string literal" ) ;
85
87
l. note ( "this is no longer accepted in Rust 2021" ) ;
86
- if span. contains ( arg_span) {
88
+ if !span. contains ( arg_span) {
89
+ // No clue where this argument is coming from.
90
+ l. emit ( ) ;
91
+ return ;
92
+ }
93
+ if arg_macro. map_or ( false , |id| cx. tcx . is_diagnostic_item ( sym:: format_macro, id) ) {
94
+ // A case of `panic!(format!(..))`.
95
+ l. note ( "the panic!() macro supports formatting, so there's no need for the format!() macro here" ) ;
96
+ if let Some ( inner) = find_inner_span ( cx, arg_span) {
97
+ l. multipart_suggestion (
98
+ "remove the `format!(..)` macro call" ,
99
+ vec ! [
100
+ ( arg_span. until( inner) , "" . into( ) ) ,
101
+ ( inner. between( arg_span. shrink_to_hi( ) ) , "" . into( ) ) ,
102
+ ] ,
103
+ Applicability :: MachineApplicable ,
104
+ ) ;
105
+ }
106
+ } else {
87
107
l. span_suggestion_verbose (
88
108
arg_span. shrink_to_lo ( ) ,
89
109
"add a \" {}\" format string to Display the message" ,
@@ -186,6 +206,15 @@ fn check_panic_str<'tcx>(
186
206
}
187
207
}
188
208
209
+ /// Given the span of `some_macro!(args)`, gives the span of `args`.
210
+ fn find_inner_span < ' tcx > ( cx : & LateContext < ' tcx > , span : Span ) -> Option < Span > {
211
+ let snippet = cx. sess ( ) . parse_sess . source_map ( ) . span_to_snippet ( span) . ok ( ) ?;
212
+ Some ( span. from_inner ( InnerSpan {
213
+ start : snippet. find ( & [ '(' , '{' , '[' ] [ ..] ) ? + 1 ,
214
+ end : snippet. rfind ( & [ ')' , '}' , ']' ] [ ..] ) ?,
215
+ } ) )
216
+ }
217
+
189
218
fn panic_call < ' tcx > ( cx : & LateContext < ' tcx > , f : & ' tcx hir:: Expr < ' tcx > ) -> ( Span , Symbol ) {
190
219
let mut expn = f. span . ctxt ( ) . outer_expn_data ( ) ;
191
220
0 commit comments