diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs index 4ea13f649..24edf6d84 100644 --- a/clippy_lints/src/attrs.rs +++ b/clippy_lints/src/attrs.rs @@ -172,12 +172,12 @@ declare_clippy_lint! { /// **What it does:** Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it /// with `#[rustfmt::skip]`. /// -/// **Why is this bad?** Since tool_attributes (rust-lang/rust#44690) are stable now, they should -/// be used instead of the old `cfg_attr(rustfmt)` attribute. +/// **Why is this bad?** Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690)) +/// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes. /// -/// **Known problems:** It currently only detects outer attributes. But since it does not really -/// makes sense to have `#![cfg_attr(rustfmt, rustfmt_skip)]` as an inner attribute, this should be -/// ok. +/// **Known problems:** This lint doesn't detect crate level inner attributes, because they get +/// processed before the PreExpansionPass lints get executed. See +/// [#3123](https://github.com/rust-lang-nursery/rust-clippy/pull/3123#issuecomment-422321765) /// /// **Example:** /// @@ -495,3 +495,46 @@ fn is_present_in_source(cx: &LateContext<'_, '_>, span: Span) -> bool { } true } + +#[derive(Copy, Clone)] +pub struct CfgAttrPass; + +impl LintPass for CfgAttrPass { + fn get_lints(&self) -> LintArray { + lint_array!( + DEPRECATED_CFG_ATTR, + ) + } +} + +impl EarlyLintPass for CfgAttrPass { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { + if_chain! { + // check cfg_attr + if attr.name() == "cfg_attr"; + if let Some(ref items) = attr.meta_item_list(); + if items.len() == 2; + // check for `rustfmt` + if let Some(feature_item) = items[0].meta_item(); + if feature_item.name() == "rustfmt"; + // check for `rustfmt_skip` + if let Some(skip_item) = &items[1].meta_item(); + if skip_item.name() == "rustfmt_skip"; + then { + let attr_style = match attr.style { + AttrStyle::Outer => "#[", + AttrStyle::Inner => "#![", + }; + span_lint_and_sugg( + cx, + DEPRECATED_CFG_ATTR, + attr.span, + "`cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes", + "use", + format!("{}rustfmt::skip]", attr_style), + ); + } + } + } +} +