use ast::{AttrStyle, Attribute}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use rustc_ast as ast; use rustc_errors::Applicability; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { /// ### What it does /// Checks for usage of the `#[allow]` attribute and suggests replacing it with /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html)) /// /// The expect attribute is still unstable and requires the `lint_reasons` /// on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to /// the crate root. /// /// This lint only warns outer attributes (`#[allow]`), as inner attributes /// (`#![allow]`) are usually used to enable or disable lints on a global scale. /// /// ### Why is this bad? /// `#[expect]` attributes suppress the lint emission, but emit a warning, if /// the expectation is unfulfilled. This can be useful to be notified when the /// lint is no longer triggered. /// /// ### Example /// ```rust,ignore /// #[allow(unused_mut)] /// fn foo() -> usize { /// let mut a = Vec::new(); /// a.len() /// } /// ``` /// Use instead: /// ```rust,ignore /// #![feature(lint_reasons)] /// #[expect(unused_mut)] /// fn foo() -> usize { /// let mut a = Vec::new(); /// a.len() /// } /// ``` #[clippy::version = "1.70.0"] pub ALLOW_ATTRIBUTES, restriction, "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings." } declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]); impl LateLintPass<'_> for AllowAttribute { // Separate each crate's features. fn check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute) { if_chain! { if !in_external_macro(cx.sess(), attr.span); if cx.tcx.features().lint_reasons; if let AttrStyle::Outer = attr.style; if let Some(ident) = attr.ident(); if ident.name == rustc_span::symbol::sym::allow; if !is_from_proc_macro(cx, &attr); then { span_lint_and_sugg( cx, ALLOW_ATTRIBUTES, ident.span, "#[allow] attribute found", "replace it with", "expect".into(), Applicability::MachineApplicable, ); } } } }