@@ -4,10 +4,11 @@ use clippy_utils::source::{snippet, snippet_indent};
44use rustc_ast:: LitKind ;
55use rustc_data_structures:: packed:: Pu128 ;
66use rustc_errors:: Applicability ;
7- use rustc_hir:: { ConstArgKind , ExprKind , Node } ;
7+ use rustc_hir:: { ConstArgKind , Expr , ExprKind , LetStmt , LocalSource , Node } ;
88use rustc_lint:: { LateContext , LateLintPass } ;
9- use rustc_middle:: ty:: IsSuggestable ;
9+ use rustc_middle:: ty:: { IsSuggestable , Ty } ;
1010use rustc_session:: declare_lint_pass;
11+ use rustc_span:: Span ;
1112
1213declare_clippy_lint ! {
1314 /// ### What it does
@@ -44,7 +45,7 @@ declare_clippy_lint! {
4445declare_lint_pass ! ( ZeroRepeatSideEffects => [ ZERO_REPEAT_SIDE_EFFECTS ] ) ;
4546
4647impl LateLintPass < ' _ > for ZeroRepeatSideEffects {
47- fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & rustc_hir :: Expr < ' _ > ) {
48+ fn check_expr ( & mut self , cx : & LateContext < ' _ > , expr : & Expr < ' _ > ) {
4849 if let Some ( args) = VecArgs :: hir ( cx, expr)
4950 && let VecArgs :: Repeat ( inner_expr, len) = args
5051 && let ExprKind :: Lit ( l) = len. kind
@@ -69,7 +70,7 @@ impl LateLintPass<'_> for ZeroRepeatSideEffects {
6970 }
7071}
7172
72- fn inner_check ( cx : & LateContext < ' _ > , expr : & ' _ rustc_hir :: Expr < ' _ > , inner_expr : & ' _ rustc_hir :: Expr < ' _ > , is_vec : bool ) {
73+ fn inner_check ( cx : & LateContext < ' _ > , expr : & ' _ Expr < ' _ > , inner_expr : & ' _ Expr < ' _ > , is_vec : bool ) {
7374 // check if expr is a call or has a call inside it
7475 if inner_expr. can_have_side_effects ( ) {
7576 let parent_hir_node = cx. tcx . parent_hir_node ( expr. hir_id ) ;
@@ -81,19 +82,22 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr:
8182 let vec = if is_vec { "vec!" } else { "" } ;
8283
8384 let ( span, sugg) = match parent_hir_node {
84- Node :: LetStmt ( l) => (
85- l. span ,
86- format ! (
87- "{inner_expr};\n {indent}let {var_name}: {return_type} = {vec}[];" ,
88- var_name = snippet( cx, l. pat. span. source_callsite( ) , ".." )
89- ) ,
90- ) ,
85+ Node :: LetStmt ( l)
86+ if matches ! ( l. source, LocalSource :: AssignDesugar ( _) )
87+ && let mut parent_iter = cx. tcx . hir_parent_iter ( l. hir_id )
88+ && let Some ( ( _, Node :: Stmt ( _) ) ) = parent_iter. next ( )
89+ && let Some ( ( _, Node :: Block ( _) ) ) = parent_iter. next ( )
90+ && let Some ( ( _, Node :: Expr ( x) ) ) = parent_iter. next ( ) =>
91+ {
92+ (
93+ x. span ,
94+ assign_expr_suggestion ( cx, x, l. pat . span , & inner_expr, return_type, vec) ,
95+ )
96+ } ,
97+ Node :: LetStmt ( l) => ( l. span , let_stmt_suggestion ( cx, l, & inner_expr, return_type, vec) ) ,
9198 Node :: Expr ( x) if let ExprKind :: Assign ( l, _, _) = x. kind => (
9299 x. span ,
93- format ! (
94- "{inner_expr};\n {indent}{var_name} = {vec}[] as {return_type}" ,
95- var_name = snippet( cx, l. span. source_callsite( ) , ".." )
96- ) ,
100+ assign_expr_suggestion ( cx, x, l. span , & inner_expr, return_type, vec) ,
97101 ) ,
98102 // NOTE: don't use the stmt span to avoid touching the trailing semicolon
99103 Node :: Stmt ( _) => ( expr. span , format ! ( "{inner_expr};\n {indent}{vec}[] as {return_type}" ) ) ,
@@ -131,3 +135,41 @@ fn inner_check(cx: &LateContext<'_>, expr: &'_ rustc_hir::Expr<'_>, inner_expr:
131135 ) ;
132136 }
133137}
138+
139+ fn let_stmt_suggestion (
140+ cx : & LateContext < ' _ > ,
141+ let_stmt : & LetStmt < ' _ > ,
142+ inner_expr : & str ,
143+ return_type : Ty < ' _ > ,
144+ vec_str : & str ,
145+ ) -> String {
146+ let indent = snippet_indent ( cx, let_stmt. span ) . unwrap_or_default ( ) ;
147+ format ! (
148+ "{inner_expr};\n {}let {var_name}: {return_type} = {vec_str}[];" ,
149+ indent,
150+ var_name = snippet( cx, let_stmt. pat. span. source_callsite( ) , ".." )
151+ )
152+ }
153+
154+ fn assign_expr_suggestion (
155+ cx : & LateContext < ' _ > ,
156+ outer_expr : & Expr < ' _ > ,
157+ assign_expr_span : Span ,
158+ inner_expr : & str ,
159+ return_type : Ty < ' _ > ,
160+ vec_str : & str ,
161+ ) -> String {
162+ let mut parent_hir_node = cx. tcx . parent_hir_node ( outer_expr. hir_id ) ;
163+ if let Node :: Stmt ( stmt) = parent_hir_node {
164+ parent_hir_node = cx. tcx . parent_hir_node ( stmt. hir_id ) ;
165+ }
166+ let needs_curly = !matches ! ( parent_hir_node, Node :: Block ( _) ) ;
167+
168+ let indent = snippet_indent ( cx, outer_expr. span ) . unwrap_or_default ( ) ;
169+ let var_name = snippet ( cx, assign_expr_span. source_callsite ( ) , ".." ) ;
170+ if needs_curly {
171+ format ! ( "{{\n {indent}{inner_expr};\n {indent}{var_name} = {vec_str}[] as {return_type}\n {indent}}}" , )
172+ } else {
173+ format ! ( "{inner_expr};\n {indent}{var_name} = {vec_str}[] as {return_type}" )
174+ }
175+ }
0 commit comments