]> git.proxmox.com Git - rustc.git/blob - src/tools/clippy/clippy_lints/src/disallowed_type.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / disallowed_type.rs
1 use clippy_utils::diagnostics::span_lint;
2
3 use rustc_data_structures::fx::FxHashSet;
4 use rustc_hir::{
5 def::Res, def_id::DefId, Crate, Item, ItemKind, PolyTraitRef, TraitBoundModifier, Ty, TyKind, UseKind,
6 };
7 use rustc_lint::{LateContext, LateLintPass};
8 use rustc_session::{declare_tool_lint, impl_lint_pass};
9 use rustc_span::{Span, Symbol};
10
11 declare_clippy_lint! {
12 /// **What it does:** Denies the configured types in clippy.toml.
13 ///
14 /// **Why is this bad?** Some types are undesirable in certain contexts.
15 ///
16 /// **Known problems:** None.
17 ///
18 /// N.B. There is no way to ban primitive types.
19 ///
20 /// **Example:**
21 ///
22 /// An example clippy.toml configuration:
23 /// ```toml
24 /// # clippy.toml
25 /// disallowed-methods = ["std::collections::BTreeMap"]
26 /// ```
27 ///
28 /// ```rust,ignore
29 /// use std::collections::BTreeMap;
30 /// // or its use
31 /// let x = std::collections::BTreeMap::new();
32 /// ```
33 /// Use instead:
34 /// ```rust,ignore
35 /// // A similar type that is allowed by the config
36 /// use std::collections::HashMap;
37 /// ```
38 pub DISALLOWED_TYPE,
39 nursery,
40 "use of a disallowed type"
41 }
42 #[derive(Clone, Debug)]
43 pub struct DisallowedType {
44 disallowed: FxHashSet<Vec<Symbol>>,
45 def_ids: FxHashSet<(DefId, Vec<Symbol>)>,
46 }
47
48 impl DisallowedType {
49 pub fn new(disallowed: &FxHashSet<String>) -> Self {
50 Self {
51 disallowed: disallowed
52 .iter()
53 .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
54 .collect(),
55 def_ids: FxHashSet::default(),
56 }
57 }
58 }
59
60 impl_lint_pass!(DisallowedType => [DISALLOWED_TYPE]);
61
62 impl<'tcx> LateLintPass<'tcx> for DisallowedType {
63 fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
64 for path in &self.disallowed {
65 let segs = path.iter().map(ToString::to_string).collect::<Vec<_>>();
66 if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::<Vec<_>>())
67 {
68 self.def_ids.insert((id, path.clone()));
69 }
70 }
71 }
72
73 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
74 if_chain! {
75 if let ItemKind::Use(path, UseKind::Single) = &item.kind;
76 if let Res::Def(_, did) = path.res;
77 if let Some((_, name)) = self.def_ids.iter().find(|(id, _)| *id == did);
78 then {
79 emit(cx, name, item.span,);
80 }
81 }
82 }
83
84 fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
85 if_chain! {
86 if let TyKind::Path(path) = &ty.kind;
87 if let Some(did) = cx.qpath_res(path, ty.hir_id).opt_def_id();
88 if let Some((_, name)) = self.def_ids.iter().find(|(id, _)| *id == did);
89 then {
90 emit(cx, name, path.span());
91 }
92 }
93 }
94
95 fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>, _: TraitBoundModifier) {
96 if_chain! {
97 if let Res::Def(_, did) = poly.trait_ref.path.res;
98 if let Some((_, name)) = self.def_ids.iter().find(|(id, _)| *id == did);
99 then {
100 emit(cx, name, poly.trait_ref.path.span);
101 }
102 }
103 }
104
105 // TODO: if non primitive const generics are a thing
106 // fn check_generic_arg(&mut self, cx: &LateContext<'tcx>, arg: &'tcx GenericArg<'tcx>) {
107 // match arg {
108 // GenericArg::Const(c) => {},
109 // }
110 // }
111 // fn check_generic_param(&mut self, cx: &LateContext<'tcx>, param: &'tcx GenericParam<'tcx>) {
112 // match param.kind {
113 // GenericParamKind::Const { .. } => {},
114 // }
115 // }
116 }
117
118 fn emit(cx: &LateContext<'_>, name: &[Symbol], span: Span) {
119 let name = name.iter().map(|s| s.to_ident_string()).collect::<Vec<_>>().join("::");
120 span_lint(
121 cx,
122 DISALLOWED_TYPE,
123 span,
124 &format!("`{}` is not allowed according to config", name),
125 );
126 }