Skip to content

Commit e687bed

Browse files
committed
Auto merge of #9495 - Alexendoo:disallowed-macros, r=Jarcho
Add `disallowed_macros` lint Closes #7790 Fixes #9558 `clippy_utils::def_path_res` already resolved macro definitions which is nice, it just needed a tweak to be able to disambiguate e.g. `std::vec` the module & `std::vec` the macro, and `serde::Serialize` the trait & `serde::Serialize` the derive macro changelog: new lint: [`disallowed_macros`] changelog: [`disallowed_methods`], [`disallowed_types`]: Fix false negative when a type/fn/macro share the same path
2 parents 425e1ea + 86c86c3 commit e687bed

23 files changed

+500
-110
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3820,6 +3820,7 @@ Released 2018-09-13
38203820
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
38213821
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
38223822
[`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
3823+
[`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros
38233824
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
38243825
[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
38253826
[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names

clippy_lints/src/await_holding_invalid.rs

+15-19
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::{match_def_path, paths};
33
use rustc_data_structures::fx::FxHashMap;
4+
use rustc_hir::def::{Namespace, Res};
45
use rustc_hir::def_id::DefId;
5-
use rustc_hir::{def::Res, AsyncGeneratorKind, Body, BodyId, GeneratorKind};
6+
use rustc_hir::{AsyncGeneratorKind, Body, BodyId, GeneratorKind};
67
use rustc_lint::{LateContext, LateLintPass};
78
use rustc_middle::ty::GeneratorInteriorTypeCause;
89
use rustc_session::{declare_tool_lint, impl_lint_pass};
910
use rustc_span::{sym, Span};
1011

11-
use crate::utils::conf::DisallowedType;
12+
use crate::utils::conf::DisallowedPath;
1213

1314
declare_clippy_lint! {
1415
/// ### What it does
@@ -171,12 +172,12 @@ impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF,
171172

172173
#[derive(Debug)]
173174
pub struct AwaitHolding {
174-
conf_invalid_types: Vec<DisallowedType>,
175-
def_ids: FxHashMap<DefId, DisallowedType>,
175+
conf_invalid_types: Vec<DisallowedPath>,
176+
def_ids: FxHashMap<DefId, DisallowedPath>,
176177
}
177178

178179
impl AwaitHolding {
179-
pub(crate) fn new(conf_invalid_types: Vec<DisallowedType>) -> Self {
180+
pub(crate) fn new(conf_invalid_types: Vec<DisallowedPath>) -> Self {
180181
Self {
181182
conf_invalid_types,
182183
def_ids: FxHashMap::default(),
@@ -187,11 +188,8 @@ impl AwaitHolding {
187188
impl LateLintPass<'_> for AwaitHolding {
188189
fn check_crate(&mut self, cx: &LateContext<'_>) {
189190
for conf in &self.conf_invalid_types {
190-
let path = match conf {
191-
DisallowedType::Simple(path) | DisallowedType::WithReason { path, .. } => path,
192-
};
193-
let segs: Vec<_> = path.split("::").collect();
194-
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
191+
let segs: Vec<_> = conf.path().split("::").collect();
192+
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
195193
self.def_ids.insert(id, conf.clone());
196194
}
197195
}
@@ -256,20 +254,18 @@ impl AwaitHolding {
256254
}
257255
}
258256

259-
fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedType) {
260-
let (type_name, reason) = match disallowed {
261-
DisallowedType::Simple(path) => (path, &None),
262-
DisallowedType::WithReason { path, reason } => (path, reason),
263-
};
264-
257+
fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPath) {
265258
span_lint_and_then(
266259
cx,
267260
AWAIT_HOLDING_INVALID_TYPE,
268261
span,
269-
&format!("`{type_name}` may not be held across an `await` point per `clippy.toml`",),
262+
&format!(
263+
"`{}` may not be held across an `await` point per `clippy.toml`",
264+
disallowed.path()
265+
),
270266
|diag| {
271-
if let Some(reason) = reason {
272-
diag.note(reason.clone());
267+
if let Some(reason) = disallowed.reason() {
268+
diag.note(reason);
273269
}
274270
},
275271
);

clippy_lints/src/disallowed_macros.rs

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::macros::macro_backtrace;
3+
use rustc_data_structures::fx::FxHashSet;
4+
use rustc_hir::def::{Namespace, Res};
5+
use rustc_hir::def_id::DefIdMap;
6+
use rustc_hir::{Expr, ForeignItem, HirId, ImplItem, Item, Pat, Path, Stmt, TraitItem, Ty};
7+
use rustc_lint::{LateContext, LateLintPass};
8+
use rustc_session::{declare_tool_lint, impl_lint_pass};
9+
use rustc_span::{ExpnId, Span};
10+
11+
use crate::utils::conf;
12+
13+
declare_clippy_lint! {
14+
/// ### What it does
15+
/// Denies the configured macros in clippy.toml
16+
///
17+
/// Note: Even though this lint is warn-by-default, it will only trigger if
18+
/// macros are defined in the clippy.toml file.
19+
///
20+
/// ### Why is this bad?
21+
/// Some macros are undesirable in certain contexts, and it's beneficial to
22+
/// lint for them as needed.
23+
///
24+
/// ### Example
25+
/// An example clippy.toml configuration:
26+
/// ```toml
27+
/// # clippy.toml
28+
/// disallowed-macros = [
29+
/// # Can use a string as the path of the disallowed macro.
30+
/// "std::print",
31+
/// # Can also use an inline table with a `path` key.
32+
/// { path = "std::println" },
33+
/// # When using an inline table, can add a `reason` for why the macro
34+
/// # is disallowed.
35+
/// { path = "serde::Serialize", reason = "no serializing" },
36+
/// ]
37+
/// ```
38+
/// ```
39+
/// use serde::Serialize;
40+
///
41+
/// // Example code where clippy issues a warning
42+
/// println!("warns");
43+
///
44+
/// // The diagnostic will contain the message "no serializing"
45+
/// #[derive(Serialize)]
46+
/// struct Data {
47+
/// name: String,
48+
/// value: usize,
49+
/// }
50+
/// ```
51+
#[clippy::version = "1.65.0"]
52+
pub DISALLOWED_MACROS,
53+
style,
54+
"use of a disallowed macro"
55+
}
56+
57+
pub struct DisallowedMacros {
58+
conf_disallowed: Vec<conf::DisallowedPath>,
59+
disallowed: DefIdMap<usize>,
60+
seen: FxHashSet<ExpnId>,
61+
}
62+
63+
impl DisallowedMacros {
64+
pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
65+
Self {
66+
conf_disallowed,
67+
disallowed: DefIdMap::default(),
68+
seen: FxHashSet::default(),
69+
}
70+
}
71+
72+
fn check(&mut self, cx: &LateContext<'_>, span: Span) {
73+
if self.conf_disallowed.is_empty() {
74+
return;
75+
}
76+
77+
for mac in macro_backtrace(span) {
78+
if !self.seen.insert(mac.expn) {
79+
return;
80+
}
81+
82+
if let Some(&index) = self.disallowed.get(&mac.def_id) {
83+
let conf = &self.conf_disallowed[index];
84+
85+
span_lint_and_then(
86+
cx,
87+
DISALLOWED_MACROS,
88+
mac.span,
89+
&format!("use of a disallowed macro `{}`", conf.path()),
90+
|diag| {
91+
if let Some(reason) = conf.reason() {
92+
diag.note(&format!("{reason} (from clippy.toml)"));
93+
}
94+
},
95+
);
96+
}
97+
}
98+
}
99+
}
100+
101+
impl_lint_pass!(DisallowedMacros => [DISALLOWED_MACROS]);
102+
103+
impl LateLintPass<'_> for DisallowedMacros {
104+
fn check_crate(&mut self, cx: &LateContext<'_>) {
105+
for (index, conf) in self.conf_disallowed.iter().enumerate() {
106+
let segs: Vec<_> = conf.path().split("::").collect();
107+
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::MacroNS)) {
108+
self.disallowed.insert(id, index);
109+
}
110+
}
111+
}
112+
113+
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
114+
self.check(cx, expr.span);
115+
}
116+
117+
fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
118+
self.check(cx, stmt.span);
119+
}
120+
121+
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &Ty<'_>) {
122+
self.check(cx, ty.span);
123+
}
124+
125+
fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
126+
self.check(cx, pat.span);
127+
}
128+
129+
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
130+
self.check(cx, item.span);
131+
self.check(cx, item.vis_span);
132+
}
133+
134+
fn check_foreign_item(&mut self, cx: &LateContext<'_>, item: &ForeignItem<'_>) {
135+
self.check(cx, item.span);
136+
self.check(cx, item.vis_span);
137+
}
138+
139+
fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &ImplItem<'_>) {
140+
self.check(cx, item.span);
141+
self.check(cx, item.vis_span);
142+
}
143+
144+
fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
145+
self.check(cx, item.span);
146+
}
147+
148+
fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, _: HirId) {
149+
self.check(cx, path.span);
150+
}
151+
}

clippy_lints/src/disallowed_methods.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
33

4-
use rustc_hir::{def::Res, def_id::DefIdMap, Expr, ExprKind};
4+
use rustc_hir::def::{Namespace, Res};
5+
use rustc_hir::def_id::DefIdMap;
6+
use rustc_hir::{Expr, ExprKind};
57
use rustc_lint::{LateContext, LateLintPass};
68
use rustc_session::{declare_tool_lint, impl_lint_pass};
79

@@ -58,12 +60,12 @@ declare_clippy_lint! {
5860

5961
#[derive(Clone, Debug)]
6062
pub struct DisallowedMethods {
61-
conf_disallowed: Vec<conf::DisallowedMethod>,
63+
conf_disallowed: Vec<conf::DisallowedPath>,
6264
disallowed: DefIdMap<usize>,
6365
}
6466

6567
impl DisallowedMethods {
66-
pub fn new(conf_disallowed: Vec<conf::DisallowedMethod>) -> Self {
68+
pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
6769
Self {
6870
conf_disallowed,
6971
disallowed: DefIdMap::default(),
@@ -77,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
7779
fn check_crate(&mut self, cx: &LateContext<'_>) {
7880
for (index, conf) in self.conf_disallowed.iter().enumerate() {
7981
let segs: Vec<_> = conf.path().split("::").collect();
80-
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
82+
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, Some(Namespace::ValueNS)) {
8183
self.disallowed.insert(id, index);
8284
}
8385
}
@@ -102,10 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
102104
};
103105
let msg = format!("use of a disallowed method `{}`", conf.path());
104106
span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
105-
if let conf::DisallowedMethod::WithReason {
106-
reason: Some(reason), ..
107-
} = conf
108-
{
107+
if let Some(reason) = conf.reason() {
109108
diag.note(&format!("{reason} (from clippy.toml)"));
110109
}
111110
});

clippy_lints/src/disallowed_types.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22

33
use rustc_data_structures::fx::FxHashMap;
4-
use rustc_hir::{def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
4+
use rustc_hir::def::{Namespace, Res};
5+
use rustc_hir::def_id::DefId;
6+
use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
57
use rustc_lint::{LateContext, LateLintPass};
68
use rustc_session::{declare_tool_lint, impl_lint_pass};
79
use rustc_span::Span;
@@ -50,13 +52,13 @@ declare_clippy_lint! {
5052
}
5153
#[derive(Clone, Debug)]
5254
pub struct DisallowedTypes {
53-
conf_disallowed: Vec<conf::DisallowedType>,
55+
conf_disallowed: Vec<conf::DisallowedPath>,
5456
def_ids: FxHashMap<DefId, Option<String>>,
5557
prim_tys: FxHashMap<PrimTy, Option<String>>,
5658
}
5759

5860
impl DisallowedTypes {
59-
pub fn new(conf_disallowed: Vec<conf::DisallowedType>) -> Self {
61+
pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
6062
Self {
6163
conf_disallowed,
6264
def_ids: FxHashMap::default(),
@@ -86,15 +88,9 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
8688
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
8789
fn check_crate(&mut self, cx: &LateContext<'_>) {
8890
for conf in &self.conf_disallowed {
89-
let (path, reason) = match conf {
90-
conf::DisallowedType::Simple(path) => (path, None),
91-
conf::DisallowedType::WithReason { path, reason } => (
92-
path,
93-
reason.as_ref().map(|reason| format!("{reason} (from clippy.toml)")),
94-
),
95-
};
96-
let segs: Vec<_> = path.split("::").collect();
97-
match clippy_utils::def_path_res(cx, &segs) {
91+
let segs: Vec<_> = conf.path().split("::").collect();
92+
let reason = conf.reason().map(|reason| format!("{reason} (from clippy.toml)"));
93+
match clippy_utils::def_path_res(cx, &segs, Some(Namespace::TypeNS)) {
9894
Res::Def(_, id) => {
9995
self.def_ids.insert(id, reason);
10096
},

clippy_lints/src/lib.register_all.rs

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
4545
LintId::of(derivable_impls::DERIVABLE_IMPLS),
4646
LintId::of(derive::DERIVE_HASH_XOR_EQ),
4747
LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
48+
LintId::of(disallowed_macros::DISALLOWED_MACROS),
4849
LintId::of(disallowed_methods::DISALLOWED_METHODS),
4950
LintId::of(disallowed_names::DISALLOWED_NAMES),
5051
LintId::of(disallowed_types::DISALLOWED_TYPES),

clippy_lints/src/lib.register_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ store.register_lints(&[
114114
derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ,
115115
derive::EXPL_IMPL_CLONE_ON_COPY,
116116
derive::UNSAFE_DERIVE_DESERIALIZE,
117+
disallowed_macros::DISALLOWED_MACROS,
117118
disallowed_methods::DISALLOWED_METHODS,
118119
disallowed_names::DISALLOWED_NAMES,
119120
disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,

clippy_lints/src/lib.register_style.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
1515
LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
1616
LintId::of(default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY),
1717
LintId::of(dereference::NEEDLESS_BORROW),
18+
LintId::of(disallowed_macros::DISALLOWED_MACROS),
1819
LintId::of(disallowed_methods::DISALLOWED_METHODS),
1920
LintId::of(disallowed_names::DISALLOWED_NAMES),
2021
LintId::of(disallowed_types::DISALLOWED_TYPES),

clippy_lints/src/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ mod default_union_representation;
199199
mod dereference;
200200
mod derivable_impls;
201201
mod derive;
202+
mod disallowed_macros;
202203
mod disallowed_methods;
203204
mod disallowed_names;
204205
mod disallowed_script_idents;
@@ -820,6 +821,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
820821
store.register_late_pass(|_| Box::new(unwrap_in_result::UnwrapInResult));
821822
store.register_late_pass(|_| Box::new(semicolon_if_nothing_returned::SemicolonIfNothingReturned));
822823
store.register_late_pass(|_| Box::new(async_yields_async::AsyncYieldsAsync));
824+
let disallowed_macros = conf.disallowed_macros.clone();
825+
store.register_late_pass(move |_| Box::new(disallowed_macros::DisallowedMacros::new(disallowed_macros.clone())));
823826
let disallowed_methods = conf.disallowed_methods.clone();
824827
store.register_late_pass(move |_| Box::new(disallowed_methods::DisallowedMethods::new(disallowed_methods.clone())));
825828
store.register_early_pass(|| Box::new(asm_syntax::InlineAsmX86AttSyntax));

clippy_lints/src/missing_enforced_import_rename.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ impl_lint_pass!(ImportRename => [MISSING_ENFORCED_IMPORT_RENAMES]);
5858
impl LateLintPass<'_> for ImportRename {
5959
fn check_crate(&mut self, cx: &LateContext<'_>) {
6060
for Rename { path, rename } in &self.conf_renames {
61-
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &path.split("::").collect::<Vec<_>>()) {
61+
let segs = path.split("::").collect::<Vec<_>>();
62+
if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs, None) {
6263
self.renames.insert(id, Symbol::intern(rename));
6364
}
6465
}

0 commit comments

Comments
 (0)