summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
blob: d609a5ca4d4653fcadcdd476ec1a181cbd349235 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! checks for `#[inline]` on trait methods without bodies

use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::sugg::DiagnosticExt;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Symbol};

declare_clippy_lint! {
    /// ### What it does
    /// Checks for `#[inline]` on trait methods without bodies
    ///
    /// ### Why is this bad?
    /// Only implementations of trait methods may be inlined.
    /// The inline attribute is ignored for trait methods without bodies.
    ///
    /// ### Example
    /// ```rust
    /// trait Animal {
    ///     #[inline]
    ///     fn name(&self) -> &'static str;
    /// }
    /// ```
    #[clippy::version = "pre 1.29.0"]
    pub INLINE_FN_WITHOUT_BODY,
    correctness,
    "use of `#[inline]` on trait methods without bodies"
}

declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);

impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
        if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind {
            let attrs = cx.tcx.hir().attrs(item.hir_id());
            check_attrs(cx, item.ident.name, attrs);
        }
    }
}

fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
    for attr in attrs {
        if !attr.has_name(sym::inline) {
            continue;
        }

        span_lint_and_then(
            cx,
            INLINE_FN_WITHOUT_BODY,
            attr.span,
            &format!("use of `#[inline]` on trait method `{name}` which has no body"),
            |diag| {
                diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
            },
        );
    }
}