|
13 | 13 | use crate::reexport::*;
|
14 | 14 | use crate::utils::{
|
15 | 15 | in_macro, last_line_of_span, match_def_path, opt_def_id, paths, snippet_opt, span_lint, span_lint_and_then,
|
16 |
| - without_block_comments, |
| 16 | + span_lint_and_sugg, without_block_comments, |
17 | 17 | };
|
18 | 18 | use crate::rustc::hir::*;
|
19 |
| -use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass}; |
| 19 | +use crate::rustc::lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintArray, LintPass}; |
20 | 20 | use crate::rustc::{declare_tool_lint, lint_array};
|
21 | 21 | use if_chain::if_chain;
|
22 | 22 | use crate::rustc::ty::{self, TyCtxt};
|
@@ -138,6 +138,19 @@ declare_clippy_lint! {
|
138 | 138 | "empty line after outer attribute"
|
139 | 139 | }
|
140 | 140 |
|
| 141 | +/// **What it does:** |
| 142 | +/// |
| 143 | +/// **Why is this bad?** |
| 144 | +/// |
| 145 | +/// **Known problems:** |
| 146 | +/// |
| 147 | +/// **Example:** |
| 148 | +declare_clippy_lint! { |
| 149 | + pub DEPRECATED_CFG_ATTR, |
| 150 | + complexity, |
| 151 | + "usage of `cfg_attr` instead of `tool_lints`" |
| 152 | +} |
| 153 | + |
141 | 154 | #[derive(Copy, Clone)]
|
142 | 155 | pub struct AttrPass;
|
143 | 156 |
|
@@ -387,3 +400,63 @@ fn is_present_in_source(cx: &LateContext<'_, '_>, span: Span) -> bool {
|
387 | 400 | }
|
388 | 401 | true
|
389 | 402 | }
|
| 403 | + |
| 404 | +#[derive(Copy, Clone)] |
| 405 | +pub struct CfgAttrPass; |
| 406 | + |
| 407 | +impl LintPass for CfgAttrPass { |
| 408 | + fn get_lints(&self) -> LintArray { |
| 409 | + lint_array!( |
| 410 | + DEPRECATED_CFG_ATTR, |
| 411 | + ) |
| 412 | + } |
| 413 | +} |
| 414 | + |
| 415 | +impl EarlyLintPass for CfgAttrPass { |
| 416 | + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { |
| 417 | + if_chain! { |
| 418 | + // check cfg_attr |
| 419 | + if attr.name() == "cfg_attr"; |
| 420 | + if let Some(ref items) = attr.meta_item_list(); |
| 421 | + if items.len() == 2; |
| 422 | + // check for `feature = "cargo-clippy"` |
| 423 | + if let Some(feature_item) = items[0].meta_item(); |
| 424 | + if let Some(value) = feature_item.value_str(); |
| 425 | + if value == "cargo-clippy"; |
| 426 | + // check for `allow(..)`/... and retrieve the lints |
| 427 | + let level = &items[1]; |
| 428 | + if let Some(name) = level.name(); |
| 429 | + if name == "allow" || name == "warn" || name == "deny" || name == "forbid"; |
| 430 | + if let Some(level_items) = level.meta_item_list(); |
| 431 | + if level_items.iter().all(|item| { |
| 432 | + if let Some(meta_item) = item.meta_item() { |
| 433 | + meta_item.is_word() |
| 434 | + } else { |
| 435 | + false |
| 436 | + } |
| 437 | + }); |
| 438 | + then { |
| 439 | + let attr_style = match attr.style { |
| 440 | + AttrStyle::Outer => "#[", |
| 441 | + AttrStyle::Inner => "#![", |
| 442 | + }; |
| 443 | + let level = name.as_str(); |
| 444 | + let mut lints = level_items.iter().fold(String::new(), |acc, item| { |
| 445 | + acc + &format!("clippy::{}, ", item.name().unwrap().as_str()) |
| 446 | + }); |
| 447 | + let lints_len = lints.len(); |
| 448 | + lints.truncate(lints_len - 2); |
| 449 | + let sugg = format!("{}{}({})]", attr_style, level, lints); |
| 450 | + span_lint_and_sugg( |
| 451 | + cx, |
| 452 | + DEPRECATED_CFG_ATTR, |
| 453 | + attr.span, |
| 454 | + "`cfg_attr` is deprecated for clippy and got replaced by tool_lints", |
| 455 | + "use", |
| 456 | + sugg, |
| 457 | + ); |
| 458 | + } |
| 459 | + } |
| 460 | + } |
| 461 | +} |
| 462 | + |
0 commit comments