diff --git a/CHANGELOG.md b/CHANGELOG.md index 9490d695295d..8af4d2a9450f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -304,6 +304,7 @@ All notable changes to this project will be documented in this file. [`unused_lifetimes`]: https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes [`use_debug`]: https://github.com/Manishearth/rust-clippy/wiki#use_debug [`used_underscore_binding`]: https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding +[`useless_attribute`]: https://github.com/Manishearth/rust-clippy/wiki#useless_attribute [`useless_format`]: https://github.com/Manishearth/rust-clippy/wiki#useless_format [`useless_let_if_seq`]: https://github.com/Manishearth/rust-clippy/wiki#useless_let_if_seq [`useless_transmute`]: https://github.com/Manishearth/rust-clippy/wiki#useless_transmute diff --git a/README.md b/README.md index 93336e0f260e..a9f148d058d9 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Table of contents: ## Lints -There are 165 lints included in this crate: +There are 166 lints included in this crate: name | default | triggers on ---------------------------------------------------------------------------------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------- @@ -175,6 +175,7 @@ name [unused_lifetimes](https://github.com/Manishearth/rust-clippy/wiki#unused_lifetimes) | warn | unused lifetimes in function definitions [use_debug](https://github.com/Manishearth/rust-clippy/wiki#use_debug) | allow | use of `Debug`-based formatting [used_underscore_binding](https://github.com/Manishearth/rust-clippy/wiki#used_underscore_binding) | allow | using a binding which is prefixed with an underscore +[useless_attribute](https://github.com/Manishearth/rust-clippy/wiki#useless_attribute) | warn | use of lint attributes on `extern crate` items [useless_format](https://github.com/Manishearth/rust-clippy/wiki#useless_format) | warn | useless use of `format!` [useless_let_if_seq](https://github.com/Manishearth/rust-clippy/wiki#useless_let_if_seq) | warn | unidiomatic `let mut` declaration followed by initialization in `if` [useless_transmute](https://github.com/Manishearth/rust-clippy/wiki#useless_transmute) | warn | transmutes that have the same to and from types or could be a cast/coercion diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 0679bf50aa7e..014ace0fb45f 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -6,7 +6,7 @@ use rustc::hir::*; use semver::Version; use syntax::ast::{Attribute, Lit, LitKind, MetaItemKind}; use syntax::codemap::Span; -use utils::{in_macro, match_path, span_lint}; +use utils::{in_macro, match_path, span_lint, span_lint_and_then, snippet_opt}; use utils::paths; /// **What it does:** Checks for items annotated with `#[inline(always)]`, @@ -35,6 +35,25 @@ declare_lint! { "use of `#[inline(always)]`" } +/// **What it does:** Checks for `extern crate` and `use` items annotated with lint attributes +/// +/// **Why is this bad?** Lint attributes have no effect on crate imports. Most likely a `!` was forgotten +/// +/// **Known problems:** Technically one might allow `unused_import` on a `use` item, but it's easier to remove the unused item. +/// +/// **Example:** +/// ```rust +/// #[deny(dead_code)] +/// extern crate foo; +/// #[allow(unused_import)] +/// use foo::bar; +/// ``` +declare_lint! { + pub USELESS_ATTRIBUTE, + Warn, + "use of lint attributes on `extern crate` items" +} + /// **What it does:** Checks for `#[deprecated]` annotations with a `since` /// field that is not a valid semantic version. /// @@ -59,7 +78,7 @@ pub struct AttrPass; impl LintPass for AttrPass { fn get_lints(&self) -> LintArray { - lint_array!(INLINE_ALWAYS, DEPRECATED_SEMVER) + lint_array!(INLINE_ALWAYS, DEPRECATED_SEMVER, USELESS_ATTRIBUTE) } } @@ -83,6 +102,29 @@ impl LateLintPass for AttrPass { if is_relevant_item(item) { check_attrs(cx, item.span, &item.name, &item.attrs) } + match item.node { + ItemExternCrate(_) | + ItemUse(_) => { + for attr in &item.attrs { + if let MetaItemKind::List(ref name, _) = attr.node.value.node { + match &**name { + "allow" | "warn" | "deny" | "forbid" => { + span_lint_and_then(cx, USELESS_ATTRIBUTE, attr.span, + "useless lint attribute", + |db| { + if let Some(mut sugg) = snippet_opt(cx, attr.span) { + sugg.insert(1, '!'); + db.span_suggestion(attr.span, "if you just forgot a `!`, use", sugg); + } + }); + }, + _ => {}, + } + } + } + }, + _ => {}, + } } fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) { diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index fdd262a75e13..8c38ea7baeb7 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -308,6 +308,7 @@ pub fn register_plugins(reg: &mut rustc_plugin::Registry) { assign_ops::MISREFACTORED_ASSIGN_OP, attrs::DEPRECATED_SEMVER, attrs::INLINE_ALWAYS, + attrs::USELESS_ATTRIBUTE, bit_mask::BAD_BIT_MASK, bit_mask::INEFFECTIVE_BIT_MASK, blacklisted_name::BLACKLISTED_NAME, diff --git a/tests/compile-fail/useless_attribute.rs b/tests/compile-fail/useless_attribute.rs new file mode 100644 index 000000000000..645d7c154f1a --- /dev/null +++ b/tests/compile-fail/useless_attribute.rs @@ -0,0 +1,10 @@ +#![feature(plugin)] +#![plugin(clippy)] +#![deny(useless_attribute)] + +#[allow(dead_code)] //~ ERROR useless lint attribute +//~| HELP if you just forgot a `!`, use +//~| SUGGESTION #![allow(dead_code)] +extern crate clippy_lints; + +fn main() {}