From 7d42172899663993a9fd2e3445ddb58ab5d10a79 Mon Sep 17 00:00:00 2001 From: Caio Date: Fri, 1 Jan 2021 15:38:11 -0300 Subject: [PATCH] Reintroduce hir::ExprKind::If --- clippy_lints/src/assertions_on_constants.rs | 30 ++++------- clippy_lints/src/blocks_in_if_conditions.rs | 4 +- clippy_lints/src/cognitive_complexity.rs | 3 ++ clippy_lints/src/consts.rs | 6 +-- clippy_lints/src/copies.rs | 15 +++--- clippy_lints/src/entry.rs | 4 +- clippy_lints/src/floating_point_arithmetic.rs | 6 +-- clippy_lints/src/implicit_return.rs | 7 +++ clippy_lints/src/implicit_saturating_sub.rs | 4 +- clippy_lints/src/let_if_seq.rs | 5 +- clippy_lints/src/loops.rs | 10 +++- clippy_lints/src/manual_strip.rs | 2 +- clippy_lints/src/methods/mod.rs | 1 + .../src/methods/unnecessary_filter_map.rs | 6 +++ clippy_lints/src/mutable_debug_assertion.rs | 4 ++ clippy_lints/src/needless_bool.rs | 4 +- clippy_lints/src/option_if_let_else.rs | 15 +++--- clippy_lints/src/question_mark.rs | 4 +- clippy_lints/src/returns.rs | 11 ++-- clippy_lints/src/shadow.rs | 7 +++ clippy_lints/src/unwrap.rs | 4 +- clippy_lints/src/utils/author.rs | 51 ++++++++----------- clippy_lints/src/utils/eager_or_lazy.rs | 1 + clippy_lints/src/utils/higher.rs | 34 ++----------- clippy_lints/src/utils/hir_utils.rs | 12 +++++ clippy_lints/src/utils/inspector.rs | 9 ++++ clippy_lints/src/utils/mod.rs | 12 ++--- clippy_lints/src/utils/sugg.rs | 1 + clippy_lints/src/utils/visitors.rs | 7 +++ tests/ui/author/if.stdout | 2 +- tests/ui/panic_in_result_fn_assertions.stderr | 2 +- 31 files changed, 152 insertions(+), 131 deletions(-) diff --git a/clippy_lints/src/assertions_on_constants.rs b/clippy_lints/src/assertions_on_constants.rs index 62c73dbac48b4..aa431f0596cca 100644 --- a/clippy_lints/src/assertions_on_constants.rs +++ b/clippy_lints/src/assertions_on_constants.rs @@ -1,8 +1,7 @@ use crate::consts::{constant, Constant}; use crate::utils::{is_direct_expn_of, is_expn_of, match_panic_call, snippet_opt, span_lint_and_help}; use if_chain::if_chain; -use rustc_ast::ast::LitKind; -use rustc_hir::{Expr, ExprKind, PatKind, UnOp}; +use rustc_hir::{Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -102,31 +101,22 @@ enum AssertKind { /// Check if the expression matches /// /// ```rust,ignore -/// match { let _t = !c; _t } { -/// true => { -/// { -/// ::std::rt::begin_panic(message, _) -/// } -/// } -/// _ => { } -/// }; +/// if !c { +/// { +/// ::std::rt::begin_panic(message, _) +/// } +/// } /// ``` /// /// where `message` is any expression and `c` is a constant bool. fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option { if_chain! { - if let ExprKind::Match(ref expr, ref arms, _) = expr.kind; - // matches { let _t = expr; _t } - if let ExprKind::DropTemps(ref expr) = expr.kind; - if let ExprKind::Unary(UnOp::UnNot, ref expr) = expr.kind; + if let ExprKind::If(ref cond, ref then, _) = expr.kind; + if let ExprKind::Unary(UnOp::UnNot, ref expr) = cond.kind; // bind the first argument of the `assert!` macro if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr); - // arm 1 pattern - if let PatKind::Lit(ref lit_expr) = arms[0].pat.kind; - if let ExprKind::Lit(ref lit) = lit_expr.kind; - if let LitKind::Bool(true) = lit.node; - // arm 1 block - if let ExprKind::Block(ref block, _) = arms[0].body.kind; + // block + if let ExprKind::Block(ref block, _) = then.kind; if block.stmts.is_empty(); if let Some(block_expr) = &block.expr; // inner block is optional. unwrap it if it exists, or use the expression as is otherwise. diff --git a/clippy_lints/src/blocks_in_if_conditions.rs b/clippy_lints/src/blocks_in_if_conditions.rs index 736730d4084f4..4efca10bcdf13 100644 --- a/clippy_lints/src/blocks_in_if_conditions.rs +++ b/clippy_lints/src/blocks_in_if_conditions.rs @@ -1,4 +1,4 @@ -use crate::utils::{differing_macro_contexts, higher, snippet_block_with_applicability, span_lint, span_lint_and_sugg}; +use crate::utils::{differing_macro_contexts, snippet_block_with_applicability, span_lint, span_lint_and_sugg}; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{BlockCheckMode, Expr, ExprKind}; @@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for BlocksInIfConditions { if in_external_macro(cx.sess(), expr.span) { return; } - if let Some((cond, _, _)) = higher::if_block(&expr) { + if let ExprKind::If(cond, _, _) = &expr.kind { if let ExprKind::Block(block, _) = &cond.kind { if block.rules == BlockCheckMode::DefaultBlock { if block.stmts.is_empty() { diff --git a/clippy_lints/src/cognitive_complexity.rs b/clippy_lints/src/cognitive_complexity.rs index b1bc2ec29e16e..b3ebdf4ca30d8 100644 --- a/clippy_lints/src/cognitive_complexity.rs +++ b/clippy_lints/src/cognitive_complexity.rs @@ -147,6 +147,9 @@ impl<'tcx> Visitor<'tcx> for CCHelper { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { walk_expr(self, e); match e.kind { + ExprKind::If(_, _, _) => { + self.cc += 1; + }, ExprKind::Match(_, ref arms, _) => { if arms.len() > 1 { self.cc += 1; diff --git a/clippy_lints/src/consts.rs b/clippy_lints/src/consts.rs index 0035ded9356cf..166eadf86c177 100644 --- a/clippy_lints/src/consts.rs +++ b/clippy_lints/src/consts.rs @@ -1,6 +1,6 @@ #![allow(clippy::float_cmp)] -use crate::utils::{clip, higher, sext, unsext}; +use crate::utils::{clip, sext, unsext}; use if_chain::if_chain; use rustc_ast::ast::{FloatTy, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; @@ -228,9 +228,6 @@ pub struct ConstEvalLateContext<'a, 'tcx> { impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option { - if let Some((ref cond, ref then, otherwise)) = higher::if_block(&e) { - return self.ifthenelse(cond, then, otherwise); - } match e.kind { ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)), ExprKind::Block(ref block, _) => self.block(block), @@ -249,6 +246,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { UnOp::UnNeg => self.constant_negate(&o, self.typeck_results.expr_ty(e)), UnOp::UnDeref => Some(if let Constant::Ref(r) = o { *r } else { o }), }), + ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise), ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right), ExprKind::Call(ref callee, ref args) => { // We only handle a few const functions for now. diff --git a/clippy_lints/src/copies.rs b/clippy_lints/src/copies.rs index 46ce92ea6d782..6f48ffeb0e9c9 100644 --- a/clippy_lints/src/copies.rs +++ b/clippy_lints/src/copies.rs @@ -1,6 +1,6 @@ use crate::utils::{eq_expr_value, in_macro, search_same, SpanlessEq, SpanlessHash}; -use crate::utils::{get_parent_expr, higher, if_sequence, span_lint_and_note}; -use rustc_hir::{Block, Expr}; +use crate::utils::{get_parent_expr, if_sequence, span_lint_and_note}; +use rustc_hir::{Block, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -109,11 +109,12 @@ impl<'tcx> LateLintPass<'tcx> for CopyAndPaste { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !expr.span.from_expansion() { // skip ifs directly in else, it will be checked in the parent if - if let Some(expr) = get_parent_expr(cx, expr) { - if let Some((_, _, Some(ref else_expr))) = higher::if_block(&expr) { - if else_expr.hir_id == expr.hir_id { - return; - } + if let Some(&Expr { + kind: ExprKind::If(_, _, Some(ref else_expr)), + .. + }) = get_parent_expr(cx, expr) { + if else_expr.hir_id == expr.hir_id { + return; } } diff --git a/clippy_lints/src/entry.rs b/clippy_lints/src/entry.rs index 35a5d00f4aa5a..37948e06869c3 100644 --- a/clippy_lints/src/entry.rs +++ b/clippy_lints/src/entry.rs @@ -1,5 +1,5 @@ use crate::utils::SpanlessEq; -use crate::utils::{get_item_name, higher, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt}; +use crate::utils::{get_item_name, is_type_diagnostic_item, match_type, paths, snippet, snippet_opt}; use crate::utils::{snippet_with_applicability, span_lint_and_then}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -54,7 +54,7 @@ declare_lint_pass!(HashMapPass => [MAP_ENTRY]); impl<'tcx> LateLintPass<'tcx> for HashMapPass { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let Some((ref check, ref then_block, ref else_block)) = higher::if_block(&expr) { + if let ExprKind::If(ref check, ref then_block, ref else_block) = expr.kind { if let ExprKind::Unary(UnOp::UnNot, ref check) = check.kind { if let Some((ty, map, key)) = check_cond(cx, check) { // in case of `if !m.contains_key(&k) { m.insert(k, v); }` diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs index 18fea8b34bfd4..ffef78aac8067 100644 --- a/clippy_lints/src/floating_point_arithmetic.rs +++ b/clippy_lints/src/floating_point_arithmetic.rs @@ -2,7 +2,7 @@ use crate::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; -use crate::utils::{eq_expr_value, get_parent_expr, higher, numeric_literal, span_lint_and_sugg, sugg}; +use crate::utils::{eq_expr_value, get_parent_expr, numeric_literal, span_lint_and_sugg, sugg}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -556,11 +556,11 @@ fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let Some((cond, body, Some(else_body))) = higher::if_block(&expr); + if let ExprKind::If(cond, body, else_body) = expr.kind; if let ExprKind::Block(block, _) = body.kind; if block.stmts.is_empty(); if let Some(if_body_expr) = block.expr; - if let ExprKind::Block(else_block, _) = else_body.kind; + if let Some(ExprKind::Block(else_block, _)) = else_body.map(|el| &el.kind); if else_block.stmts.is_empty(); if let Some(else_body_expr) = else_block.expr; if let Some((if_expr_positive, body)) = are_negated(cx, if_body_expr, else_body_expr); diff --git a/clippy_lints/src/implicit_return.rs b/clippy_lints/src/implicit_return.rs index 03e95c9e27f6a..109d90ff772b5 100644 --- a/clippy_lints/src/implicit_return.rs +++ b/clippy_lints/src/implicit_return.rs @@ -81,6 +81,13 @@ fn expr_match(cx: &LateContext<'_>, expr: &Expr<'_>) { lint(cx, expr.span, break_expr.span, LINT_BREAK); } }, + ExprKind::If(.., if_expr, else_expr) => { + expr_match(cx, if_expr); + + if let Some(else_expr) = else_expr { + expr_match(cx, else_expr); + } + }, ExprKind::Match(.., arms, source) => { let check_all_arms = match source { MatchSource::IfLetDesugar { diff --git a/clippy_lints/src/implicit_saturating_sub.rs b/clippy_lints/src/implicit_saturating_sub.rs index 3a01acd8fdc97..16e162badb5ee 100644 --- a/clippy_lints/src/implicit_saturating_sub.rs +++ b/clippy_lints/src/implicit_saturating_sub.rs @@ -1,4 +1,4 @@ -use crate::utils::{higher, in_macro, match_qpath, span_lint_and_sugg, SpanlessEq}; +use crate::utils::{in_macro, match_qpath, span_lint_and_sugg, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { return; } if_chain! { - if let Some((ref cond, ref then, None)) = higher::if_block(&expr); + if let ExprKind::If(cond, then, None) = &expr.kind; // Check if the conditional expression is a binary operation if let ExprKind::Binary(ref cond_op, ref cond_left, ref cond_right) = cond.kind; diff --git a/clippy_lints/src/let_if_seq.rs b/clippy_lints/src/let_if_seq.rs index 0d2d95324c4f7..db717cd1240a4 100644 --- a/clippy_lints/src/let_if_seq.rs +++ b/clippy_lints/src/let_if_seq.rs @@ -1,5 +1,4 @@ -use crate::utils::visitors::LocalUsedVisitor; -use crate::utils::{higher, qpath_res, snippet, span_lint_and_then}; +use crate::utils::{qpath_res, snippet, span_lint_and_then, visitors::LocalUsedVisitor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir as hir; @@ -64,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for LetIfSeq { if let hir::StmtKind::Local(ref local) = stmt.kind; if let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind; if let hir::StmtKind::Expr(ref if_) = expr.kind; - if let Some((ref cond, ref then, ref else_)) = higher::if_block(&if_); + if let hir::ExprKind::If(ref cond, ref then, ref else_) = if_.kind; if !LocalUsedVisitor::new(canonical_id).check_expr(cond); if let hir::ExprKind::Block(ref then, _) = then.kind; if let Some(value) = check_assign(cx, canonical_id, &*then); diff --git a/clippy_lints/src/loops.rs b/clippy_lints/src/loops.rs index 1bd96b2b4c89b..281964ee5e8f3 100644 --- a/clippy_lints/src/loops.rs +++ b/clippy_lints/src/loops.rs @@ -742,6 +742,14 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult { // Break can come from the inner loop so remove them. absorb_break(&never_loop_block(b, main_loop_id)) }, + ExprKind::If(ref e, ref e2, ref e3) => { + let e1 = never_loop_expr(e, main_loop_id); + let e2 = never_loop_expr(e2, main_loop_id); + let e3 = e3 + .as_ref() + .map_or(NeverLoopResult::Otherwise, |e| never_loop_expr(e, main_loop_id)); + combine_seq(e1, combine_branches(e2, e3)) + }, ExprKind::Match(ref e, ref arms, _) => { let e = never_loop_expr(e, main_loop_id); if arms.is_empty() { @@ -2594,7 +2602,7 @@ fn is_loop(expr: &Expr<'_>) -> bool { } fn is_conditional(expr: &Expr<'_>) -> bool { - matches!(expr.kind, ExprKind::Match(..)) + matches!(expr.kind, ExprKind::If(..) | ExprKind::Match(..)) } fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { diff --git a/clippy_lints/src/manual_strip.rs b/clippy_lints/src/manual_strip.rs index 3c4368a3545a9..a0cfe145a301c 100644 --- a/clippy_lints/src/manual_strip.rs +++ b/clippy_lints/src/manual_strip.rs @@ -80,7 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { } if_chain! { - if let Some((cond, then, _)) = higher::if_block(&expr); + if let ExprKind::If(cond, then, _) = &expr.kind; if let ExprKind::MethodCall(_, _, [target_arg, pattern], _) = cond.kind; if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id); if let ExprKind::Path(target_path) = &target_arg.kind; diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index e99fe1b97ff64..2234890d6e94f 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -2048,6 +2048,7 @@ fn lint_expect_fun_call( hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) // These variants are debatable or require further examination + | hir::ExprKind::If(..) | hir::ExprKind::Match(..) | hir::ExprKind::Block{ .. } => true, _ => false, diff --git a/clippy_lints/src/methods/unnecessary_filter_map.rs b/clippy_lints/src/methods/unnecessary_filter_map.rs index d082a88cd2db5..d98e6160d3085 100644 --- a/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -90,6 +90,12 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc } (found_mapping, found_filtering) }, + // There must be an else_arm or there will be a type error + hir::ExprKind::If(_, ref if_arm, Some(ref else_arm)) => { + let if_check = check_expression(cx, arg_id, if_arm); + let else_check = check_expression(cx, arg_id, else_arm); + (if_check.0 | else_check.0, if_check.1 | else_check.1) + }, hir::ExprKind::Path(path) if match_qpath(path, &paths::OPTION_NONE) => (false, true), _ => (true, true), } diff --git a/clippy_lints/src/mutable_debug_assertion.rs b/clippy_lints/src/mutable_debug_assertion.rs index 76417aa7ed09d..71f91eb4bfbe3 100644 --- a/clippy_lints/src/mutable_debug_assertion.rs +++ b/clippy_lints/src/mutable_debug_assertion.rs @@ -90,6 +90,10 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { self.found = true; return; }, + ExprKind::If(..) => { + self.found = true; + return; + }, ExprKind::Path(_) => { if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) { if adj diff --git a/clippy_lints/src/needless_bool.rs b/clippy_lints/src/needless_bool.rs index 42f97b2ac497a..6b9a37b525201 100644 --- a/clippy_lints/src/needless_bool.rs +++ b/clippy_lints/src/needless_bool.rs @@ -4,7 +4,7 @@ use crate::utils::sugg::Sugg; use crate::utils::{ - higher, is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg, + is_expn_of, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg, }; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -71,7 +71,7 @@ declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]); impl<'tcx> LateLintPass<'tcx> for NeedlessBool { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use self::Expression::{Bool, RetBool}; - if let Some((ref pred, ref then_block, Some(ref else_expr))) = higher::if_block(&e) { + if let ExprKind::If(ref pred, ref then_block, Some(ref else_expr)) = e.kind { let reduce = |ret, not| { let mut applicability = Applicability::MachineApplicable; let snip = Sugg::hir_with_applicability(cx, pred, "", &mut applicability); diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs index 681dbce97697e..391f893ef35ff 100644 --- a/clippy_lints/src/option_if_let_else.rs +++ b/clippy_lints/src/option_if_let_else.rs @@ -109,25 +109,26 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { /// it in curly braces. Otherwise, we don't. fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { utils::get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { + let mut should_wrap = false; + if let Some(Expr { kind: ExprKind::Match( _, arms, - MatchSource::IfDesugar { - contains_else_clause: true, - } - | MatchSource::IfLetDesugar { + MatchSource::IfLetDesugar { contains_else_clause: true, }, ), .. }) = parent.expr { - expr.hir_id == arms[1].body.hir_id - } else { - false + should_wrap = expr.hir_id == arms[1].body.hir_id; + } else if let Some(Expr { kind: ExprKind::If(_, _, Some(else_clause)), .. }) = parent.expr { + should_wrap = expr.hir_id == else_clause.hir_id; } + + should_wrap }) } diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index b91233ac58280..6c480d48c7561 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -8,7 +8,7 @@ use rustc_span::sym; use crate::utils::sugg::Sugg; use crate::utils::{ - eq_expr_value, higher, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability, + eq_expr_value, is_type_diagnostic_item, match_def_path, match_qpath, paths, snippet_with_applicability, span_lint_and_sugg, }; @@ -50,7 +50,7 @@ impl QuestionMark { /// If it matches, it will suggest to use the question mark operator instead fn check_is_none_and_early_return_none(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let Some((if_expr, body, else_)) = higher::if_block(&expr); + if let ExprKind::If(if_expr, body, else_) = &expr.kind; if let ExprKind::MethodCall(segment, _, args, _) = &if_expr.kind; if segment.ident.name == sym!(is_none); if Self::expression_returns_none(cx, body); diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs index 7f4913a02cbd3..35827e027aab8 100644 --- a/clippy_lints/src/returns.rs +++ b/clippy_lints/src/returns.rs @@ -184,6 +184,14 @@ fn check_final_expr<'tcx>( ExprKind::Block(ref block, _) => { check_block_return(cx, block); }, + ExprKind::If(_, then, else_clause_opt) => { + if let ExprKind::Block(ref ifblock, _) = then.kind { + check_block_return(cx, ifblock); + } + if let Some(else_clause) = else_clause_opt { + check_final_expr(cx, else_clause, None, RetReplacement::Empty); + } + }, // a match expr, check all arms // an if/if let expr, check both exprs // note, if without else is going to be a type checking error anyways @@ -194,9 +202,6 @@ fn check_final_expr<'tcx>( check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block); } }, - MatchSource::IfDesugar { - contains_else_clause: true, - } | MatchSource::IfLetDesugar { contains_else_clause: true, } => { diff --git a/clippy_lints/src/shadow.rs b/clippy_lints/src/shadow.rs index f839659267825..f2f3dfa09a7d4 100644 --- a/clippy_lints/src/shadow.rs +++ b/clippy_lints/src/shadow.rs @@ -333,6 +333,13 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut check_expr(cx, e, bindings) } }, + ExprKind::If(ref cond, ref then, ref otherwise) => { + check_expr(cx, cond, bindings); + check_expr(cx, &**then, bindings); + if let Some(ref o) = *otherwise { + check_expr(cx, o, bindings); + } + }, ExprKind::Match(ref init, arms, _) => { check_expr(cx, init, bindings); let len = bindings.len(); diff --git a/clippy_lints/src/unwrap.rs b/clippy_lints/src/unwrap.rs index f4a77e54dd149..6a87f53436980 100644 --- a/clippy_lints/src/unwrap.rs +++ b/clippy_lints/src/unwrap.rs @@ -1,5 +1,5 @@ use crate::utils::{ - differing_macro_contexts, higher::if_block, is_type_diagnostic_item, span_lint_and_then, + differing_macro_contexts, is_type_diagnostic_item, span_lint_and_then, usage::is_potentially_mutated, }; use if_chain::if_chain; @@ -158,7 +158,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> { if in_external_macro(self.cx.tcx.sess, expr.span) { return; } - if let Some((cond, then, els)) = if_block(&expr) { + if let ExprKind::If(cond, then, els) = &expr.kind { walk_expr(self, cond); self.visit_branch(cond, then, false); if let Some(els) = els { diff --git a/clippy_lints/src/utils/author.rs b/clippy_lints/src/utils/author.rs index 4249dbb4e6519..43afa65de3e55 100644 --- a/clippy_lints/src/utils/author.rs +++ b/clippy_lints/src/utils/author.rs @@ -1,7 +1,7 @@ //! A group of attributes that can be attached to Rust code in order //! to generate a clippy lint detecting said code automatically. -use crate::utils::{get_attr, higher}; +use crate::utils::get_attr; use rustc_ast::ast::{Attribute, LitFloatType, LitKind}; use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashMap; @@ -201,32 +201,6 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { #[allow(clippy::too_many_lines)] fn visit_expr(&mut self, expr: &Expr<'_>) { - // handle if desugarings - // TODO add more desugarings here - if let Some((cond, then, opt_else)) = higher::if_block(&expr) { - let cond_pat = self.next("cond"); - let then_pat = self.next("then"); - if let Some(else_) = opt_else { - let else_pat = self.next("else_"); - println!( - " if let Some((ref {}, ref {}, Some({}))) = higher::if_block(&{});", - cond_pat, then_pat, else_pat, self.current - ); - self.current = else_pat; - self.visit_expr(else_); - } else { - println!( - " if let Some((ref {}, ref {}, None)) = higher::if_block(&{});", - cond_pat, then_pat, self.current - ); - } - self.current = cond_pat; - self.visit_expr(cond); - self.current = then_pat; - self.visit_expr(then); - return; - } - print!(" if let ExprKind::"); let current = format!("{}.kind", self.current); match expr.kind { @@ -351,6 +325,25 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { self.current = body_pat; self.visit_block(body); }, + ExprKind::If(ref cond, ref then, ref opt_else) => { + let cond_pat = self.next("cond"); + let then_pat = self.next("then"); + if let Some(ref else_) = *opt_else { + let else_pat = self.next("else_"); + println!( + "If(ref {}, ref {}, Some(ref {})) = {};", + cond_pat, then_pat, else_pat, current + ); + self.current = else_pat; + self.visit_expr(else_); + } else { + println!("If(ref {}, ref {}, None) = {};", cond_pat, then_pat, current); + } + self.current = cond_pat; + self.visit_expr(cond); + self.current = then_pat; + self.visit_expr(then); + }, ExprKind::Match(ref expr, ref arms, desugaring) => { let des = desugaring_name(desugaring); let expr_pat = self.next("expr"); @@ -743,10 +736,6 @@ fn desugaring_name(des: hir::MatchSource) -> String { contains_else_clause ), hir::MatchSource::IfLetGuardDesugar => "MatchSource::IfLetGuardDesugar".to_string(), - hir::MatchSource::IfDesugar { contains_else_clause } => format!( - "MatchSource::IfDesugar {{ contains_else_clause: {} }}", - contains_else_clause - ), hir::MatchSource::AwaitDesugar => "MatchSource::AwaitDesugar".to_string(), } } diff --git a/clippy_lints/src/utils/eager_or_lazy.rs b/clippy_lints/src/utils/eager_or_lazy.rs index 8fe5ddee1ca8d..2f157c5030f44 100644 --- a/clippy_lints/src/utils/eager_or_lazy.rs +++ b/clippy_lints/src/utils/eager_or_lazy.rs @@ -62,6 +62,7 @@ fn identify_some_pure_patterns(expr: &Expr<'_>) -> bool { | ExprKind::Type(..) | ExprKind::DropTemps(..) | ExprKind::Loop(..) + | ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Closure(..) | ExprKind::Block(..) diff --git a/clippy_lints/src/utils/higher.rs b/clippy_lints/src/utils/higher.rs index 01ffac5b5599d..9b3585865da32 100644 --- a/clippy_lints/src/utils/higher.rs +++ b/clippy_lints/src/utils/higher.rs @@ -170,33 +170,6 @@ pub fn while_loop<'tcx>(expr: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx hir::Expr< None } -/// Recover the essential nodes of a desugared if block -/// `if cond { then } else { els }` becomes `(cond, then, Some(els))` -pub fn if_block<'tcx>( - expr: &'tcx hir::Expr<'tcx>, -) -> Option<( - &'tcx hir::Expr<'tcx>, - &'tcx hir::Expr<'tcx>, - Option<&'tcx hir::Expr<'tcx>>, -)> { - if let hir::ExprKind::Match(ref cond, ref arms, hir::MatchSource::IfDesugar { contains_else_clause }) = expr.kind { - let cond = if let hir::ExprKind::DropTemps(ref cond) = cond.kind { - cond - } else { - panic!("If block desugar must contain DropTemps"); - }; - let then = &arms[0].body; - let els = if contains_else_clause { - Some(&*arms[1].body) - } else { - None - }; - Some((cond, then, els)) - } else { - None - } -} - /// Represent the pre-expansion arguments of a `vec!` invocation. pub enum VecArgs<'a> { /// `vec![elem; len]` @@ -267,12 +240,11 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option SpanlessEq<'a, 'tcx> { (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => { self.eq_expr(la, ra) && self.eq_expr(li, ri) }, + (&ExprKind::If(ref lc, ref lt, ref le), &ExprKind::If(ref rc, ref rt, ref re)) => { + self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r)) + }, (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node, (&ExprKind::Loop(ref lb, ref ll, ref lls), &ExprKind::Loop(ref rb, ref rl, ref rls)) => { lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.as_str() == r.ident.as_str()) @@ -564,6 +567,15 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_name(i.ident.name); } }, + ExprKind::If(ref cond, ref then, ref else_opt) => { + let c: fn(_, _, _) -> _ = ExprKind::If; + c.hash(&mut self.s); + self.hash_expr(cond); + self.hash_expr(&**then); + if let Some(ref e) = *else_opt { + self.hash_expr(e); + } + }, ExprKind::Match(ref e, arms, ref s) => { self.hash_expr(e); diff --git a/clippy_lints/src/utils/inspector.rs b/clippy_lints/src/utils/inspector.rs index 5d946e4bd495d..71c11788d93ac 100644 --- a/clippy_lints/src/utils/inspector.rs +++ b/clippy_lints/src/utils/inspector.rs @@ -213,6 +213,15 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) { hir::ExprKind::Loop(..) => { println!("{}Loop", ind); }, + hir::ExprKind::If(ref cond, _, ref else_opt) => { + println!("{}If", ind); + println!("{}condition:", ind); + print_expr(cx, cond, indent + 1); + if let Some(ref els) = *else_opt { + println!("{}else:", ind); + print_expr(cx, els, indent + 1); + } + }, hir::ExprKind::Match(ref cond, _, ref source) => { println!("{}Match", ind); println!("{}condition:", ind); diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs index 1c68e837c4ab9..bd103246e4ef8 100644 --- a/clippy_lints/src/utils/mod.rs +++ b/clippy_lints/src/utils/mod.rs @@ -1405,7 +1405,7 @@ pub fn if_sequence<'tcx>( let mut conds = SmallVec::new(); let mut blocks: SmallVec<[&Block<'_>; 1]> = SmallVec::new(); - while let Some((ref cond, ref then_expr, ref else_expr)) = higher::if_block(&expr) { + while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind { conds.push(&**cond); if let ExprKind::Block(ref block, _) = then_expr.kind { blocks.push(block); @@ -1434,11 +1434,11 @@ pub fn parent_node_is_if_expr(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool { let map = cx.tcx.hir(); let parent_id = map.get_parent_node(expr.hir_id); let parent_node = map.get(parent_id); - - match parent_node { - Node::Expr(e) => higher::if_block(&e).is_some(), - Node::Arm(e) => higher::if_block(&e.body).is_some(), - _ => false, + if let Node::Expr(Expr { kind: ExprKind::If(_, _, _), .. }) = parent_node { + true + } + else { + false } } diff --git a/clippy_lints/src/utils/sugg.rs b/clippy_lints/src/utils/sugg.rs index 1fcd41e4dbfed..03678db575f0d 100644 --- a/clippy_lints/src/utils/sugg.rs +++ b/clippy_lints/src/utils/sugg.rs @@ -103,6 +103,7 @@ impl<'a> Sugg<'a> { match expr.kind { hir::ExprKind::AddrOf(..) | hir::ExprKind::Box(..) + | hir::ExprKind::If(..) | hir::ExprKind::Closure(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Match(..) => Sugg::MaybeParen(snippet), diff --git a/clippy_lints/src/utils/visitors.rs b/clippy_lints/src/utils/visitors.rs index 28b3e79d7a6d6..b769a18802b6b 100644 --- a/clippy_lints/src/utils/visitors.rs +++ b/clippy_lints/src/utils/visitors.rs @@ -101,6 +101,13 @@ where } } else { match expr.kind { + hir::ExprKind::If(cond, then, else_opt) => { + self.inside_stmt(true).visit_expr(cond); + self.visit_expr(then); + if let Some(el) = else_opt { + self.visit_expr(el); + } + } hir::ExprKind::Match(cond, arms, _) => { self.inside_stmt(true).visit_expr(cond); for arm in arms { diff --git a/tests/ui/author/if.stdout b/tests/ui/author/if.stdout index c18d035953e53..cac64a3f40b41 100644 --- a/tests/ui/author/if.stdout +++ b/tests/ui/author/if.stdout @@ -1,7 +1,7 @@ if_chain! { if let StmtKind::Local(ref local) = stmt.kind; if let Some(ref init) = local.init; - if let Some((ref cond, ref then, Some(else_))) = higher::if_block(&init); + if let ExprKind::If(ref cond, ref then, Some(ref else_)) = init.kind; if let ExprKind::Block(ref block) = else_.kind; if let Some(trailing_expr) = &block.expr; if block.stmts.len() == 1; diff --git a/tests/ui/panic_in_result_fn_assertions.stderr b/tests/ui/panic_in_result_fn_assertions.stderr index 86f61ad718a9c..a17f043737d4e 100644 --- a/tests/ui/panic_in_result_fn_assertions.stderr +++ b/tests/ui/panic_in_result_fn_assertions.stderr @@ -14,7 +14,7 @@ note: return Err() instead of panicking --> $DIR/panic_in_result_fn_assertions.rs:9:9 | LL | assert!(x == 5, "wrong argument"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`