Skip to content

Commit ac2220f

Browse files
committed
Remove the pre-expansion pass
1 parent 0029a91 commit ac2220f

19 files changed

+635
-273
lines changed
Lines changed: 82 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,66 @@
1-
use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg};
2-
use clippy_utils::diagnostics::span_lint_and_sugg;
1+
use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR};
2+
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
33
use clippy_utils::msrvs::{self, MsrvStack};
44
use clippy_utils::sym;
55
use rustc_ast::AttrStyle;
66
use rustc_errors::Applicability;
7-
use rustc_lint::EarlyContext;
7+
use rustc_hir::attrs::CfgEntry;
8+
use rustc_hir::def_id::{LOCAL_CRATE, LocalDefId};
9+
use rustc_lint::{EarlyContext, LateContext};
810

9-
pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) {
11+
pub(super) fn check_rustfmt(cx: &EarlyContext<'_>, attrs: &[Attribute], msrv: &MsrvStack) {
12+
for attr in attrs {
13+
check_rustfmt_attr(cx, attr, msrv);
14+
}
15+
}
16+
17+
fn check_rustfmt_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) {
1018
// check cfg_attr
11-
if attr.has_name(sym::cfg_attr)
19+
if attr.has_name(sym::cfg_attr_trace)
1220
&& let Some(items) = attr.meta_item_list()
1321
&& items.len() == 2
1422
&& let Some(feature_item) = items[0].meta_item()
15-
{
1623
// check for `rustfmt`
17-
if feature_item.has_name(sym::rustfmt)
18-
&& msrv.meets(msrvs::TOOL_ATTRIBUTES)
19-
// check for `rustfmt_skip` and `rustfmt::skip`
20-
&& let Some(skip_item) = &items[1].meta_item()
21-
&& (skip_item.has_name(sym::rustfmt_skip)
22-
|| skip_item
23-
.path
24-
.segments
25-
.last()
26-
.expect("empty path in attribute")
27-
.ident
28-
.name
29-
== sym::skip)
30-
// Only lint outer attributes, because custom inner attributes are unstable
31-
// Tracking issue: https://github.com/rust-lang/rust/issues/54726
32-
&& attr.style == AttrStyle::Outer
33-
{
34-
span_lint_and_sugg(
35-
cx,
36-
DEPRECATED_CFG_ATTR,
37-
attr.span,
38-
"`cfg_attr` is deprecated for rustfmt and got replaced by tool attributes",
39-
"use",
40-
"#[rustfmt::skip]".to_string(),
41-
Applicability::MachineApplicable,
42-
);
43-
} else {
44-
check_deprecated_cfg_recursively(cx, feature_item);
45-
if let Some(behind_cfg_attr) = items[1].meta_item() {
46-
unnecessary_clippy_cfg::check(cx, feature_item, behind_cfg_attr, attr);
47-
}
48-
}
49-
}
50-
}
51-
52-
pub(super) fn check_clippy(cx: &EarlyContext<'_>, attr: &Attribute) {
53-
if attr.has_name(sym::cfg)
54-
&& let Some(list) = attr.meta_item_list()
24+
&& feature_item.has_name(sym::rustfmt)
25+
&& msrv.meets(msrvs::TOOL_ATTRIBUTES)
26+
// check for `rustfmt_skip` and `rustfmt::skip`
27+
&& let Some(skip_item) = &items[1].meta_item()
28+
&& (skip_item.has_name(sym::rustfmt_skip)
29+
|| skip_item
30+
.path
31+
.segments
32+
.last()
33+
.expect("empty path in attribute")
34+
.ident
35+
.name
36+
== sym::skip)
37+
// Only lint outer attributes, because custom inner attributes are unstable
38+
// Tracking issue: https://github.com/rust-lang/rust/issues/54726
39+
&& attr.style == AttrStyle::Outer
5540
{
56-
for item in list.iter().filter_map(|item| item.meta_item()) {
57-
check_deprecated_cfg_recursively(cx, item);
58-
}
41+
span_lint_and_then(
42+
cx,
43+
DEPRECATED_CFG_ATTR,
44+
attr.span,
45+
"`cfg_attr` is deprecated for rustfmt",
46+
|diag| {
47+
diag.span_suggestion_verbose(
48+
attr.span,
49+
"use the `rustfmt::skip` tool attribute instead",
50+
"#[rustfmt::skip]",
51+
Applicability::MachineApplicable,
52+
);
53+
},
54+
);
5955
}
6056
}
6157

62-
fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::MetaItem) {
58+
pub(super) fn check(cx: &EarlyContext<'_>, attr: &rustc_ast::MetaItem) {
6359
if let Some(ident) = attr.ident() {
6460
if matches!(ident.name, sym::any | sym::all | sym::not) {
6561
let Some(list) = attr.meta_item_list() else { return };
6662
for item in list.iter().filter_map(|item| item.meta_item()) {
67-
check_deprecated_cfg_recursively(cx, item);
63+
check(cx, item);
6864
}
6965
} else {
7066
check_cargo_clippy_attr(cx, attr);
@@ -85,3 +81,40 @@ fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) {
8581
);
8682
}
8783
}
84+
85+
pub fn check_stripped(cx: &LateContext<'_>) {
86+
for stripped in cx.tcx.stripped_cfg_items(LOCAL_CRATE) {
87+
if let Some(parent_module) = stripped.parent_module.as_local() {
88+
check_cfg_entry(cx, &stripped.cfg.0, parent_module);
89+
}
90+
}
91+
}
92+
93+
fn check_cfg_entry(cx: &LateContext<'_>, cfg: &CfgEntry, parent_module: LocalDefId) {
94+
match cfg {
95+
&CfgEntry::NameValue {
96+
name: sym::feature,
97+
name_span: _,
98+
value: Some((sym::cargo_clippy, _)),
99+
span,
100+
} => {
101+
span_lint_hir_and_then(
102+
cx,
103+
DEPRECATED_CLIPPY_CFG_ATTR,
104+
cx.tcx.local_def_id_to_hir_id(parent_module),
105+
span,
106+
"`feature = \"cargo-clippy\"` was replaced by `clippy`",
107+
|diag| {
108+
diag.span_suggestion(span, "replace with", "clippy", Applicability::MachineApplicable);
109+
},
110+
);
111+
},
112+
CfgEntry::All(children, _) | CfgEntry::Any(children, _) => {
113+
for child in children {
114+
check_cfg_entry(cx, child, parent_module);
115+
}
116+
},
117+
CfgEntry::Not(child, _) => check_cfg_entry(cx, child, parent_module),
118+
_ => {},
119+
}
120+
}

clippy_lints/src/attrs/mod.rs

Lines changed: 73 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -160,9 +160,11 @@ declare_clippy_lint! {
160160
/// are stable now, they should be used instead of the old `cfg_attr(rustfmt)` attributes.
161161
///
162162
/// ### Known problems
163-
/// This lint doesn't detect crate level inner attributes, because they get
164-
/// processed before the PreExpansionPass lints get executed. See
165-
/// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
163+
/// Does not detect attributes applied to macro invocations such as
164+
/// ```no_run
165+
/// #[cfg_attr(rustfmt, rustfmt_skip)]
166+
/// println!("..");
167+
/// ```
166168
///
167169
/// ### Example
168170
/// ```no_run
@@ -314,11 +316,16 @@ declare_clippy_lint! {
314316

315317
declare_clippy_lint! {
316318
/// ### What it does
317-
/// Checks for `any` and `all` combinators in `cfg` with only one condition.
319+
/// Checks for `any` and `all` combinators in `cfg` or `cfg_attr` with only one condition.
318320
///
319321
/// ### Why is this bad?
320322
/// If there is only one condition, no need to wrap it into `any` or `all` combinators.
321323
///
324+
/// ### Known Problems
325+
/// Only attributes that are attached to items included in the current compilation will be linted,
326+
/// for the examples below the lint will only fire when `Bar` is compiled - in this case when on
327+
/// a `unix` target.
328+
///
322329
/// ### Example
323330
/// ```no_run
324331
/// #[cfg(any(unix))]
@@ -474,22 +481,27 @@ declare_clippy_lint! {
474481
"ignored tests without messages"
475482
}
476483

477-
pub struct Attributes {
484+
pub struct LateAttributes {
478485
msrv: Msrv,
479486
}
480487

481-
impl_lint_pass!(Attributes => [
488+
impl_lint_pass!(LateAttributes => [
482489
INLINE_ALWAYS,
483490
REPR_PACKED_WITHOUT_ABI,
491+
DEPRECATED_CLIPPY_CFG_ATTR,
484492
]);
485493

486-
impl Attributes {
494+
impl LateAttributes {
487495
pub fn new(conf: &'static Conf) -> Self {
488496
Self { msrv: conf.msrv }
489497
}
490498
}
491499

492-
impl<'tcx> LateLintPass<'tcx> for Attributes {
500+
impl<'tcx> LateLintPass<'tcx> for LateAttributes {
501+
fn check_crate(&mut self, cx: &LateContext<'tcx>) {
502+
deprecated_cfg_attr::check_stripped(cx);
503+
}
504+
493505
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
494506
let attrs = cx.tcx.hir_attrs(item.hir_id());
495507
if let ItemKind::Fn { ident, .. } = item.kind
@@ -526,35 +538,6 @@ impl EarlyAttributes {
526538
}
527539

528540
impl_lint_pass!(EarlyAttributes => [
529-
DEPRECATED_CFG_ATTR,
530-
NON_MINIMAL_CFG,
531-
DEPRECATED_CLIPPY_CFG_ATTR,
532-
UNNECESSARY_CLIPPY_CFG,
533-
]);
534-
535-
impl EarlyLintPass for EarlyAttributes {
536-
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
537-
deprecated_cfg_attr::check(cx, attr, &self.msrv);
538-
deprecated_cfg_attr::check_clippy(cx, attr);
539-
non_minimal_cfg::check(cx, attr);
540-
}
541-
542-
extract_msrv_attr!();
543-
}
544-
545-
pub struct PostExpansionEarlyAttributes {
546-
msrv: MsrvStack,
547-
}
548-
549-
impl PostExpansionEarlyAttributes {
550-
pub fn new(conf: &'static Conf) -> Self {
551-
Self {
552-
msrv: MsrvStack::new(conf.msrv),
553-
}
554-
}
555-
}
556-
557-
impl_lint_pass!(PostExpansionEarlyAttributes => [
558541
ALLOW_ATTRIBUTES,
559542
ALLOW_ATTRIBUTES_WITHOUT_REASON,
560543
DEPRECATED_SEMVER,
@@ -564,9 +547,13 @@ impl_lint_pass!(PostExpansionEarlyAttributes => [
564547
SHOULD_PANIC_WITHOUT_EXPECT,
565548
MIXED_ATTRIBUTES_STYLE,
566549
DUPLICATED_ATTRIBUTES,
550+
DEPRECATED_CFG_ATTR,
551+
DEPRECATED_CLIPPY_CFG_ATTR,
552+
UNNECESSARY_CLIPPY_CFG,
553+
NON_MINIMAL_CFG,
567554
]);
568555

569-
impl EarlyLintPass for PostExpansionEarlyAttributes {
556+
impl EarlyLintPass for EarlyAttributes {
570557
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
571558
blanket_clippy_restriction_lints::check_command_line(cx);
572559
duplicated_attributes::check(cx, &krate.attrs);
@@ -585,6 +572,15 @@ impl EarlyLintPass for PostExpansionEarlyAttributes {
585572
if is_lint_level(ident.name, attr.id) {
586573
blanket_clippy_restriction_lints::check(cx, ident.name, items);
587574
}
575+
if matches!(ident.name, sym::cfg_trace | sym::cfg_attr_trace)
576+
&& let Some(meta_item) = items.first().and_then(|item| item.meta_item())
577+
{
578+
non_minimal_cfg::check(cx, items, &self.msrv);
579+
deprecated_cfg_attr::check(cx, meta_item);
580+
if let Some(behind_cfg) = items.get(1).and_then(|item| item.meta_item()) {
581+
unnecessary_clippy_cfg::check(cx, meta_item, behind_cfg, attr);
582+
}
583+
}
588584
if items.is_empty() || !attr.has_name(sym::deprecated) {
589585
return;
590586
}
@@ -620,14 +616,52 @@ impl EarlyLintPass for PostExpansionEarlyAttributes {
620616
}
621617

622618
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &'_ ast::Item) {
623-
match item.kind {
619+
match &item.kind {
624620
ast::ItemKind::ExternCrate(..) | ast::ItemKind::Use(..) => useless_attribute::check(cx, item, &item.attrs),
621+
ast::ItemKind::Struct(.., variant) => {
622+
for field in variant.fields() {
623+
deprecated_cfg_attr::check_rustfmt(cx, &field.attrs, &self.msrv);
624+
}
625+
},
626+
ast::ItemKind::ForeignMod(foreign) => {
627+
for item in &foreign.items {
628+
deprecated_cfg_attr::check_rustfmt(cx, &item.attrs, &self.msrv)
629+
}
630+
},
625631
_ => {},
626632
}
627633

634+
deprecated_cfg_attr::check_rustfmt(cx, &item.attrs, &self.msrv);
628635
mixed_attributes_style::check(cx, item.span, &item.attrs);
629636
duplicated_attributes::check(cx, &item.attrs);
630637
}
631638

639+
fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
640+
match &stmt.kind {
641+
ast::StmtKind::Let(local) => deprecated_cfg_attr::check_rustfmt(cx, &local.attrs, &self.msrv),
642+
ast::StmtKind::Semi(expr) => deprecated_cfg_attr::check_rustfmt(cx, &expr.attrs, &self.msrv),
643+
_ => {},
644+
}
645+
}
646+
647+
fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &ast::Arm) {
648+
deprecated_cfg_attr::check_rustfmt(cx, &arm.attrs, &self.msrv);
649+
}
650+
651+
fn check_trait_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) {
652+
deprecated_cfg_attr::check_rustfmt(cx, &item.attrs, &self.msrv);
653+
}
654+
655+
fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &ast::AssocItem) {
656+
deprecated_cfg_attr::check_rustfmt(cx, &item.attrs, &self.msrv);
657+
}
658+
659+
fn check_variant(&mut self, cx: &EarlyContext<'_>, variant: &ast::Variant) {
660+
deprecated_cfg_attr::check_rustfmt(cx, &variant.attrs, &self.msrv);
661+
for field in variant.data.fields() {
662+
deprecated_cfg_attr::check_rustfmt(cx, &field.attrs, &self.msrv);
663+
}
664+
}
665+
632666
extract_msrv_attr!();
633667
}

0 commit comments

Comments
 (0)