• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use ast::{AttrStyle, Attribute};
2 use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro};
3 use rustc_ast as ast;
4 use rustc_errors::Applicability;
5 use rustc_lint::{LateContext, LateLintPass, LintContext};
6 use rustc_middle::lint::in_external_macro;
7 use rustc_session::{declare_lint_pass, declare_tool_lint};
8 
9 declare_clippy_lint! {
10     /// Checks for usage of the `#[allow]` attribute and suggests replacing it with
11     /// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
12     ///
13     /// The expect attribute is still unstable and requires the `lint_reasons`
14     /// on nightly. It can be enabled by adding `#![feature(lint_reasons)]` to
15     /// the crate root.
16     ///
17     /// This lint only warns outer attributes (`#[allow]`), as inner attributes
18     /// (`#![allow]`) are usually used to enable or disable lints on a global scale.
19     ///
20     /// ### Why is this bad?
21     ///
22     /// `#[expect]` attributes suppress the lint emission, but emit a warning, if
23     /// the expectation is unfulfilled. This can be useful to be notified when the
24     /// lint is no longer triggered.
25     ///
26     /// ### Example
27     /// ```rust,ignore
28     /// #[allow(unused_mut)]
29     /// fn foo() -> usize {
30     ///    let mut a = Vec::new();
31     ///    a.len()
32     /// }
33     /// ```
34     /// Use instead:
35     /// ```rust,ignore
36     /// #![feature(lint_reasons)]
37     /// #[expect(unused_mut)]
38     /// fn foo() -> usize {
39     ///     let mut a = Vec::new();
40     ///     a.len()
41     /// }
42     /// ```
43     #[clippy::version = "1.70.0"]
44     pub ALLOW_ATTRIBUTES,
45     restriction,
46     "`#[allow]` will not trigger if a warning isn't found. `#[expect]` triggers if there are no warnings."
47 }
48 
49 declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]);
50 
51 impl LateLintPass<'_> for AllowAttribute {
52     // Separate each crate's features.
check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute)53     fn check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute) {
54         if_chain! {
55             if !in_external_macro(cx.sess(), attr.span);
56             if cx.tcx.features().lint_reasons;
57             if let AttrStyle::Outer = attr.style;
58             if let Some(ident) = attr.ident();
59             if ident.name == rustc_span::symbol::sym::allow;
60             if !is_from_proc_macro(cx, &attr);
61             then {
62                 span_lint_and_sugg(
63                     cx,
64                     ALLOW_ATTRIBUTES,
65                     ident.span,
66                     "#[allow] attribute found",
67                     "replace it with",
68                     "expect".into(),
69                     Applicability::MachineApplicable,
70                 );
71             }
72         }
73     }
74 }
75