@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
2
2
use clippy_utils:: higher:: { FormatArgsArg , FormatArgsExpn , FormatExpn } ;
3
3
use clippy_utils:: source:: snippet_opt;
4
4
use clippy_utils:: ty:: implements_trait;
5
- use clippy_utils:: { get_trait_def_id , is_diag_trait_item, match_def_path, paths} ;
5
+ use clippy_utils:: { is_diag_trait_item, match_def_path, paths} ;
6
6
use if_chain:: if_chain;
7
7
use rustc_errors:: Applicability ;
8
8
use rustc_hir:: { Expr , ExprKind } ;
@@ -64,18 +64,18 @@ declare_clippy_lint! {
64
64
declare_lint_pass ! ( FormatArgs => [ FORMAT_IN_FORMAT_ARGS , TO_STRING_IN_FORMAT_ARGS ] ) ;
65
65
66
66
const FORMAT_MACROS : & [ & [ & str ] ] = & [
67
- & [ "alloc" , "macros" , "format" ] ,
68
- & [ "core" , "macros" , "assert_eq" ] ,
69
- & [ "core" , "macros" , "assert_ne" ] ,
70
- & [ "core" , "macros" , "write" ] ,
71
- & [ "core" , "macros" , "writeln" ] ,
72
- & [ "core" , "macros" , "builtin" , "assert" ] ,
73
- & [ "core" , "macros" , "builtin" , "format_args" ] ,
74
- & [ "std" , "macros" , "eprint" ] ,
75
- & [ "std" , "macros" , "eprintln" ] ,
76
- & [ "std" , "macros" , "panic" ] ,
77
- & [ "std" , "macros" , "print" ] ,
78
- & [ "std" , "macros" , "println" ] ,
67
+ & paths :: FORMAT_MACRO ,
68
+ & paths :: FORMAT_ARGS_MACRO ,
69
+ & paths :: ASSERT_EQ_MACRO ,
70
+ & paths :: ASSERT_MACRO ,
71
+ & paths :: ASSERT_NE_MACRO ,
72
+ & paths :: EPRINT_MACRO ,
73
+ & paths :: EPRINTLN_MACRO ,
74
+ & paths :: PANIC_MACRO ,
75
+ & paths :: PRINT_MACRO ,
76
+ & paths :: PRINTLN_MACRO ,
77
+ & paths :: WRITE_MACRO ,
78
+ & paths :: WRITELN_MACRO ,
79
79
] ;
80
80
81
81
impl < ' tcx > LateLintPass < ' tcx > for FormatArgs {
@@ -116,49 +116,50 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
116
116
}
117
117
118
118
fn check_format_in_format_args ( cx : & LateContext < ' _ > , call_site : Span , name : Symbol , arg : & FormatArgsArg < ' _ > ) {
119
- if FormatExpn :: parse ( arg. value ) . is_some ( ) {
120
- span_lint_and_then (
121
- cx,
122
- FORMAT_IN_FORMAT_ARGS ,
123
- trim_semicolon ( cx, call_site) ,
124
- & format ! ( "`format!` in `{}!` args" , name) ,
125
- |diag| {
126
- diag. help ( & format ! (
127
- "combine the `format!(..)` arguments with the outer `{}!(..)` call" ,
128
- name
129
- ) ) ;
130
- diag. help ( "or consider changing `format!` to `format_args!`" ) ;
131
- } ,
132
- ) ;
119
+ if_chain ! {
120
+ if FormatExpn :: parse( arg. value) . is_some( ) ;
121
+ if !arg. value. span. ctxt( ) . outer_expn_data( ) . call_site. from_expansion( ) ;
122
+ then {
123
+ span_lint_and_then(
124
+ cx,
125
+ FORMAT_IN_FORMAT_ARGS ,
126
+ trim_semicolon( cx, call_site) ,
127
+ & format!( "`format!` in `{}!` args" , name) ,
128
+ |diag| {
129
+ diag. help( & format!(
130
+ "combine the `format!(..)` arguments with the outer `{}!(..)` call" ,
131
+ name
132
+ ) ) ;
133
+ diag. help( "or consider changing `format!` to `format_args!`" ) ;
134
+ } ,
135
+ ) ;
136
+ }
133
137
}
134
138
}
135
139
136
140
fn check_to_string_in_format_args < ' tcx > ( cx : & LateContext < ' tcx > , name : Symbol , arg : & FormatArgsArg < ' tcx > ) {
137
141
let value = arg. value ;
138
142
if_chain ! {
143
+ if !value. span. from_expansion( ) ;
139
144
if let ExprKind :: MethodCall ( _, _, [ receiver] , _) = value. kind;
140
145
if let Some ( method_def_id) = cx. typeck_results( ) . type_dependent_def_id( value. hir_id) ;
141
146
if is_diag_trait_item( cx, method_def_id, sym:: ToString ) ;
142
147
let receiver_ty = cx. typeck_results( ) . expr_ty( receiver) ;
143
148
if let Some ( display_trait_id) = cx. tcx. get_diagnostic_item( sym:: Display ) ;
144
- if let Some ( value_snippet) = snippet_opt( cx, value. span) ;
145
- if let Some ( dot) = value_snippet. rfind( '.' ) ;
146
149
if let Some ( receiver_snippet) = snippet_opt( cx, receiver. span) ;
147
150
then {
148
- let ( n_derefs, target) = count_derefs(
151
+ let ( n_overloaded_derefs, target) = count_overloaded_derefs(
152
+ 0 ,
149
153
0 ,
150
154
receiver_ty,
151
155
& mut cx. typeck_results( ) . expr_adjustments( receiver) . iter( ) ,
152
156
) ;
153
157
if implements_trait( cx, target, display_trait_id, & [ ] ) {
154
- if n_derefs == 0 {
155
- let span = value. span. with_lo(
156
- value. span. lo( ) + BytePos ( u32 :: try_from( dot) . unwrap( ) )
157
- ) ;
158
+ if n_overloaded_derefs == 0 {
158
159
span_lint_and_sugg(
159
160
cx,
160
161
TO_STRING_IN_FORMAT_ARGS ,
161
- span,
162
+ value . span. with_lo ( receiver . span . hi ( ) ) ,
162
163
& format!( "`to_string` applied to a type that implements `Display` in `{}!` args" , name) ,
163
164
"remove this" ,
164
165
String :: new( ) ,
@@ -171,7 +172,7 @@ fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, ar
171
172
value. span,
172
173
& format!( "`to_string` applied to a type that implements `Display` in `{}!` args" , name) ,
173
174
"use this" ,
174
- format!( "{:*>width$}{}" , "" , receiver_snippet, width = n_derefs ) ,
175
+ format!( "{:*>width$}{}" , "" , receiver_snippet, width = n_overloaded_derefs ) ,
175
176
Applicability :: MachineApplicable ,
176
177
) ;
177
178
}
@@ -195,17 +196,31 @@ fn trim_semicolon(cx: &LateContext<'_>, span: Span) -> Span {
195
196
} )
196
197
}
197
198
198
- fn count_derefs < ' tcx , I > ( n : usize , ty : Ty < ' tcx > , iter : & mut I ) -> ( usize , Ty < ' tcx > )
199
+ fn count_overloaded_derefs < ' tcx , I > (
200
+ n_total : usize ,
201
+ n_overloaded : usize ,
202
+ ty : Ty < ' tcx > ,
203
+ iter : & mut I ,
204
+ ) -> ( usize , Ty < ' tcx > )
199
205
where
200
206
I : Iterator < Item = & ' tcx Adjustment < ' tcx > > ,
201
207
{
202
208
if let Some ( Adjustment {
203
- kind : Adjust :: Deref ( Some ( _ ) ) ,
209
+ kind : Adjust :: Deref ( overloaded_deref ) ,
204
210
target,
205
211
} ) = iter. next ( )
206
212
{
207
- count_derefs ( n + 1 , target, iter)
213
+ count_overloaded_derefs (
214
+ n_total + 1 ,
215
+ if overloaded_deref. is_some ( ) {
216
+ n_total + 1
217
+ } else {
218
+ n_overloaded
219
+ } ,
220
+ target,
221
+ iter,
222
+ )
208
223
} else {
209
- ( n , ty)
224
+ ( n_overloaded , ty)
210
225
}
211
226
}
0 commit comments