1 use clippy_utils::diagnostics::span_lint_and_then;
3 use rustc_data_structures::fx::FxHashMap;
5 def::Res, def_id::DefId, Item, ItemKind, PolyTraitRef, PrimTy, TraitBoundModifier, 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 /// ### Why is this bad?
18 /// Some types are undesirable in certain contexts.
21 /// An example clippy.toml configuration:
24 /// disallowed-types = [
25 /// # Can use a string as the path of the disallowed type.
26 /// "std::collections::BTreeMap",
27 /// # Can also use an inline table with a `path` key.
28 /// { path = "std::net::TcpListener" },
29 /// # When using an inline table, can add a `reason` for why the type
31 /// { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" },
36 /// use std::collections::BTreeMap;
38 /// let x = std::collections::BTreeMap::new();
42 /// // A similar type that is allowed by the config
43 /// use std::collections::HashMap;
45 #[clippy::version = "1.55.0"]
48 "use of disallowed types"
50 #[derive(Clone, Debug)]
51 pub struct DisallowedTypes {
52 conf_disallowed: Vec<conf::DisallowedType>,
53 def_ids: FxHashMap<DefId, Option<String>>,
54 prim_tys: FxHashMap<PrimTy, Option<String>>,
57 impl DisallowedTypes {
58 pub fn new(conf_disallowed: Vec<conf::DisallowedType>) -> Self {
61 def_ids: FxHashMap::default(),
62 prim_tys: FxHashMap::default(),
66 fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
69 if let Some(reason) = self.def_ids.get(did) {
70 emit(cx, &cx.tcx.def_path_str(*did), span, reason.as_deref());
73 Res::PrimTy(prim) => {
74 if let Some(reason) = self.prim_tys.get(prim) {
75 emit(cx, prim.name_str(), span, reason.as_deref());
83 impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
85 impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
86 fn check_crate(&mut self, cx: &LateContext<'_>) {
87 for conf in &self.conf_disallowed {
88 let (path, reason) = match conf {
89 conf::DisallowedType::Simple(path) => (path, None),
90 conf::DisallowedType::WithReason { path, reason } => (
92 reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
95 let segs: Vec<_> = path.split("::").collect();
96 match clippy_utils::path_to_res(cx, &segs) {
98 self.def_ids.insert(id, reason);
101 self.prim_tys.insert(ty, reason);
108 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
109 if let ItemKind::Use(path, UseKind::Single) = &item.kind {
110 self.check_res_emit(cx, &path.res, item.span);
114 fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) {
115 if let TyKind::Path(path) = &ty.kind {
116 self.check_res_emit(cx, &cx.qpath_res(path, ty.hir_id), ty.span);
120 fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>, _: TraitBoundModifier) {
121 self.check_res_emit(cx, &poly.trait_ref.path.res, poly.trait_ref.path.span);
125 fn emit(cx: &LateContext<'_>, name: &str, span: Span, reason: Option<&str>) {
130 &format!("`{}` is not allowed according to config", name),
132 if let Some(reason) = reason {