@@ -2,7 +2,7 @@ use rustc::hir::*;
22use rustc:: hir:: map:: Node :: { NodeItem , NodeImplItem } ;
33use rustc:: lint:: * ;
44use 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} ;
66use format:: get_argument_fmtstr_parts;
77
88/// **What it does:** This lint warns when you using `print!()` with a format string that
@@ -67,63 +67,69 @@ impl LintPass for Pass {
6767
6868impl LateLintPass for Pass {
6969 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( ) ;
8176
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+ } ;
8386
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) ) ;
8788
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" ,
9792
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,
102103
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+ } }
114119 }
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" ) ;
123129 }
124130 }
125131 }
126- }
132+ } }
127133 }
128134}
129135
0 commit comments