@@ -72,18 +72,38 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
7272 // Find the span of the argument to `panic!()`, before expansion in the
7373 // case of `panic!(some_macro!())`.
7474 let mut arg_span = arg. span ;
75+ let mut arg_macro = None ;
7576 while !span. contains ( arg_span) {
7677 let expn = arg_span. ctxt ( ) . outer_expn_data ( ) ;
7778 if expn. is_root ( ) {
7879 break ;
7980 }
81+ arg_macro = expn. macro_def_id ;
8082 arg_span = expn. call_site ;
8183 }
8284
8385 cx. struct_span_lint ( NON_FMT_PANIC , arg_span, |lint| {
8486 let mut l = lint. build ( "panic message is not a string literal" ) ;
8587 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 {
87107 l. span_suggestion_verbose (
88108 arg_span. shrink_to_lo ( ) ,
89109 "add a \" {}\" format string to Display the message" ,
@@ -186,6 +206,15 @@ fn check_panic_str<'tcx>(
186206 }
187207}
188208
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+
189218fn panic_call < ' tcx > ( cx : & LateContext < ' tcx > , f : & ' tcx hir:: Expr < ' tcx > ) -> ( Span , Symbol ) {
190219 let mut expn = f. span . ctxt ( ) . outer_expn_data ( ) ;
191220
0 commit comments