|
12 | 12 |
|
13 | 13 | use crate::reexport::*;
|
14 | 14 | use crate::utils::{
|
15 |
| - in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, |
| 15 | + in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_sugg, |
16 | 16 | span_lint_and_then, without_block_comments,
|
17 | 17 | };
|
18 | 18 | use if_chain::if_chain;
|
19 | 19 | use crate::rustc::hir::*;
|
20 | 20 | use crate::rustc::lint::{
|
21 |
| - CheckLintNameResult, LateContext, LateLintPass, LintArray, LintContext, LintPass, |
| 21 | + CheckLintNameResult, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintContext, LintPass, |
22 | 22 | };
|
23 | 23 | use crate::rustc::ty::{self, TyCtxt};
|
24 | 24 | use crate::rustc::{declare_tool_lint, lint_array};
|
@@ -169,6 +169,35 @@ declare_clippy_lint! {
|
169 | 169 | "unknown_lints for scoped Clippy lints"
|
170 | 170 | }
|
171 | 171 |
|
| 172 | +/// **What it does:** Checks for `#[cfg_attr(rustfmt, rustfmt_skip)]` and suggests to replace it |
| 173 | +/// with `#[rustfmt::skip]`. |
| 174 | +/// |
| 175 | +/// **Why is this bad?** Since tool_attributes ([rust-lang/rust#44690](https://github.com/rust-lang/rust/issues/44690)) |
| 176 | +/// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes. |
| 177 | +/// |
| 178 | +/// **Known problems:** This lint doesn't detect crate level inner attributes, because they get |
| 179 | +/// processed before the PreExpansionPass lints get executed. See |
| 180 | +/// [#3123](https://github.com/rust-lang-nursery/rust-clippy/pull/3123#issuecomment-422321765) |
| 181 | +/// |
| 182 | +/// **Example:** |
| 183 | +/// |
| 184 | +/// Bad: |
| 185 | +/// ```rust |
| 186 | +/// #[cfg_attr(rustfmt, rustfmt_skip)] |
| 187 | +/// fn main() { } |
| 188 | +/// ``` |
| 189 | +/// |
| 190 | +/// Good: |
| 191 | +/// ```rust |
| 192 | +/// #[rustfmt::skip] |
| 193 | +/// fn main() { } |
| 194 | +/// ``` |
| 195 | +declare_clippy_lint! { |
| 196 | + pub DEPRECATED_CFG_ATTR, |
| 197 | + complexity, |
| 198 | + "usage of `cfg_attr(rustfmt)` instead of `tool_attributes`" |
| 199 | +} |
| 200 | + |
172 | 201 | #[derive(Copy, Clone)]
|
173 | 202 | pub struct AttrPass;
|
174 | 203 |
|
@@ -466,3 +495,46 @@ fn is_present_in_source(cx: &LateContext<'_, '_>, span: Span) -> bool {
|
466 | 495 | }
|
467 | 496 | true
|
468 | 497 | }
|
| 498 | + |
| 499 | +#[derive(Copy, Clone)] |
| 500 | +pub struct CfgAttrPass; |
| 501 | + |
| 502 | +impl LintPass for CfgAttrPass { |
| 503 | + fn get_lints(&self) -> LintArray { |
| 504 | + lint_array!( |
| 505 | + DEPRECATED_CFG_ATTR, |
| 506 | + ) |
| 507 | + } |
| 508 | +} |
| 509 | + |
| 510 | +impl EarlyLintPass for CfgAttrPass { |
| 511 | + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { |
| 512 | + if_chain! { |
| 513 | + // check cfg_attr |
| 514 | + if attr.name() == "cfg_attr"; |
| 515 | + if let Some(ref items) = attr.meta_item_list(); |
| 516 | + if items.len() == 2; |
| 517 | + // check for `rustfmt` |
| 518 | + if let Some(feature_item) = items[0].meta_item(); |
| 519 | + if feature_item.name() == "rustfmt"; |
| 520 | + // check for `rustfmt_skip` and `rustfmt::skip` |
| 521 | + if let Some(skip_item) = &items[1].meta_item(); |
| 522 | + if skip_item.name() == "rustfmt_skip" || skip_item.name() == "skip"; |
| 523 | + then { |
| 524 | + let attr_style = match attr.style { |
| 525 | + AttrStyle::Outer => "#[", |
| 526 | + AttrStyle::Inner => "#![", |
| 527 | + }; |
| 528 | + span_lint_and_sugg( |
| 529 | + cx, |
| 530 | + DEPRECATED_CFG_ATTR, |
| 531 | + attr.span, |
| 532 | + "`cfg_attr` is deprecated for rustfmt and got replaced by tool_attributes", |
| 533 | + "use", |
| 534 | + format!("{}rustfmt::skip]", attr_style), |
| 535 | + ); |
| 536 | + } |
| 537 | + } |
| 538 | + } |
| 539 | +} |
| 540 | + |
0 commit comments