]> git.lizzy.rs Git - rust.git/blob - clippy_lints/src/disallowed_type.rs
Add primitive type support to disallowed_type lint
[rust.git] / 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, PrimTy, 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     /// **Example:**
19     ///
20     /// An example clippy.toml configuration:
21     /// ```toml
22     /// # clippy.toml
23     /// disallowed-types = ["std::collections::BTreeMap"]
24     /// ```
25     ///
26     /// ```rust,ignore
27     /// use std::collections::BTreeMap;
28     /// // or its use
29     /// let x = std::collections::BTreeMap::new();
30     /// ```
31     /// Use instead:
32     /// ```rust,ignore
33     /// // A similar type that is allowed by the config
34     /// use std::collections::HashMap;
35     /// ```
36     pub DISALLOWED_TYPE,
37     nursery,
38     "use of a disallowed type"
39 }
40 #[derive(Clone, Debug)]
41 pub struct DisallowedType {
42     disallowed: FxHashSet<Vec<Symbol>>,
43     def_ids: FxHashSet<DefId>,
44     prim_tys: FxHashSet<PrimTy>,
45 }
46
47 impl DisallowedType {
48     pub fn new(disallowed: &FxHashSet<String>) -> Self {
49         Self {
50             disallowed: disallowed
51                 .iter()
52                 .map(|s| s.split("::").map(|seg| Symbol::intern(seg)).collect::<Vec<_>>())
53                 .collect(),
54             def_ids: FxHashSet::default(),
55             prim_tys: FxHashSet::default(),
56         }
57     }
58
59     fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
60         match res {
61             Res::Def(_, did) => {
62                 if self.def_ids.contains(did) {
63                     emit(cx, &cx.tcx.def_path_str(*did), span);
64                 }
65             },
66             Res::PrimTy(prim) => {
67                 if self.prim_tys.contains(prim) {
68                     emit(cx, prim.name_str(), span);
69                 }
70             },
71             _ => {},
72         }
73     }
74 }
75
76 impl_lint_pass!(DisallowedType => [DISALLOWED_TYPE]);
77
78 impl<'tcx> LateLintPass<'tcx> for DisallowedType {
79     fn check_crate(&mut self, cx: &LateContext<'_>, _: &Crate<'_>) {
80         for path in &self.disallowed {
81             let segs = path.iter().map(ToString::to_string).collect::<Vec<_>>();
82             match clippy_utils::path_to_res(cx, &segs.iter().map(String::as_str).collect::<Vec<_>>()) {
83                 Res::Def(_, id) => {
84                     self.def_ids.insert(id);
85                 },
86                 Res::PrimTy(ty) => {
87                     self.prim_tys.insert(ty);
88                 },
89                 _ => {},
90             }
91         }
92     }
93
94     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
95         if let ItemKind::Use(path, UseKind::Single) = &item.kind {
96             self.check_res_emit(cx, &path.res, item.span);
97         }
98     }
99
100     fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
101         if let TyKind::Path(path) = &ty.kind {
102             self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span);
103         }
104     }
105
106     fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>, _: TraitBoundModifier) {
107         self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span);
108     }
109 }
110
111 fn emit(cx: &LateContext<'_>, name: &str, span: Span) {
112     span_lint(
113         cx,
114         DISALLOWED_TYPE,
115         span,
116         &format!("`{}` is not allowed according to config", name),
117     );
118 }