1 use clippy_utils::diagnostics::span_lint_and_then;
3 use rustc_data_structures::fx::FxHashMap;
4 use rustc_hir::def::Res;
5 use rustc_hir::def_id::DefId;
6 use rustc_hir::{Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
7 use rustc_lint::{LateContext, LateLintPass};
8 use rustc_session::{declare_tool_lint, impl_lint_pass};
11 use crate::utils::conf;
13 declare_clippy_lint! {
15 /// Denies the configured types in clippy.toml.
17 /// Note: Even though this lint is warn-by-default, it will only trigger if
18 /// types are defined in the clippy.toml file.
20 /// ### Why is this bad?
21 /// Some types are undesirable in certain contexts.
24 /// An example clippy.toml configuration:
27 /// disallowed-types = [
28 /// # Can use a string as the path of the disallowed type.
29 /// "std::collections::BTreeMap",
30 /// # Can also use an inline table with a `path` key.
31 /// { path = "std::net::TcpListener" },
32 /// # When using an inline table, can add a `reason` for why the type
34 /// { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
39 /// use std::collections::BTreeMap;
41 /// let x = std::collections::BTreeMap::new();
45 /// // A similar type that is allowed by the config
46 /// use std::collections::HashMap;
48 #[clippy::version = "1.55.0"]
51 "use of disallowed types"
53 #[derive(Clone, Debug)]
54 pub struct DisallowedTypes {
55 conf_disallowed: Vec<conf::DisallowedPath>,
56 def_ids: FxHashMap<DefId, usize>,
57 prim_tys: FxHashMap<PrimTy, usize>,
60 impl DisallowedTypes {
61 pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
64 def_ids: FxHashMap::default(),
65 prim_tys: FxHashMap::default(),
69 fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
72 if let Some(&index) = self.def_ids.get(did) {
73 emit(cx, &cx.tcx.def_path_str(*did), span, &self.conf_disallowed[index]);
76 Res::PrimTy(prim) => {
77 if let Some(&index) = self.prim_tys.get(prim) {
78 emit(cx, prim.name_str(), span, &self.conf_disallowed[index]);
86 impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
88 impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
89 fn check_crate(&mut self, cx: &LateContext<'_>) {
90 for (index, conf) in self.conf_disallowed.iter().enumerate() {
91 let segs: Vec<_> = conf.path().split("::").collect();
93 for res in clippy_utils::def_path_res(cx, &segs) {
96 self.def_ids.insert(id, index);
99 self.prim_tys.insert(ty, index);
107 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
108 if let ItemKind::Use(path, UseKind::Single) = &item.kind {
109 for res in &path.res {
110 self.check_res_emit(cx, res, item.span);
115 fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
116 if let TyKind::Path(path) = &ty.kind {
117 self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span);
121 fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) {
122 self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span);
126 fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) {
131 &format!("`{name}` is not allowed according to config"),
133 if let Some(reason) = conf.reason() {