@@ -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;
@@ -39,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
39
40
if let ExprKind :: MethodCall ( unwrap_fun, [ write_call] , _) = expr. kind;
40
41
if unwrap_fun. ident. name == sym:: unwrap;
41
42
// match call to write_fmt
42
- if let ExprKind :: MethodCall ( write_fun, [ write_recv, write_arg] , _) = write_call. kind;
43
+ if let ExprKind :: MethodCall ( write_fun, [ write_recv, write_arg] , _) = look_in_block ( cx , & write_call. kind) ;
43
44
if write_fun. ident. name == sym!( write_fmt) ;
44
45
// match calls to std::io::stdout() / std::io::stderr ()
45
46
if let Some ( dest_name) = if match_function_call( cx, write_recv, & paths:: STDOUT ) . is_some( ) {
@@ -100,3 +101,34 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
100
101
}
101
102
}
102
103
}
104
+
105
+ /// If `kind` is a block that looks like `{ let result = $expr; result }` then
106
+ /// returns $expr. Otherwise returns `kind`.
107
+ fn look_in_block < ' tcx , ' hir > ( cx : & LateContext < ' tcx > , kind : & ' tcx ExprKind < ' hir > ) -> & ' tcx ExprKind < ' hir > {
108
+ if_chain ! {
109
+ if let ExprKind :: Block ( block, _label @ None ) = kind;
110
+ if let Block {
111
+ stmts: [ Stmt { kind: StmtKind :: Local ( local) , .. } ] ,
112
+ expr: Some ( expr_end_of_block) ,
113
+ rules: BlockCheckMode :: DefaultBlock ,
114
+ ..
115
+ } = block;
116
+
117
+ // Find id of the local that expr_end_of_block resolves to
118
+ if let ExprKind :: Path ( QPath :: Resolved ( None , expr_path) ) = expr_end_of_block. kind;
119
+ if let Res :: Local ( expr_res) = expr_path. res;
120
+ if let Some ( Node :: Binding ( res_pat) ) = cx. tcx. hir( ) . find( expr_res) ;
121
+
122
+ // Find id of the local we found in the block
123
+ if let PatKind :: Binding ( BindingAnnotation :: Unannotated , local_hir_id, _ident, None ) = local. pat. kind;
124
+
125
+ // If those two are the same hir id
126
+ if res_pat. hir_id == local_hir_id;
127
+
128
+ if let Some ( init) = local. init;
129
+ then {
130
+ return & init. kind;
131
+ }
132
+ }
133
+ kind
134
+ }
0 commit comments