]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/panic_in_result_fn.rs
Last PR adjustments
[rust.git] / clippy_lints / src / panic_in_result_fn.rs
index 791a2bf079846838beba6b84de4918c7f72b27df..efec12489a9bad42708568988843610ddfb172b9 100644 (file)
@@ -1,6 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::return_ty;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{find_macro_calls, return_ty};
+use clippy_utils::visitors::{for_each_expr, Descend};
+use core::ops::ControlFlow;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
-    /// **What it does:** Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result.
+    /// ### What it does
+    /// Checks for usage of `panic!`, `unimplemented!`, `todo!`, `unreachable!` or assertions in a function of type result.
     ///
-    /// **Why is this bad?** For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided.
+    /// ### Why is this bad?
+    /// For some codebases, it is desirable for functions of type result to return an error instead of crashing. Hence panicking macros should be avoided.
     ///
-    /// **Known problems:** Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked.
-    ///
-    /// **Example:**
+    /// ### Known problems
+    /// Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked.
     ///
+    /// ### Example
     /// ```rust
     /// fn result_with_panic() -> Result<bool, String>
     /// {
@@ -28,6 +33,7 @@
     ///     Err(String::from("error"))
     /// }
     /// ```
+    #[clippy::version = "1.48.0"]
     pub PANIC_IN_RESULT_FN,
     restriction,
     "functions of type `Result<..>` that contain `panic!()`, `todo!()`, `unreachable()`, `unimplemented()` or assertion"
@@ -45,25 +51,28 @@ fn check_fn(
         span: Span,
         hir_id: hir::HirId,
     ) {
-        if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::result_type) {
+        if !matches!(fn_kind, FnKind::Closure) && is_type_diagnostic_item(cx, return_ty(cx, hir_id), sym::Result) {
             lint_impl_body(cx, span, body);
         }
     }
 }
 
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
-    let panics = find_macro_calls(
-        &[
-            "unimplemented",
-            "unreachable",
-            "panic",
-            "todo",
-            "assert",
-            "assert_eq",
-            "assert_ne",
-        ],
-        body,
-    );
+    let mut panics = Vec::new();
+    let _: Option<!> = for_each_expr(body.value, |e| {
+        let Some(macro_call) = root_macro_call_first_node(cx, e) else {
+            return ControlFlow::Continue(Descend::Yes);
+        };
+        if matches!(
+            cx.tcx.item_name(macro_call.def_id).as_str(),
+            "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne"
+        ) {
+            panics.push(macro_call.span);
+            ControlFlow::Continue(Descend::No)
+        } else {
+            ControlFlow::Continue(Descend::Yes)
+        }
+    });
     if !panics.is_empty() {
         span_lint_and_then(
             cx,