@@ -2,7 +2,7 @@ use rustc::hir::*;
2
2
use rustc:: hir:: map:: Node :: { NodeItem , NodeImplItem } ;
3
3
use rustc:: lint:: * ;
4
4
use utils:: paths;
5
- use utils:: { is_expn_of, match_path, span_lint} ;
5
+ use utils:: { is_expn_of, match_path, match_def_path , resolve_node , span_lint} ;
6
6
use format:: get_argument_fmtstr_parts;
7
7
8
8
/// **What it does:** This lint warns when you using `print!()` with a format string that
@@ -67,63 +67,69 @@ impl LintPass for Pass {
67
67
68
68
impl LateLintPass for Pass {
69
69
fn check_expr ( & mut self , cx : & LateContext , expr : & Expr ) {
70
- if let ExprCall ( ref fun, ref args) = expr. node {
71
- if let ExprPath ( _, ref path) = fun. node {
72
- // Search for `std::io::_print(..)` which is unique in a
73
- // `print!` expansion.
74
- if match_path ( path, & paths:: IO_PRINT ) {
75
- if let Some ( span) = is_expn_of ( cx, expr. span , "print" ) {
76
- // `println!` uses `print!`.
77
- let ( span, name) = match is_expn_of ( cx, span, "println" ) {
78
- Some ( span) => ( span, "println" ) ,
79
- None => ( span, "print" ) ,
80
- } ;
70
+ if_let_chain ! { [
71
+ let ExprCall ( ref fun, ref args) = expr. node,
72
+ let ExprPath ( ..) = fun. node,
73
+ let Some ( fun) = resolve_node( cx, fun. id) ,
74
+ ] , {
75
+ let fun_id = fun. def_id( ) ;
81
76
82
- span_lint ( cx, PRINT_STDOUT , span, & format ! ( "use of `{}!`" , name) ) ;
77
+ // Search for `std::io::_print(..)` which is unique in a
78
+ // `print!` expansion.
79
+ if match_def_path( cx, fun_id, & paths:: IO_PRINT ) {
80
+ if let Some ( span) = is_expn_of( cx, expr. span, "print" ) {
81
+ // `println!` uses `print!`.
82
+ let ( span, name) = match is_expn_of( cx, span, "println" ) {
83
+ Some ( span) => ( span, "println" ) ,
84
+ None => ( span, "print" ) ,
85
+ } ;
83
86
84
- // Check print! with format string ending in "\n".
85
- if_let_chain ! { [
86
- name == "print" ,
87
+ span_lint( cx, PRINT_STDOUT , span, & format!( "use of `{}!`" , name) ) ;
87
88
88
- // ensure we're calling Arguments::new_v1
89
- args. len( ) == 1 ,
90
- let ExprCall ( ref args_fun, ref args_args) = args[ 0 ] . node,
91
- let ExprPath ( _, ref args_path) = args_fun. node,
92
- match_path( args_path, & paths:: FMT_ARGUMENTS_NEWV1 ) ,
93
- args_args. len( ) == 2 ,
94
- let ExprAddrOf ( _, ref match_expr) = args_args[ 1 ] . node,
95
- let ExprMatch ( ref args, _, _) = match_expr. node,
96
- let ExprTup ( ref args) = args. node,
89
+ // Check print! with format string ending in "\n".
90
+ if_let_chain!{ [
91
+ name == "print" ,
97
92
98
- // collect the format string parts and check the last one
99
- let Some ( fmtstrs) = get_argument_fmtstr_parts( cx, & args_args[ 0 ] ) ,
100
- let Some ( last_str) = fmtstrs. last( ) ,
101
- let Some ( '\n' ) = last_str. chars( ) . last( ) ,
93
+ // ensure we're calling Arguments::new_v1
94
+ args. len( ) == 1 ,
95
+ let ExprCall ( ref args_fun, ref args_args) = args[ 0 ] . node,
96
+ let ExprPath ( ..) = args_fun. node,
97
+ let Some ( def) = resolve_node( cx, args_fun. id) ,
98
+ match_def_path( cx, def. def_id( ) , & paths:: FMT_ARGUMENTS_NEWV1 ) ,
99
+ args_args. len( ) == 2 ,
100
+ let ExprAddrOf ( _, ref match_expr) = args_args[ 1 ] . node,
101
+ let ExprMatch ( ref args, _, _) = match_expr. node,
102
+ let ExprTup ( ref args) = args. node,
102
103
103
- // "foo{}bar" is made into two strings + one argument,
104
- // if the format string starts with `{}` (eg. "{}foo"),
105
- // the string array is prepended an empty string "".
106
- // We only want to check the last string after any `{}`:
107
- args. len( ) < fmtstrs. len( ) ,
108
- ] , {
109
- span_lint( cx, PRINT_WITH_NEWLINE , span,
110
- "using `print!()` with a format string that ends in a \
111
- newline, consider using `println!()` instead") ;
112
- } }
113
- }
104
+ // collect the format string parts and check the last one
105
+ let Some ( fmtstrs) = get_argument_fmtstr_parts( cx, & args_args[ 0 ] ) ,
106
+ let Some ( last_str) = fmtstrs. last( ) ,
107
+ let Some ( '\n' ) = last_str. chars( ) . last( ) ,
108
+
109
+ // "foo{}bar" is made into two strings + one argument,
110
+ // if the format string starts with `{}` (eg. "{}foo"),
111
+ // the string array is prepended an empty string "".
112
+ // We only want to check the last string after any `{}`:
113
+ args. len( ) < fmtstrs. len( ) ,
114
+ ] , {
115
+ span_lint( cx, PRINT_WITH_NEWLINE , span,
116
+ "using `print!()` with a format string that ends in a \
117
+ newline, consider using `println!()` instead") ;
118
+ } }
114
119
}
115
- // Search for something like
116
- // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
117
- else if args. len ( ) == 2 && match_path ( path, & paths:: FMT_ARGUMENTV1_NEW ) {
118
- if let ExprPath ( None , ref path) = args[ 1 ] . node {
119
- if match_path ( path, & paths:: DEBUG_FMT_METHOD ) && !is_in_debug_impl ( cx, expr) &&
120
- is_expn_of ( cx, expr. span , "panic" ) . is_none ( ) {
121
- span_lint ( cx, USE_DEBUG , args[ 0 ] . span , "use of `Debug`-based formatting" ) ;
122
- }
120
+ }
121
+ // Search for something like
122
+ // `::std::fmt::ArgumentV1::new(__arg0, ::std::fmt::Debug::fmt)`
123
+ else if args. len( ) == 2 && match_def_path( cx, fun_id, & paths:: FMT_ARGUMENTV1_NEW ) {
124
+ if let ExprPath ( None , _) = args[ 1 ] . node {
125
+ let def_id = resolve_node( cx, args[ 1 ] . id) . unwrap( ) . def_id( ) ;
126
+ if match_def_path( cx, def_id, & paths:: DEBUG_FMT_METHOD ) && !is_in_debug_impl( cx, expr) &&
127
+ is_expn_of( cx, expr. span, "panic" ) . is_none( ) {
128
+ span_lint( cx, USE_DEBUG , args[ 0 ] . span, "use of `Debug`-based formatting" ) ;
123
129
}
124
130
}
125
131
}
126
- }
132
+ } }
127
133
}
128
134
}
129
135
0 commit comments