@@ -4,7 +4,6 @@ use crate::rustc::{declare_tool_lint, lint_array};
44use if_chain:: if_chain;
55use crate :: rustc:: ty;
66use crate :: syntax:: ast:: LitKind ;
7- use crate :: syntax_pos:: Span ;
87use crate :: utils:: paths;
98use crate :: utils:: { in_macro, is_expn_of, last_path_segment, match_def_path, match_type, opt_def_id, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty} ;
109use crate :: rustc_errors:: Applicability ;
@@ -47,7 +46,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
4746 return ;
4847 }
4948 match expr. node {
50-
5149 // `format!("{}", foo)` expansion
5250 ExprKind :: Call ( ref fun, ref args) => {
5351 if_chain ! {
@@ -58,12 +56,24 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
5856 if check_single_piece( & args[ 0 ] ) ;
5957 if let Some ( format_arg) = get_single_string_arg( cx, & args[ 1 ] ) ;
6058 if check_unformatted( & args[ 2 ] ) ;
59+ if let ExprKind :: AddrOf ( _, ref format_arg) = format_arg. node;
6160 then {
62- let sugg = format!( "{}.to_string()" , snippet( cx, format_arg, "<arg>" ) . into_owned( ) ) ;
61+ let ( message, sugg) = if_chain! {
62+ if let ExprKind :: MethodCall ( ref path, _, _) = format_arg. node;
63+ if path. ident. as_interned_str( ) == "to_string" ;
64+ then {
65+ ( "`to_string()` is enough" ,
66+ snippet( cx, format_arg. span, "<arg>" ) . to_string( ) )
67+ } else {
68+ ( "consider using .to_string()" ,
69+ format!( "{}.to_string()" , snippet( cx, format_arg. span, "<arg>" ) ) )
70+ }
71+ } ;
72+
6373 span_lint_and_then( cx, USELESS_FORMAT , span, "useless use of `format!`" , |db| {
6474 db. span_suggestion_with_applicability(
6575 expr. span,
66- "consider using .to_string()" ,
76+ message ,
6777 sugg,
6878 Applicability :: MachineApplicable ,
6979 ) ;
@@ -114,9 +124,9 @@ fn check_single_piece(expr: &Expr) -> bool {
114124/// ::std::fmt::Display::fmt)],
115125/// }
116126/// ```
117- /// and that type of `__arg0` is `&str` or `String`
118- /// then returns the span of first element of the matched tuple
119- fn get_single_string_arg ( cx : & LateContext < ' _ , ' _ > , expr : & Expr ) -> Option < Span > {
127+ /// and that the type of `__arg0` is `&str` or `String`,
128+ /// then returns the span of first element of the matched tuple.
129+ fn get_single_string_arg < ' a > ( cx : & LateContext < ' _ , ' _ > , expr : & ' a Expr ) -> Option < & ' a Expr > {
120130 if_chain ! {
121131 if let ExprKind :: AddrOf ( _, ref expr) = expr. node;
122132 if let ExprKind :: Match ( ref match_expr, ref arms, _) = expr. node;
@@ -135,7 +145,7 @@ fn get_single_string_arg(cx: &LateContext<'_, '_>, expr: &Expr) -> Option<Span>
135145 let ty = walk_ptrs_ty( cx. tables. pat_ty( & pat[ 0 ] ) ) ;
136146 if ty. sty == ty:: Str || match_type( cx, ty, & paths:: STRING ) {
137147 if let ExprKind :: Tup ( ref values) = match_expr. node {
138- return Some ( values[ 0 ] . span ) ;
148+ return Some ( & values[ 0 ] ) ;
139149 }
140150 }
141151 }
@@ -162,9 +172,12 @@ fn check_unformatted(expr: &Expr) -> bool {
162172 if let ExprKind :: Struct ( _, ref fields, _) = exprs[ 0 ] . node;
163173 if let Some ( format_field) = fields. iter( ) . find( |f| f. ident. name == "format" ) ;
164174 if let ExprKind :: Struct ( _, ref fields, _) = format_field. expr. node;
165- if let Some ( align_field) = fields. iter( ) . find( |f| f. ident. name == "width" ) ;
166- if let ExprKind :: Path ( ref qpath) = align_field. expr. node;
167- if last_path_segment( qpath) . ident. name == "Implied" ;
175+ if let Some ( width_field) = fields. iter( ) . find( |f| f. ident. name == "width" ) ;
176+ if let ExprKind :: Path ( ref width_qpath) = width_field. expr. node;
177+ if last_path_segment( width_qpath) . ident. name == "Implied" ;
178+ if let Some ( precision_field) = fields. iter( ) . find( |f| f. ident. name == "precision" ) ;
179+ if let ExprKind :: Path ( ref precision_path) = precision_field. expr. node;
180+ if last_path_segment( precision_path) . ident. name == "Implied" ;
168181 then {
169182 return true ;
170183 }
0 commit comments