]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/panic_unimplemented.rs
Split out `infalliable_detructuring_match`
[rust.git] / clippy_lints / src / panic_unimplemented.rs
index 6379dffd22e372ac8305f8fce41fe8a50ad2e555..6ef6b9a20aa4b185211eaa6c96c48dae49d11af0 100644 (file)
-use crate::utils::{is_direct_expn_of, is_expn_of, match_function_call, paths, span_lint};
-use if_chain::if_chain;
-use rustc_ast::ast::LitKind;
-use rustc_hir::{Expr, ExprKind};
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
+use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for missing parameters in `panic!`.
+    /// ### What it does
+    /// Checks for usage of `panic!`.
     ///
-    /// **Why is this bad?** Contrary to the `format!` family of macros, there are
-    /// two forms of `panic!`: if there are no parameters given, the first argument
-    /// is not a format string and used literally. So while `format!("{}")` will
-    /// fail to compile, `panic!("{}")` will not.
+    /// ### Why is this bad?
+    /// `panic!` will stop the execution of the executable
     ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
-    /// ```no_run
-    /// panic!("This `panic!` is probably missing a parameter there: {}");
-    /// ```
-    pub PANIC_PARAMS,
-    style,
-    "missing parameters in `panic!` calls"
-}
-
-declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `panic!`.
-    ///
-    /// **Why is this bad?** `panic!` will stop the execution of the executable
-    ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
+    /// ### Example
     /// ```no_run
     /// panic!("even with a good reason");
     /// ```
+    #[clippy::version = "1.40.0"]
     pub PANIC,
     restriction,
     "usage of the `panic!` macro"
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `unimplemented!`.
-    ///
-    /// **Why is this bad?** This macro should not be present in production code
+    /// ### What it does
+    /// Checks for usage of `unimplemented!`.
     ///
-    /// **Known problems:** None.
+    /// ### Why is this bad?
+    /// This macro should not be present in production code
     ///
-    /// **Example:**
+    /// ### Example
     /// ```no_run
     /// unimplemented!();
     /// ```
+    #[clippy::version = "pre 1.29.0"]
     pub UNIMPLEMENTED,
     restriction,
     "`unimplemented!` should not be present in production code"
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `todo!`.
+    /// ### What it does
+    /// Checks for usage of `todo!`.
     ///
-    /// **Why is this bad?** This macro should not be present in production code
+    /// ### Why is this bad?
+    /// This macro should not be present in production code
     ///
-    /// **Known problems:** None.
-    ///
-    /// **Example:**
+    /// ### Example
     /// ```no_run
     /// todo!();
     /// ```
+    #[clippy::version = "1.40.0"]
     pub TODO,
     restriction,
     "`todo!` should not be present in production code"
 }
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `unreachable!`.
-    ///
-    /// **Why is this bad?** This macro can cause code to panic
+    /// ### What it does
+    /// Checks for usage of `unreachable!`.
     ///
-    /// **Known problems:** None.
+    /// ### Why is this bad?
+    /// This macro can cause code to panic
     ///
-    /// **Example:**
+    /// ### Example
     /// ```no_run
     /// unreachable!();
     /// ```
+    #[clippy::version = "1.40.0"]
     pub UNREACHABLE,
     restriction,
-    "`unreachable!` should not be present in production code"
+    "usage of the `unreachable!` macro"
 }
 
-declare_lint_pass!(PanicUnimplemented => [PANIC_PARAMS, UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
+declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
 
 impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if_chain! {
-            if let ExprKind::Block(ref block, _) = expr.kind;
-            if let Some(ref ex) = block.expr;
-            if let Some(params) = match_function_call(cx, ex, &paths::BEGIN_PANIC)
-                .or_else(|| match_function_call(cx, ex, &paths::BEGIN_PANIC_FMT));
-            then {
-                let span = get_outer_span(expr);
-                if is_expn_of(expr.span, "unimplemented").is_some() {
-                    span_lint(cx, UNIMPLEMENTED, span,
-                              "`unimplemented` should not be present in production code");
-                } else if is_expn_of(expr.span, "todo").is_some() {
-                    span_lint(cx, TODO, span,
-                              "`todo` should not be present in production code");
-                } else if is_expn_of(expr.span, "unreachable").is_some() {
-                    span_lint(cx, UNREACHABLE, span,
-                              "`unreachable` should not be present in production code");
-                } else if is_expn_of(expr.span, "panic").is_some() {
-                    span_lint(cx, PANIC, span,
-                              "`panic` should not be present in production code");
-                    match_panic(params, expr, cx);
-                }
-            }
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+        if is_panic(cx, macro_call.def_id) {
+            span_lint(
+                cx,
+                PANIC,
+                macro_call.span,
+                "`panic` should not be present in production code",
+            );
+            return;
         }
-    }
-}
-
-fn get_outer_span(expr: &Expr<'_>) -> Span {
-    if_chain! {
-        if expr.span.from_expansion();
-        let first = expr.span.ctxt().outer_expn_data();
-        if first.call_site.from_expansion();
-        let second = first.call_site.ctxt().outer_expn_data();
-        then {
-            second.call_site
-        } else {
-            expr.span
-        }
-    }
-}
-
-fn match_panic(params: &[Expr<'_>], expr: &Expr<'_>, cx: &LateContext<'_>) {
-    if_chain! {
-        if let ExprKind::Lit(ref lit) = params[0].kind;
-        if is_direct_expn_of(expr.span, "panic").is_some();
-        if let LitKind::Str(ref string, _) = lit.node;
-        let string = string.as_str().replace("{{", "").replace("}}", "");
-        if let Some(par) = string.find('{');
-        if string[par..].contains('}');
-        if params[0].span.source_callee().is_none();
-        if params[0].span.lo() != params[0].span.hi();
-        then {
-            span_lint(cx, PANIC_PARAMS, params[0].span,
-                      "you probably are missing some parameter in your format string");
+        match cx.tcx.item_name(macro_call.def_id).as_str() {
+            "todo" => {
+                span_lint(
+                    cx,
+                    TODO,
+                    macro_call.span,
+                    "`todo` should not be present in production code",
+                );
+            },
+            "unimplemented" => {
+                span_lint(
+                    cx,
+                    UNIMPLEMENTED,
+                    macro_call.span,
+                    "`unimplemented` should not be present in production code",
+                );
+            },
+            "unreachable" => {
+                span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro");
+            },
+            _ => {},
         }
     }
 }