@@ -4,7 +4,8 @@ use clippy_utils::source::snippet_with_applicability;
4
4
use clippy_utils:: { is_expn_of, match_function_call, paths} ;
5
5
use if_chain:: if_chain;
6
6
use rustc_errors:: Applicability ;
7
- use rustc_hir:: { Expr , ExprKind } ;
7
+ use rustc_hir:: def:: Res ;
8
+ use rustc_hir:: { BindingAnnotation , Block , BlockCheckMode , Expr , ExprKind , Node , PatKind , QPath , Stmt , StmtKind } ;
8
9
use rustc_lint:: { LateContext , LateLintPass } ;
9
10
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
10
11
use rustc_span:: sym;
@@ -47,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
47
48
if let ExprKind :: MethodCall ( unwrap_fun, [ write_call] , _) = expr. kind;
48
49
if unwrap_fun. ident. name == sym:: unwrap;
49
50
// match call to write_fmt
50
- if let ExprKind :: MethodCall ( write_fun, [ write_recv, write_arg] , _) = write_call. kind;
51
+ if let ExprKind :: MethodCall ( write_fun, [ write_recv, write_arg] , _) = look_in_block ( cx , & write_call. kind) ;
51
52
if write_fun. ident. name == sym!( write_fmt) ;
52
53
// match calls to std::io::stdout() / std::io::stderr ()
53
54
if let Some ( dest_name) = if match_function_call( cx, write_recv, & paths:: STDOUT ) . is_some( ) {
@@ -108,3 +109,34 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
108
109
}
109
110
}
110
111
}
112
+
113
+ /// If `kind` is a block that looks like `{ let result = $expr; result }` then
114
+ /// returns $expr. Otherwise returns `kind`.
115
+ fn look_in_block < ' tcx , ' hir > ( cx : & LateContext < ' tcx > , kind : & ' tcx ExprKind < ' hir > ) -> & ' tcx ExprKind < ' hir > {
116
+ if_chain ! {
117
+ if let ExprKind :: Block ( block, _label @ None ) = kind;
118
+ if let Block {
119
+ stmts: [ Stmt { kind: StmtKind :: Local ( local) , .. } ] ,
120
+ expr: Some ( expr_end_of_block) ,
121
+ rules: BlockCheckMode :: DefaultBlock ,
122
+ ..
123
+ } = block;
124
+
125
+ // Find id of the local that expr_end_of_block resolves to
126
+ if let ExprKind :: Path ( QPath :: Resolved ( None , expr_path) ) = expr_end_of_block. kind;
127
+ if let Res :: Local ( expr_res) = expr_path. res;
128
+ if let Some ( Node :: Binding ( res_pat) ) = cx. tcx. hir( ) . find( expr_res) ;
129
+
130
+ // Find id of the local we found in the block
131
+ if let PatKind :: Binding ( BindingAnnotation :: Unannotated , local_hir_id, _ident, None ) = local. pat. kind;
132
+
133
+ // If those two are the same hir id
134
+ if res_pat. hir_id == local_hir_id;
135
+
136
+ if let Some ( init) = local. init;
137
+ then {
138
+ return & init. kind;
139
+ }
140
+ }
141
+ kind
142
+ }
0 commit comments