Skip to content

Commit b0e7640

Browse files
committed
Auto merge of rust-lang#12267 - Jarcho:issue_12254, r=Alexendoo
Don't allow derive macros to silence `disallowed_macros` fixes rust-lang#12254 The implementation is a bit of a hack, but "works". A derive expanding to another derive won't work properly, but we shouldn't be linting those anyways. changelog: `disallowed_macros`: Don't allow derive macros to silence their own expansion
2 parents 75f57cf + ac7c6e5 commit b0e7640

File tree

5 files changed

+112
-46
lines changed

5 files changed

+112
-46
lines changed

clippy_lints/src/disallowed_macros.rs

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
use clippy_config::types::DisallowedPath;
2-
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
33
use clippy_utils::macros::macro_backtrace;
44
use rustc_ast::Attribute;
55
use rustc_data_structures::fx::FxHashSet;
6+
use rustc_errors::Diagnostic;
67
use rustc_hir::def_id::DefIdMap;
7-
use rustc_hir::{Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
8+
use rustc_hir::{
9+
Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
10+
};
811
use rustc_lint::{LateContext, LateLintPass};
912
use rustc_session::impl_lint_pass;
10-
use rustc_span::{ExpnId, Span};
13+
use rustc_span::{ExpnId, MacroKind, Span};
1114

1215
declare_clippy_lint! {
1316
/// ### What it does
@@ -57,6 +60,10 @@ pub struct DisallowedMacros {
5760
conf_disallowed: Vec<DisallowedPath>,
5861
disallowed: DefIdMap<usize>,
5962
seen: FxHashSet<ExpnId>,
63+
64+
// Track the most recently seen node that can have a `derive` attribute.
65+
// Needed to use the correct lint level.
66+
derive_src: Option<OwnerId>,
6067
}
6168

6269
impl DisallowedMacros {
@@ -65,10 +72,11 @@ impl DisallowedMacros {
6572
conf_disallowed,
6673
disallowed: DefIdMap::default(),
6774
seen: FxHashSet::default(),
75+
derive_src: None,
6876
}
6977
}
7078

71-
fn check(&mut self, cx: &LateContext<'_>, span: Span) {
79+
fn check(&mut self, cx: &LateContext<'_>, span: Span, derive_src: Option<OwnerId>) {
7280
if self.conf_disallowed.is_empty() {
7381
return;
7482
}
@@ -80,18 +88,26 @@ impl DisallowedMacros {
8088

8189
if let Some(&index) = self.disallowed.get(&mac.def_id) {
8290
let conf = &self.conf_disallowed[index];
83-
84-
span_lint_and_then(
85-
cx,
86-
DISALLOWED_MACROS,
87-
mac.span,
88-
&format!("use of a disallowed macro `{}`", conf.path()),
89-
|diag| {
90-
if let Some(reason) = conf.reason() {
91-
diag.note(reason);
92-
}
93-
},
94-
);
91+
let msg = format!("use of a disallowed macro `{}`", conf.path());
92+
let add_note = |diag: &mut Diagnostic| {
93+
if let Some(reason) = conf.reason() {
94+
diag.note(reason);
95+
}
96+
};
97+
if matches!(mac.kind, MacroKind::Derive)
98+
&& let Some(derive_src) = derive_src
99+
{
100+
span_lint_hir_and_then(
101+
cx,
102+
DISALLOWED_MACROS,
103+
cx.tcx.local_def_id_to_hir_id(derive_src.def_id),
104+
mac.span,
105+
&msg,
106+
add_note,
107+
);
108+
} else {
109+
span_lint_and_then(cx, DISALLOWED_MACROS, mac.span, &msg, add_note);
110+
}
95111
}
96112
}
97113
}
@@ -110,49 +126,57 @@ impl LateLintPass<'_> for DisallowedMacros {
110126
}
111127

112128
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
113-
self.check(cx, expr.span);
129+
self.check(cx, expr.span, None);
114130
// `$t + $t` can have the context of $t, check also the span of the binary operator
115131
if let ExprKind::Binary(op, ..) = expr.kind {
116-
self.check(cx, op.span);
132+
self.check(cx, op.span, None);
117133
}
118134
}
119135

120136
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
121-
self.check(cx, stmt.span);
137+
self.check(cx, stmt.span, None);
122138
}
123139

124140
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) {
125-
self.check(cx, ty.span);
141+
self.check(cx, ty.span, None);
126142
}
127143

128144
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
129-
self.check(cx, pat.span);
145+
self.check(cx, pat.span, None);
130146
}
131147

132148
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
133-
self.check(cx, item.span);
134-
self.check(cx, item.vis_span);
149+
self.check(cx, item.span, self.derive_src);
150+
self.check(cx, item.vis_span, None);
151+
152+
if matches!(
153+
item.kind,
154+
ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)
155+
) && macro_backtrace(item.span).all(|m| !matches!(m.kind, MacroKind::Derive))
156+
{
157+
self.derive_src = Some(item.owner_id);
158+
}
135159
}
136160

137161
fn check_foreign_item(&mut self, cx: &LateContext<'_>, item: &ForeignItem<'_>) {
138-
self.check(cx, item.span);
139-
self.check(cx, item.vis_span);
162+
self.check(cx, item.span, None);
163+
self.check(cx, item.vis_span, None);
140164
}
141165

142166
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) {
143-
self.check(cx, item.span);
144-
self.check(cx, item.vis_span);
167+
self.check(cx, item.span, None);
168+
self.check(cx, item.vis_span, None);
145169
}
146170

147171
fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
148-
self.check(cx, item.span);
172+
self.check(cx, item.span, None);
149173
}
150174

151175
fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) {
152-
self.check(cx, path.span);
176+
self.check(cx, path.span, None);
153177
}
154178

155179
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &Attribute) {
156-
self.check(cx, attr.span);
180+
self.check(cx, attr.span, self.derive_src);
157181
}
158182
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
extern crate proc_macro;
2+
use proc_macro::Delimiter::{Brace, Bracket, Parenthesis};
3+
use proc_macro::Spacing::{Alone, Joint};
4+
use proc_macro::{Group, Ident, Punct, Span, TokenStream, TokenTree as TT};
5+
6+
#[proc_macro_derive(Derive)]
7+
pub fn derive(_: TokenStream) -> TokenStream {
8+
TokenStream::from_iter([
9+
TT::from(Punct::new('#', Alone)),
10+
TT::from(Group::new(
11+
Bracket,
12+
TokenStream::from_iter([
13+
TT::from(Ident::new("allow", Span::call_site())),
14+
TT::from(Group::new(
15+
Parenthesis,
16+
TokenStream::from_iter([
17+
TT::from(Ident::new("clippy", Span::call_site())),
18+
TT::from(Punct::new(':', Joint)),
19+
TT::from(Punct::new(':', Alone)),
20+
TT::from(Ident::new("disallowed_macros", Span::call_site())),
21+
]),
22+
)),
23+
]),
24+
)),
25+
TT::from(Ident::new("impl", Span::call_site())),
26+
TT::from(Ident::new("Foo", Span::call_site())),
27+
TT::from(Group::new(Brace, TokenStream::new())),
28+
])
29+
}

tests/ui-toml/disallowed_macros/clippy.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ disallowed-macros = [
1010
"macros::item",
1111
"macros::binop",
1212
"macros::attr",
13+
"proc_macros::Derive",
1314
]

tests/ui-toml/disallowed_macros/disallowed_macros.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
//@aux-build:macros.rs
2+
//@aux-build:proc_macros.rs
23

34
#![allow(unused)]
45

56
extern crate macros;
7+
extern crate proc_macros;
68

9+
use proc_macros::Derive;
710
use serde::Serialize;
811

912
fn main() {
@@ -40,3 +43,6 @@ trait Y {
4043
impl Y for S {
4144
macros::item!();
4245
}
46+
47+
#[derive(Derive)]
48+
struct Foo;
Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: use of a disallowed macro `std::println`
2-
--> $DIR/disallowed_macros.rs:10:5
2+
--> $DIR/disallowed_macros.rs:13:5
33
|
44
LL | println!("one");
55
| ^^^^^^^^^^^^^^^
@@ -8,92 +8,98 @@ LL | println!("one");
88
= help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]`
99

1010
error: use of a disallowed macro `std::println`
11-
--> $DIR/disallowed_macros.rs:11:5
11+
--> $DIR/disallowed_macros.rs:14:5
1212
|
1313
LL | println!("two");
1414
| ^^^^^^^^^^^^^^^
1515

1616
error: use of a disallowed macro `std::cfg`
17-
--> $DIR/disallowed_macros.rs:12:5
17+
--> $DIR/disallowed_macros.rs:15:5
1818
|
1919
LL | cfg!(unix);
2020
| ^^^^^^^^^^
2121

2222
error: use of a disallowed macro `std::vec`
23-
--> $DIR/disallowed_macros.rs:13:5
23+
--> $DIR/disallowed_macros.rs:16:5
2424
|
2525
LL | vec![1, 2, 3];
2626
| ^^^^^^^^^^^^^
2727

2828
error: use of a disallowed macro `serde::Serialize`
29-
--> $DIR/disallowed_macros.rs:15:14
29+
--> $DIR/disallowed_macros.rs:18:14
3030
|
3131
LL | #[derive(Serialize)]
3232
| ^^^^^^^^^
3333
|
3434
= note: no serializing (from clippy.toml)
3535

3636
error: use of a disallowed macro `macros::expr`
37-
--> $DIR/disallowed_macros.rs:18:13
37+
--> $DIR/disallowed_macros.rs:21:13
3838
|
3939
LL | let _ = macros::expr!();
4040
| ^^^^^^^^^^^^^^^
4141

4242
error: use of a disallowed macro `macros::stmt`
43-
--> $DIR/disallowed_macros.rs:19:5
43+
--> $DIR/disallowed_macros.rs:22:5
4444
|
4545
LL | macros::stmt!();
4646
| ^^^^^^^^^^^^^^^
4747

4848
error: use of a disallowed macro `macros::pat`
49-
--> $DIR/disallowed_macros.rs:20:9
49+
--> $DIR/disallowed_macros.rs:23:9
5050
|
5151
LL | let macros::pat!() = 1;
5252
| ^^^^^^^^^^^^^^
5353

5454
error: use of a disallowed macro `macros::ty`
55-
--> $DIR/disallowed_macros.rs:21:12
55+
--> $DIR/disallowed_macros.rs:24:12
5656
|
5757
LL | let _: macros::ty!() = "";
5858
| ^^^^^^^^^^^^^
5959

6060
error: use of a disallowed macro `macros::item`
61-
--> $DIR/disallowed_macros.rs:22:5
61+
--> $DIR/disallowed_macros.rs:25:5
6262
|
6363
LL | macros::item!();
6464
| ^^^^^^^^^^^^^^^
6565

6666
error: use of a disallowed macro `macros::binop`
67-
--> $DIR/disallowed_macros.rs:23:13
67+
--> $DIR/disallowed_macros.rs:26:13
6868
|
6969
LL | let _ = macros::binop!(1);
7070
| ^^^^^^^^^^^^^^^^^
7171

7272
error: use of a disallowed macro `macros::attr`
73-
--> $DIR/disallowed_macros.rs:28:1
73+
--> $DIR/disallowed_macros.rs:31:1
7474
|
7575
LL | / macros::attr! {
7676
LL | | struct S;
7777
LL | | }
7878
| |_^
7979

8080
error: use of a disallowed macro `macros::item`
81-
--> $DIR/disallowed_macros.rs:33:5
81+
--> $DIR/disallowed_macros.rs:36:5
8282
|
8383
LL | macros::item!();
8484
| ^^^^^^^^^^^^^^^
8585

8686
error: use of a disallowed macro `macros::item`
87-
--> $DIR/disallowed_macros.rs:37:5
87+
--> $DIR/disallowed_macros.rs:40:5
8888
|
8989
LL | macros::item!();
9090
| ^^^^^^^^^^^^^^^
9191

9292
error: use of a disallowed macro `macros::item`
93-
--> $DIR/disallowed_macros.rs:41:5
93+
--> $DIR/disallowed_macros.rs:44:5
9494
|
9595
LL | macros::item!();
9696
| ^^^^^^^^^^^^^^^
9797

98-
error: aborting due to 15 previous errors
98+
error: use of a disallowed macro `proc_macros::Derive`
99+
--> $DIR/disallowed_macros.rs:47:10
100+
|
101+
LL | #[derive(Derive)]
102+
| ^^^^^^
103+
104+
error: aborting due to 16 previous errors
99105

0 commit comments

Comments
 (0)