@@ -2,8 +2,9 @@ use rustc::hir::*;
2
2
use rustc:: lint:: * ;
3
3
use rustc:: ty;
4
4
use syntax:: ast:: LitKind ;
5
+ use syntax_pos:: Span ;
5
6
use utils:: paths;
6
- use utils:: { in_macro, is_expn_of, match_def_path, match_type, opt_def_id, resolve_node, snippet, span_lint_and_then, walk_ptrs_ty} ;
7
+ use 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} ;
7
8
8
9
/// **What it does:** Checks for the use of `format!("string literal with no
9
10
/// argument")` and `format!("{}", foo)` where `foo` is a string.
@@ -43,20 +44,19 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
43
44
return ;
44
45
}
45
46
match expr. node {
47
+
46
48
// `format!("{}", foo)` expansion
47
49
ExprCall ( ref fun, ref args) => {
48
50
if_chain ! {
49
51
if let ExprPath ( ref qpath) = fun. node;
50
- if args. len( ) == 2 ;
52
+ if args. len( ) == 3 ;
51
53
if let Some ( fun_def_id) = opt_def_id( resolve_node( cx, qpath, fun. hir_id) ) ;
52
- if match_def_path( cx. tcx, fun_def_id, & paths:: FMT_ARGUMENTS_NEWV1 ) ;
53
- // ensure the format string is `"{..}"` with only one argument and no text
54
- if check_static_str( & args[ 0 ] ) ;
55
- // ensure the format argument is `{}` ie. Display with no fancy option
56
- // and that the argument is a string
57
- if check_arg_is_display( cx, & args[ 1 ] ) ;
54
+ if match_def_path( cx. tcx, fun_def_id, & paths:: FMT_ARGUMENTS_NEWV1FORMATTED ) ;
55
+ if check_single_piece( & args[ 0 ] ) ;
56
+ if let Some ( format_arg) = get_single_string_arg( cx, & args[ 1 ] ) ;
57
+ if check_unformatted( & args[ 2 ] ) ;
58
58
then {
59
- let sugg = format!( "{}.to_string()" , snippet( cx, expr . span , "<expr >" ) . into_owned( ) ) ;
59
+ let sugg = format!( "{}.to_string()" , snippet( cx, format_arg , "<arg >" ) . into_owned( ) ) ;
60
60
span_lint_and_then( cx, USELESS_FORMAT , span, "useless use of `format!`" , |db| {
61
61
db. span_suggestion( expr. span, "consider using .to_string()" , sugg) ;
62
62
} ) ;
@@ -79,7 +79,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
79
79
}
80
80
81
81
/// Checks if the expressions matches `&[""]`
82
- fn check_static_str ( expr : & Expr ) -> bool {
82
+ fn check_single_piece ( expr : & Expr ) -> bool {
83
83
if_chain ! {
84
84
if let ExprAddrOf ( _, ref expr) = expr. node; // &[""]
85
85
if let ExprArray ( ref exprs) = expr. node; // [""]
@@ -96,15 +96,17 @@ fn check_static_str(expr: &Expr) -> bool {
96
96
97
97
/// Checks if the expressions matches
98
98
/// ```rust,ignore
99
- /// &match (&42 ,) {
99
+ /// &match (&"arg" ,) {
100
100
/// (__arg0,) => [::std::fmt::ArgumentV1::new(__arg0,
101
101
/// ::std::fmt::Display::fmt)],
102
102
/// }
103
103
/// ```
104
- fn check_arg_is_display ( cx : & LateContext , expr : & Expr ) -> bool {
104
+ /// and that type of `__arg0` is `&str` or `String`
105
+ /// then returns the span of first element of the matched tuple
106
+ fn get_single_string_arg ( cx : & LateContext , expr : & Expr ) -> Option < Span > {
105
107
if_chain ! {
106
108
if let ExprAddrOf ( _, ref expr) = expr. node;
107
- if let ExprMatch ( _ , ref arms, _) = expr. node;
109
+ if let ExprMatch ( ref match_expr , ref arms, _) = expr. node;
108
110
if arms. len( ) == 1 ;
109
111
if arms[ 0 ] . pats. len( ) == 1 ;
110
112
if let PatKind :: Tuple ( ref pat, None ) = arms[ 0 ] . pats[ 0 ] . node;
@@ -118,8 +120,40 @@ fn check_arg_is_display(cx: &LateContext, expr: &Expr) -> bool {
118
120
if match_def_path( cx. tcx, fun_def_id, & paths:: DISPLAY_FMT_METHOD ) ;
119
121
then {
120
122
let ty = walk_ptrs_ty( cx. tables. pat_ty( & pat[ 0 ] ) ) ;
123
+ if ty. sty == ty:: TyStr || match_type( cx, ty, & paths:: STRING ) {
124
+ if let ExprTup ( ref values) = match_expr. node {
125
+ return Some ( values[ 0 ] . span) ;
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ None
132
+ }
121
133
122
- return ty. sty == ty:: TyStr || match_type( cx, ty, & paths:: STRING ) ;
134
+ /// Checks if the expression matches
135
+ /// ```rust,ignore
136
+ /// &[_ {
137
+ /// format: _ {
138
+ /// width: _::Implied,
139
+ /// ...
140
+ /// },
141
+ /// ...,
142
+ /// }]
143
+ /// ```
144
+ fn check_unformatted ( expr : & Expr ) -> bool {
145
+ if_chain ! {
146
+ if let ExprAddrOf ( _, ref expr) = expr. node;
147
+ if let ExprArray ( ref exprs) = expr. node;
148
+ if exprs. len( ) == 1 ;
149
+ if let ExprStruct ( _, ref fields, _) = exprs[ 0 ] . node;
150
+ if let Some ( format_field) = fields. iter( ) . find( |f| f. name. node == "format" ) ;
151
+ if let ExprStruct ( _, ref fields, _) = format_field. expr. node;
152
+ if let Some ( align_field) = fields. iter( ) . find( |f| f. name. node == "width" ) ;
153
+ if let ExprPath ( ref qpath) = align_field. expr. node;
154
+ if last_path_segment( qpath) . name == "Implied" ;
155
+ then {
156
+ return true ;
123
157
}
124
158
}
125
159
0 commit comments