]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/manual_assert.rs
modify code
[rust.git] / clippy_lints / src / manual_assert.rs
index c639be1bccba4645fd9f088713d8d66044583319..26b53ab5d683739b5e5b7d7df594be12f808575c 100644 (file)
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::PanicExpn;
+use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, sugg};
+use clippy_utils::{peel_blocks_with_stmt, sugg};
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_hir::{Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -26,6 +27,7 @@
     /// let sad_people: Vec<&str> = vec![];
     /// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
     /// ```
+    #[clippy::version = "1.57.0"]
     pub MANUAL_ASSERT,
     pedantic,
     "`panic!` and only a `panic!` in `if`-then statement"
 
 declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
 
-impl LateLintPass<'_> for ManualAssert {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+impl<'tcx> LateLintPass<'tcx> for ManualAssert {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if_chain! {
-            if let Expr {
-                kind: ExprKind:: If(cond, Expr {
-                    kind: ExprKind::Block(
-                        Block {
-                            stmts: [stmt],
-                            ..
-                        },
-                        _),
-                    ..
-                }, None),
-                ..
-            } = &expr;
-            if is_expn_of(stmt.span, "panic").is_some();
-            if !matches!(cond.kind, ExprKind::Let(_, _, _));
-            if let StmtKind::Semi(semi) = stmt.kind;
+            if let ExprKind::If(cond, then, None) = expr.kind;
+            if !matches!(cond.kind, ExprKind::Let(_));
+            if !expr.span.from_expansion();
+            let then = peel_blocks_with_stmt(then);
+            if let Some(macro_call) = root_macro_call(then.span);
+            if cx.tcx.item_name(macro_call.def_id) == sym::panic;
             if !cx.tcx.sess.source_map().is_multiline(cond.span);
-
+            if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
             then {
-                let span = if let Some(panic_expn) = PanicExpn::parse(semi) {
-                    match *panic_expn.format_args.value_args {
-                        [] => panic_expn.format_args.format_string_span,
-                        [.., last] => panic_expn.format_args.format_string_span.to(last.span),
-                    }
-                } else {
-                    if_chain! {
-                        if let ExprKind::Block(block, _) = semi.kind;
-                        if let Some(init) = block.expr;
-                        if let ExprKind::Call(_, [format_args]) = init.kind;
-
-                        then {
-                            format_args.span
-                        } else {
-                            return
-                        }
-                    }
-                };
                 let mut applicability = Applicability::MachineApplicable;
-                let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
-                let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
-                    if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
-                         sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
-                    } else {
-                       format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par())
-                    }
-                } else {
-                   format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
+                let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
+                let cond = cond.peel_drop_temps();
+                let (cond, not) = match cond.kind {
+                    ExprKind::Unary(UnOp::Not, e) => (e, ""),
+                    _ => (cond, "!"),
                 };
-
+                let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
+                let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
                 span_lint_and_sugg(
                     cx,
                     MANUAL_ASSERT,
                     expr.span,
                     "only a `panic!` in `if`-then statement",
                     "try",
-                    format!("assert!({}, {});", cond_sugg, sugg),
+                    sugg,
                     Applicability::MachineApplicable,
                 );
             }