Skip to content

Commit c4636ab

Browse files
committed
Auto merge of rust-lang#7315 - DevinR528:disallowed-ty, r=giraffate
Add disallowed_type lint, this adds a field to the conf struct Fixes rust-lang#7277 changelog: Add ``[`disallowed_type`]`` a lint that can enforce banning types specified in the config.
2 parents 2464ee9 + ea45e2a commit c4636ab

File tree

8 files changed

+263
-1
lines changed

8 files changed

+263
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,6 +2358,7 @@ Released 2018-09-13
23582358
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
23592359
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
23602360
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
2361+
[`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
23612362
[`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
23622363
[`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
23632364
[`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons

clippy_lints/src/disallowed_type.rs

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use clippy_utils::diagnostics::span_lint;
2+
3+
use rustc_data_structures::fx::FxHashSet;
4+
use rustc_hir::{def::Res, Item, ItemKind, PolyTraitRef, TraitBoundModifier, Ty, TyKind, UseKind};
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_session::{declare_tool_lint, impl_lint_pass};
7+
use rustc_span::{Span, Symbol};
8+
9+
declare_clippy_lint! {
10+
/// **What it does:** Denies the configured types in clippy.toml.
11+
///
12+
/// **Why is this bad?** Some types are undesirable in certain contexts.
13+
///
14+
/// **Known problems:** The fully qualified path must be used. This lint
15+
/// doesn't support aliases or reexported names; be aware that many types
16+
/// in `std` are actually reexports.
17+
///
18+
/// For example, if you want to disallow `BTreeMap`, your clippy.toml
19+
/// configuration would look like
20+
/// `disallowed-methods = ["alloc::collections::btree::map::BTreeMap"]` and not
21+
/// `disallowed-methods = ["std::collections::BTreeMap"]` as you might expect.
22+
///
23+
/// N.B. There is no way to ban primitive types.
24+
///
25+
/// **Example:**
26+
///
27+
/// An example clippy.toml configuration:
28+
/// ```toml
29+
/// # clippy.toml
30+
/// disallowed-methods = ["alloc::collections::btree::map::BTreeMap"]
31+
/// ```
32+
///
33+
/// ```rust,ignore
34+
/// use std::collections::BTreeMap;
35+
/// // or its use
36+
/// let x = std::collections::BTreeMap::new();
37+
/// ```
38+
/// Use instead:
39+
/// ```rust,ignore
40+
/// // A similar type that is allowed by the config
41+
/// use std::collections::HashMap;
42+
/// ```
43+
pub DISALLOWED_TYPE,
44+
nursery,
45+
"use of a disallowed type"
46+
}
47+
#[derive(Clone, Debug)]
48+
pub struct DisallowedType {
49+
disallowed: FxHashSet<Vec<Symbol>>,
50+
}
51+
52+
impl DisallowedType {
53+
pub fn new(disallowed: &FxHashSet<String>) -> Self {
54+
Self {
55+
disallowed: disallowed
56+
.iter()
57+
.map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
58+
.collect(),
59+
}
60+
}
61+
}
62+
63+
impl_lint_pass!(DisallowedType => [DISALLOWED_TYPE]);
64+
65+
impl<'tcx> LateLintPass<'tcx> for DisallowedType {
66+
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
67+
if_chain! {
68+
if let ItemKind::Use(path, UseKind::Single) = &item.kind;
69+
if let Res::Def(_, id) = path.res;
70+
let use_path = cx.get_def_path(id);
71+
if let Some(name) = self.disallowed.iter().find(|path| **path == use_path);
72+
then {
73+
emit(cx, name, item.span,);
74+
}
75+
}
76+
}
77+
78+
fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
79+
if_chain! {
80+
if let TyKind::Path(path) = &ty.kind;
81+
if let Some(did) = cx.qpath_res(path, ty.hir_id).opt_def_id();
82+
let use_path = cx.get_def_path(did);
83+
if let Some(name) = self.disallowed.iter().find(|path| **path == use_path);
84+
then {
85+
emit(cx, name, path.span());
86+
}
87+
}
88+
}
89+
90+
fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>, _: TraitBoundModifier) {
91+
if_chain! {
92+
if let Res::Def(_, did) = poly.trait_ref.path.res;
93+
let use_path = cx.get_def_path(did);
94+
if let Some(name) = self.disallowed.iter().find(|path| **path == use_path);
95+
then {
96+
emit(cx, name, poly.trait_ref.path.span);
97+
}
98+
}
99+
}
100+
101+
// TODO: if non primitive const generics are a thing
102+
// fn check_generic_arg(&mut self, cx: &LateContext<'tcx>, arg: &'tcx GenericArg<'tcx>) {
103+
// match arg {
104+
// GenericArg::Const(c) => {},
105+
// }
106+
// }
107+
// fn check_generic_param(&mut self, cx: &LateContext<'tcx>, param: &'tcx GenericParam<'tcx>) {
108+
// match param.kind {
109+
// GenericParamKind::Const { .. } => {},
110+
// }
111+
// }
112+
}
113+
114+
fn emit(cx: &LateContext<'_>, name: &[Symbol], span: Span) {
115+
let name = name.iter().map(|s| s.to_ident_string()).collect::<Vec<_>>().join("::");
116+
span_lint(
117+
cx,
118+
DISALLOWED_TYPE,
119+
span,
120+
&format!("`{}` is not allowed according to config", name),
121+
);
122+
}

clippy_lints/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ mod default_numeric_fallback;
187187
mod dereference;
188188
mod derive;
189189
mod disallowed_method;
190+
mod disallowed_type;
190191
mod doc;
191192
mod double_comparison;
192193
mod double_parens;
@@ -582,6 +583,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
582583
derive::EXPL_IMPL_CLONE_ON_COPY,
583584
derive::UNSAFE_DERIVE_DESERIALIZE,
584585
disallowed_method::DISALLOWED_METHOD,
586+
disallowed_type::DISALLOWED_TYPE,
585587
doc::DOC_MARKDOWN,
586588
doc::MISSING_ERRORS_DOC,
587589
doc::MISSING_PANICS_DOC,
@@ -1760,6 +1762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
17601762
LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
17611763
LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
17621764
LintId::of(disallowed_method::DISALLOWED_METHOD),
1765+
LintId::of(disallowed_type::DISALLOWED_TYPE),
17631766
LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
17641767
LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
17651768
LintId::of(floating_point_arithmetic::SUBOPTIMAL_FLOPS),
@@ -2064,6 +2067,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
20642067
store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv));
20652068
store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison);
20662069
store.register_late_pass(|| box unused_async::UnusedAsync);
2070+
let disallowed_types = conf.disallowed_types.iter().cloned().collect::<FxHashSet<_>>();
2071+
store.register_late_pass(move || box disallowed_type::DisallowedType::new(&disallowed_types));
20672072

20682073
}
20692074

clippy_lints/src/utils/conf.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ define_Conf! {
190190
(warn_on_all_wildcard_imports: bool = false),
191191
/// Lint: DISALLOWED_METHOD. The list of disallowed methods, written as fully qualified paths.
192192
(disallowed_methods: Vec<String> = Vec::new()),
193+
/// Lint: DISALLOWED_TYPE. The list of disallowed types, written as fully qualified paths.
194+
(disallowed_types: Vec<String> = Vec::new()),
193195
/// Lint: UNREADABLE_LITERAL. Should the fraction of a decimal be linted to include separators.
194196
(unreadable_literal_lint_fractions: bool = true),
195197
/// Lint: UPPER_CASE_ACRONYMS. Enables verbose mode. Triggers if there is more than one uppercase char next to each other
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
disallowed-types = [
2+
"std::collections::hash::map::HashMap",
3+
"core::sync::atomic::AtomicU32",
4+
"syn::ty::TypePath",
5+
"proc_macro2::Ident",
6+
"std::thread::Thread",
7+
"std::time::Instant",
8+
"std::io::Read",
9+
]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#![warn(clippy::disallowed_type)]
2+
3+
extern crate quote;
4+
extern crate syn;
5+
6+
use std::sync as foo;
7+
use std::sync::atomic::AtomicU32;
8+
use std::time::Instant as Sneaky;
9+
10+
struct HashMap;
11+
12+
fn bad_return_type() -> fn() -> Sneaky {
13+
todo!()
14+
}
15+
16+
fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {
17+
todo!()
18+
}
19+
20+
fn trait_obj(_: &dyn std::io::Read) {
21+
todo!()
22+
}
23+
24+
static BAD: foo::atomic::AtomicPtr<()> = foo::atomic::AtomicPtr::new(std::ptr::null_mut());
25+
26+
#[allow(clippy::diverging_sub_expression)]
27+
fn main() {
28+
let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
29+
let _ = Sneaky::now();
30+
let _ = foo::atomic::AtomicU32::new(0);
31+
static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
32+
let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default();
33+
let _ = syn::Ident::new("", todo!());
34+
let _ = HashMap;
35+
}
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
error: `core::sync::atomic::AtomicU32` is not allowed according to config
2+
--> $DIR/conf_disallowed_type.rs:7:1
3+
|
4+
LL | use std::sync::atomic::AtomicU32;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `-D clippy::disallowed-type` implied by `-D warnings`
8+
9+
error: `std::time::Instant` is not allowed according to config
10+
--> $DIR/conf_disallowed_type.rs:8:1
11+
|
12+
LL | use std::time::Instant as Sneaky;
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: `std::time::Instant` is not allowed according to config
16+
--> $DIR/conf_disallowed_type.rs:12:33
17+
|
18+
LL | fn bad_return_type() -> fn() -> Sneaky {
19+
| ^^^^^^
20+
21+
error: `std::time::Instant` is not allowed according to config
22+
--> $DIR/conf_disallowed_type.rs:16:28
23+
|
24+
LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {
25+
| ^^^^^^
26+
27+
error: `core::sync::atomic::AtomicU32` is not allowed according to config
28+
--> $DIR/conf_disallowed_type.rs:16:39
29+
|
30+
LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {
31+
| ^^^^^^^^^^^^^^^^^^^^^^
32+
33+
error: `std::io::Read` is not allowed according to config
34+
--> $DIR/conf_disallowed_type.rs:20:22
35+
|
36+
LL | fn trait_obj(_: &dyn std::io::Read) {
37+
| ^^^^^^^^^^^^^
38+
39+
error: `std::collections::hash::map::HashMap` is not allowed according to config
40+
--> $DIR/conf_disallowed_type.rs:28:48
41+
|
42+
LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
43+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
44+
45+
error: `std::collections::hash::map::HashMap` is not allowed according to config
46+
--> $DIR/conf_disallowed_type.rs:28:12
47+
|
48+
LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new();
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
50+
51+
error: `std::time::Instant` is not allowed according to config
52+
--> $DIR/conf_disallowed_type.rs:29:13
53+
|
54+
LL | let _ = Sneaky::now();
55+
| ^^^^^^
56+
57+
error: `core::sync::atomic::AtomicU32` is not allowed according to config
58+
--> $DIR/conf_disallowed_type.rs:30:13
59+
|
60+
LL | let _ = foo::atomic::AtomicU32::new(0);
61+
| ^^^^^^^^^^^^^^^^^^^^^^
62+
63+
error: `core::sync::atomic::AtomicU32` is not allowed according to config
64+
--> $DIR/conf_disallowed_type.rs:31:17
65+
|
66+
LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
67+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
68+
69+
error: `core::sync::atomic::AtomicU32` is not allowed according to config
70+
--> $DIR/conf_disallowed_type.rs:31:48
71+
|
72+
LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1);
73+
| ^^^^^^^^^^^^^^^^^^^^^^
74+
75+
error: `syn::ty::TypePath` is not allowed according to config
76+
--> $DIR/conf_disallowed_type.rs:32:43
77+
|
78+
LL | let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default();
79+
| ^^^^^^^^^^^^^
80+
81+
error: `proc_macro2::Ident` is not allowed according to config
82+
--> $DIR/conf_disallowed_type.rs:33:13
83+
|
84+
LL | let _ = syn::Ident::new("", todo!());
85+
| ^^^^^^^^^^
86+
87+
error: aborting due to 14 previous errors
88+
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
1+
error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `disallowed-types`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1
22

33
error: aborting due to previous error
44

0 commit comments

Comments
 (0)