]> git.lizzy.rs Git - rust.git/commitdiff
Lint for trait methods without bodies
authorRyan Cumming <etaoins@gmail.com>
Wed, 17 Jan 2018 09:41:24 +0000 (20:41 +1100)
committerRyan Cumming <etaoins@gmail.com>
Thu, 18 Jan 2018 09:01:24 +0000 (20:01 +1100)
As discussed in rust-lang/rust#47475 the #[inline] attribute is
currently allowed on trait methods without bodies (i.e. without a
default implementation). This is misleading as it could be interpreted
as affecting the implementations of the trait method. Add a lint for any
use of #[inline] on a trait method without a body.

Fixes rust-lang/rust#47475

CHANGELOG.md
clippy_lints/src/inline_fn_without_body.rs [new file with mode: 0644]
clippy_lints/src/lib.rs
main [new file with mode: 0755]
tests/ui/inline_fn_without_body.rs [new file with mode: 0644]
tests/ui/inline_fn_without_body.stderr [new file with mode: 0644]

index 77e9babf9d4a5a6441d7458b18d09edf4d0928fa..7af39eda8ec10291c0e03feb8fcfe54030687c9e 100644 (file)
@@ -583,6 +583,7 @@ All notable changes to this project will be documented in this file.
 [`ineffective_bit_mask`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#ineffective_bit_mask
 [`infinite_iter`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#infinite_iter
 [`inline_always`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_always
+[`inline_fn_without_body`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#inline_fn_without_body
 [`int_plus_one`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#int_plus_one
 [`integer_arithmetic`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#integer_arithmetic
 [`invalid_ref`]: https://rust-lang-nursery.github.io/rust-clippy/master/index.html#invalid_ref
diff --git a/clippy_lints/src/inline_fn_without_body.rs b/clippy_lints/src/inline_fn_without_body.rs
new file mode 100644 (file)
index 0000000..f2b7560
--- /dev/null
@@ -0,0 +1,61 @@
+//! checks for `#[inline]` on trait methods without bodies
+
+use rustc::lint::*;
+use rustc::hir::*;
+use syntax::ast::{Attribute, Name};
+use utils::span_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.
+///
+/// **Known problems:** None.
+///
+/// **Example:**
+/// ```rust
+/// trait Animal {
+///     #[inline]
+///     fn name(&self) -> &'static str;
+/// }
+/// ```
+declare_lint! {
+    pub INLINE_FN_WITHOUT_BODY,
+    Warn,
+    "use of `#[inline]` on trait methods without bodies"
+}
+
+#[derive(Copy, Clone)]
+pub struct Pass;
+
+impl LintPass for Pass {
+    fn get_lints(&self) -> LintArray {
+        lint_array!(INLINE_FN_WITHOUT_BODY)
+    }
+}
+
+impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
+    fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx TraitItem) {
+        match item.node {
+            TraitItemKind::Method(_, TraitMethod::Required(_)) => {
+                check_attrs(cx, &item.name, &item.attrs);
+            },
+            _ => {},
+        }
+    }
+}
+
+fn check_attrs(cx: &LateContext, name: &Name, attrs: &[Attribute]) {
+    for attr in attrs {
+        if attr.name().map_or(true, |n| n != "inline") {
+            continue;
+        }
+
+        span_lint(
+            cx,
+            INLINE_FN_WITHOUT_BODY,
+            attr.span,
+            &format!("use of `#[inline]` on trait method `{}` which has no body", name),
+        );
+    }
+}
index 11afefd6d4be6e5cf3fd1d590488898b3e0b383a..68ef021e76dc8e5cdf84bca49ca9c4256d5f63f5 100644 (file)
@@ -109,6 +109,7 @@ macro_rules! declare_restriction_lint {
 pub mod if_let_redundant_pattern_matching;
 pub mod if_not_else;
 pub mod infinite_iter;
+pub mod inline_fn_without_body;
 pub mod int_plus_one;
 pub mod invalid_ref;
 pub mod is_unit_expr;
@@ -359,6 +360,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
     reg.register_late_lint_pass(box use_self::UseSelf);
     reg.register_late_lint_pass(box bytecount::ByteCount);
     reg.register_late_lint_pass(box infinite_iter::Pass);
+    reg.register_late_lint_pass(box inline_fn_without_body::Pass);
     reg.register_late_lint_pass(box invalid_ref::InvalidRef);
     reg.register_late_lint_pass(box identity_conversion::IdentityConversion::default());
     reg.register_late_lint_pass(box types::ImplicitHasher);
@@ -477,6 +479,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) {
         identity_op::IDENTITY_OP,
         if_let_redundant_pattern_matching::IF_LET_REDUNDANT_PATTERN_MATCHING,
         infinite_iter::INFINITE_ITER,
+        inline_fn_without_body::INLINE_FN_WITHOUT_BODY,
         invalid_ref::INVALID_REF,
         is_unit_expr::UNIT_EXPR,
         large_enum_variant::LARGE_ENUM_VARIANT,
diff --git a/main b/main
new file mode 100755 (executable)
index 0000000..c5f9f91
Binary files /dev/null and b/main differ
diff --git a/tests/ui/inline_fn_without_body.rs b/tests/ui/inline_fn_without_body.rs
new file mode 100644 (file)
index 0000000..aa50d7c
--- /dev/null
@@ -0,0 +1,18 @@
+
+
+
+#![warn(inline_fn_without_body)]
+#![allow(inline_always)]
+trait Foo {
+    #[inline]
+    fn default_inline();
+
+    #[inline(always)]
+    fn always_inline();
+
+    #[inline]
+    fn has_body() {
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/inline_fn_without_body.stderr b/tests/ui/inline_fn_without_body.stderr
new file mode 100644 (file)
index 0000000..1f4b4af
--- /dev/null
@@ -0,0 +1,14 @@
+error: use of `#[inline]` on trait method `default_inline` which has no body
+ --> $DIR/inline_fn_without_body.rs:7:5
+  |
+7 |     #[inline]
+  |     ^^^^^^^^^
+  |
+  = note: `-D inline-fn-without-body` implied by `-D warnings`
+
+error: use of `#[inline]` on trait method `always_inline` which has no body
+  --> $DIR/inline_fn_without_body.rs:10:5
+   |
+10 |     #[inline(always)]
+   |     ^^^^^^^^^^^^^^^^^
+