diff --git a/CHANGELOG.md b/CHANGELOG.md index 77e9babf9d4..7af39eda8ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 index 00000000000..f2b75608674 --- /dev/null +++ b/clippy_lints/src/inline_fn_without_body.rs @@ -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), + ); + } +} diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 11afefd6d4b..68ef021e76d 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -109,6 +109,7 @@ pub mod identity_op; 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 index 00000000000..c5f9f914d33 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 index 00000000000..aa50d7c96c6 --- /dev/null +++ b/tests/ui/inline_fn_without_body.rs @@ -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 index 00000000000..1f4b4afb264 --- /dev/null +++ b/tests/ui/inline_fn_without_body.stderr @@ -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)] + | ^^^^^^^^^^^^^^^^^ +