Add new duplicated_attributes
lint
This commit is contained in:
parent
453242cbde
commit
f34804d807
@ -5157,6 +5157,7 @@ Released 2018-09-13
|
|||||||
[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
|
[`drop_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#drop_ref
|
||||||
[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
|
[`duplicate_mod`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_mod
|
||||||
[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
|
[`duplicate_underscore_argument`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicate_underscore_argument
|
||||||
|
[`duplicated_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicated_attributes
|
||||||
[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
|
[`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec
|
||||||
[`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute
|
[`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute
|
||||||
[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
|
[`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else
|
||||||
|
64
clippy_lints/src/attrs/duplicated_attributes.rs
Normal file
64
clippy_lints/src/attrs/duplicated_attributes.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use super::DUPLICATED_ATTRIBUTES;
|
||||||
|
use clippy_utils::diagnostics::span_lint_and_then;
|
||||||
|
use rustc_ast::{Attribute, MetaItem};
|
||||||
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
|
use rustc_lint::EarlyContext;
|
||||||
|
use rustc_span::{sym, Span};
|
||||||
|
use std::collections::hash_map::Entry;
|
||||||
|
|
||||||
|
fn emit_if_duplicated(
|
||||||
|
cx: &EarlyContext<'_>,
|
||||||
|
attr: &MetaItem,
|
||||||
|
attr_paths: &mut FxHashMap<String, Span>,
|
||||||
|
complete_path: String,
|
||||||
|
) {
|
||||||
|
match attr_paths.entry(complete_path) {
|
||||||
|
Entry::Vacant(v) => {
|
||||||
|
v.insert(attr.span);
|
||||||
|
},
|
||||||
|
Entry::Occupied(o) => {
|
||||||
|
span_lint_and_then(cx, DUPLICATED_ATTRIBUTES, attr.span, "duplicated attribute", |diag| {
|
||||||
|
diag.span_note(*o.get(), "first defined here");
|
||||||
|
diag.span_help(attr.span, "remove this attribute");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_duplicated_attr(
|
||||||
|
cx: &EarlyContext<'_>,
|
||||||
|
attr: &MetaItem,
|
||||||
|
attr_paths: &mut FxHashMap<String, Span>,
|
||||||
|
parent: &mut Vec<String>,
|
||||||
|
) {
|
||||||
|
let Some(ident) = attr.ident() else { return };
|
||||||
|
let name = ident.name;
|
||||||
|
if name == sym::doc || name == sym::cfg_attr {
|
||||||
|
// FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg
|
||||||
|
// conditions are the same.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if let Some(value) = attr.value_str() {
|
||||||
|
emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":")));
|
||||||
|
} else if let Some(sub_attrs) = attr.meta_item_list() {
|
||||||
|
parent.push(name.as_str().to_string());
|
||||||
|
for sub_attr in sub_attrs {
|
||||||
|
if let Some(meta) = sub_attr.meta_item() {
|
||||||
|
check_duplicated_attr(cx, meta, attr_paths, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parent.pop();
|
||||||
|
} else {
|
||||||
|
emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.join(":")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
|
||||||
|
let mut attr_paths = FxHashMap::default();
|
||||||
|
|
||||||
|
for attr in attrs {
|
||||||
|
if let Some(meta) = attr.meta() {
|
||||||
|
check_duplicated_attr(cx, &meta, &mut attr_paths, &mut Vec::new());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ mod allow_attributes_without_reason;
|
|||||||
mod blanket_clippy_restriction_lints;
|
mod blanket_clippy_restriction_lints;
|
||||||
mod deprecated_cfg_attr;
|
mod deprecated_cfg_attr;
|
||||||
mod deprecated_semver;
|
mod deprecated_semver;
|
||||||
|
mod duplicated_attributes;
|
||||||
mod empty_line_after;
|
mod empty_line_after;
|
||||||
mod inline_always;
|
mod inline_always;
|
||||||
mod maybe_misused_cfg;
|
mod maybe_misused_cfg;
|
||||||
@ -16,7 +17,7 @@ mod useless_attribute;
|
|||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use clippy_config::msrvs::Msrv;
|
use clippy_config::msrvs::Msrv;
|
||||||
use rustc_ast::{Attribute, MetaItemKind, NestedMetaItem};
|
use rustc_ast::{Attribute, Crate, MetaItemKind, NestedMetaItem};
|
||||||
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
|
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
|
||||||
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
|
||||||
use rustc_session::{declare_lint_pass, impl_lint_pass};
|
use rustc_session::{declare_lint_pass, impl_lint_pass};
|
||||||
@ -489,6 +490,32 @@ declare_clippy_lint! {
|
|||||||
"item has both inner and outer attributes"
|
"item has both inner and outer attributes"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare_clippy_lint! {
|
||||||
|
/// ### What it does
|
||||||
|
/// Checks for attributes that appear two or more times.
|
||||||
|
///
|
||||||
|
/// ### Why is this bad?
|
||||||
|
/// Repeating an attribute on the same item (or globally on the same crate)
|
||||||
|
/// is unnecessary and doesn't have an effect.
|
||||||
|
///
|
||||||
|
/// ### Example
|
||||||
|
/// ```no_run
|
||||||
|
/// #[allow(dead_code)]
|
||||||
|
/// #[allow(dead_code)]
|
||||||
|
/// fn foo() {}
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```no_run
|
||||||
|
/// #[allow(dead_code)]
|
||||||
|
/// fn foo() {}
|
||||||
|
/// ```
|
||||||
|
#[clippy::version = "1.78.0"]
|
||||||
|
pub DUPLICATED_ATTRIBUTES,
|
||||||
|
suspicious,
|
||||||
|
"duplicated attribute"
|
||||||
|
}
|
||||||
|
|
||||||
declare_lint_pass!(Attributes => [
|
declare_lint_pass!(Attributes => [
|
||||||
ALLOW_ATTRIBUTES_WITHOUT_REASON,
|
ALLOW_ATTRIBUTES_WITHOUT_REASON,
|
||||||
INLINE_ALWAYS,
|
INLINE_ALWAYS,
|
||||||
@ -568,12 +595,18 @@ impl_lint_pass!(EarlyAttributes => [
|
|||||||
DEPRECATED_CLIPPY_CFG_ATTR,
|
DEPRECATED_CLIPPY_CFG_ATTR,
|
||||||
UNNECESSARY_CLIPPY_CFG,
|
UNNECESSARY_CLIPPY_CFG,
|
||||||
MIXED_ATTRIBUTES_STYLE,
|
MIXED_ATTRIBUTES_STYLE,
|
||||||
|
DUPLICATED_ATTRIBUTES,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
impl EarlyLintPass for EarlyAttributes {
|
impl EarlyLintPass for EarlyAttributes {
|
||||||
|
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
|
||||||
|
duplicated_attributes::check(cx, &krate.attrs);
|
||||||
|
}
|
||||||
|
|
||||||
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
|
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &rustc_ast::Item) {
|
||||||
empty_line_after::check(cx, item);
|
empty_line_after::check(cx, item);
|
||||||
mixed_attributes_style::check(cx, item);
|
mixed_attributes_style::check(cx, item);
|
||||||
|
duplicated_attributes::check(cx, &item.attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
|
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
|
||||||
|
@ -54,6 +54,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
|
|||||||
crate::attrs::DEPRECATED_CFG_ATTR_INFO,
|
crate::attrs::DEPRECATED_CFG_ATTR_INFO,
|
||||||
crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO,
|
crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO,
|
||||||
crate::attrs::DEPRECATED_SEMVER_INFO,
|
crate::attrs::DEPRECATED_SEMVER_INFO,
|
||||||
|
crate::attrs::DUPLICATED_ATTRIBUTES_INFO,
|
||||||
crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
|
crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
|
||||||
crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
|
crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
|
||||||
crate::attrs::INLINE_ALWAYS_INFO,
|
crate::attrs::INLINE_ALWAYS_INFO,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user