about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Moelius <samuel.moelius@trailofbits.com>2025-01-02 18:03:54 -0500
committerSamuel Moelius <sam@moeli.us>2025-03-20 21:02:33 -0400
commitaadda467525d6bb6ade388312cb71f20f8c0e2f4 (patch)
treee6d9acf413aef03977af0b6db3c63c3dc1e4ee58
parent1e5237f4a56ae958af7e5824343eacf737b67083 (diff)
downloadrust-aadda467525d6bb6ade388312cb71f20f8c0e2f4.tar.gz
rust-aadda467525d6bb6ade388312cb71f20f8c0e2f4.zip
Add `ignore_without_reason` lint
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/attrs/mod.rs45
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--tests/ui/ignore_without_reason.rs14
-rw-r--r--tests/ui/ignore_without_reason.stderr12
5 files changed, 72 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1bf4b51ff0f..0d00638f2ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5681,6 +5681,7 @@ Released 2018-09-13
 [`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
 [`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
 [`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
+[`ignore_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignore_without_reason
 [`ignored_unit_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns
 [`impl_hash_borrow_with_str_and_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_hash_borrow_with_str_and_bytes
 [`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
diff --git a/clippy_lints/src/attrs/mod.rs b/clippy_lints/src/attrs/mod.rs
index e04d2ad5d13..7ba7b476617 100644
--- a/clippy_lints/src/attrs/mod.rs
+++ b/clippy_lints/src/attrs/mod.rs
@@ -14,8 +14,9 @@ mod useless_attribute;
 mod utils;
 
 use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::msrvs::{self, Msrv, MsrvStack};
-use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind};
+use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind};
 use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
@@ -448,6 +449,31 @@ declare_clippy_lint! {
     "duplicated attribute"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for ignored tests without messages.
+    ///
+    /// ### Why is this bad?
+    /// The reason for ignoring the test may not be obvious.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// #[test]
+    /// #[ignore]
+    /// fn test() {}
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// #[test]
+    /// #[ignore = "Some good reason"]
+    /// fn test() {}
+    /// ```
+    #[clippy::version = "1.85.0"]
+    pub IGNORE_WITHOUT_REASON,
+    restriction,
+    "ignored tests without messages"
+}
+
 pub struct Attributes {
     msrv: Msrv,
 }
@@ -532,6 +558,7 @@ impl_lint_pass!(PostExpansionEarlyAttributes => [
     ALLOW_ATTRIBUTES,
     ALLOW_ATTRIBUTES_WITHOUT_REASON,
     DEPRECATED_SEMVER,
+    IGNORE_WITHOUT_REASON,
     USELESS_ATTRIBUTE,
     BLANKET_CLIPPY_RESTRICTION_LINTS,
     SHOULD_PANIC_WITHOUT_EXPECT,
@@ -575,6 +602,22 @@ impl EarlyLintPass for PostExpansionEarlyAttributes {
         if attr.has_name(sym::should_panic) {
             should_panic_without_expect::check(cx, attr);
         }
+
+        if attr.has_name(sym::ignore)
+            && match &attr.kind {
+                AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrArgs::Eq { .. }),
+                AttrKind::DocComment(..) => true,
+            }
+        {
+            span_lint_and_help(
+                cx,
+                IGNORE_WITHOUT_REASON,
+                attr.span,
+                "`#[ignore]` without reason",
+                None,
+                "add a reason with `= \"..\"`",
+            );
+        }
     }
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &'_ ast::Item) {
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 7fa23dad698..a9b6b369c4c 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -52,6 +52,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO,
     crate::attrs::DEPRECATED_SEMVER_INFO,
     crate::attrs::DUPLICATED_ATTRIBUTES_INFO,
+    crate::attrs::IGNORE_WITHOUT_REASON_INFO,
     crate::attrs::INLINE_ALWAYS_INFO,
     crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO,
     crate::attrs::NON_MINIMAL_CFG_INFO,
diff --git a/tests/ui/ignore_without_reason.rs b/tests/ui/ignore_without_reason.rs
new file mode 100644
index 00000000000..eb8aaf179be
--- /dev/null
+++ b/tests/ui/ignore_without_reason.rs
@@ -0,0 +1,14 @@
+#![warn(clippy::ignore_without_reason)]
+
+fn main() {}
+
+#[test]
+fn unignored_test() {}
+
+#[test]
+#[ignore = "Some good reason"]
+fn ignored_with_reason() {}
+
+#[test]
+#[ignore]
+fn ignored_without_reason() {}
diff --git a/tests/ui/ignore_without_reason.stderr b/tests/ui/ignore_without_reason.stderr
new file mode 100644
index 00000000000..4c0210c2bbc
--- /dev/null
+++ b/tests/ui/ignore_without_reason.stderr
@@ -0,0 +1,12 @@
+error: `#[ignore]` without reason
+  --> tests/ui/ignore_without_reason.rs:13:1
+   |
+LL | #[ignore]
+   | ^^^^^^^^^
+   |
+   = help: add a reason with `= ".."`
+   = note: `-D clippy::ignore-without-reason` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ignore_without_reason)]`
+
+error: aborting due to 1 previous error
+