@@ -4,7 +4,8 @@ use clippy_utils::source::snippet_with_applicability;
44use clippy_utils:: { is_expn_of, match_function_call, paths} ;
55use if_chain:: if_chain;
66use 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 } ;
89use rustc_lint:: { LateContext , LateLintPass } ;
910use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
1011use rustc_span:: sym;
@@ -47,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
4748 if let ExprKind :: MethodCall ( unwrap_fun, [ write_call] , _) = expr. kind;
4849 if unwrap_fun. ident. name == sym:: unwrap;
4950 // 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) ;
5152 if write_fun. ident. name == sym!( write_fmt) ;
5253 // match calls to std::io::stdout() / std::io::stderr ()
5354 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 {
108109 }
109110 }
110111}
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