rapx/analysis/safety_flow/
hir_visitor.rs1use crate::compat::FxHashMap;
2use rustc_hir::{
3 Block, BlockCheckMode, Body, BodyId, ExprKind, ImplItemKind, QPath, def_id::DefId, intravisit,
4 intravisit::Visitor,
5};
6use rustc_middle::ty::{self, Ty, TyCtxt};
7use std::collections::HashSet;
8
9pub struct ContainsUnsafe<'tcx> {
10 tcx: TyCtxt<'tcx>,
11 fn_unsafe: bool,
12 block_unsafe: bool,
13}
14
15impl<'tcx> ContainsUnsafe<'tcx> {
16 pub fn contains_unsafe(tcx: TyCtxt<'tcx>, body_id: BodyId) -> (bool, bool) {
17 let mut visitor = ContainsUnsafe {
18 tcx,
19 fn_unsafe: false,
20 block_unsafe: false,
21 };
22
23 let body = visitor.tcx.hir_body(body_id);
24 visitor.fn_unsafety(body);
25 visitor.visit_body(body);
26
27 (visitor.fn_unsafe, visitor.block_unsafe)
28 }
29
30 fn fn_unsafety(&mut self, body: &'tcx Body<'tcx>) {
35 let did = body.value.hir_id.owner.to_def_id();
36 if self.tcx.def_kind(did) == rustc_hir::def::DefKind::Fn
37 || self.tcx.def_kind(did) == rustc_hir::def::DefKind::AssocFn
38 {
39 let sig = self.tcx.fn_sig(did);
40 if let rustc_hir::Safety::Unsafe = sig.skip_binder().safety() {
41 self.fn_unsafe = true;
42 }
43 }
44 }
45}
46
47impl<'tcx> Visitor<'tcx> for ContainsUnsafe<'tcx> {
51 fn visit_block(&mut self, block: &'tcx Block<'tcx>) {
52 if let BlockCheckMode::UnsafeBlock(_unsafe_source) = block.rules {
53 self.block_unsafe = true;
54 }
55 intravisit::walk_block(self, block);
56 }
57}
58
59pub struct ContainsLit {
60 pub structs_used: HashSet<String>,
61}
62
63impl<'tcx> Visitor<'tcx> for ContainsLit {
64 fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) {
65 if let ExprKind::Struct(ref qpath, _, _) = expr.kind {
66 if let QPath::Resolved(_, path) = qpath {
67 if let Some(ident) = path.segments.last().map(|segment| segment.ident) {
68 self.structs_used.insert(ident.to_string());
69 }
70 }
71 }
72 intravisit::walk_expr(self, expr);
73 }
74}
75
76pub type AdtImplMap<'tcx> = FxHashMap<DefId, Vec<(DefId, Ty<'tcx>)>>;
82
83pub fn create_adt_impl_map(tcx: TyCtxt<'_>) -> AdtImplMap<'_> {
87 let mut map = FxHashMap::default();
88 for impl_item_id in tcx.hir_crate_items(()).impl_items() {
89 let impl_item = tcx.hir_impl_item(impl_item_id);
90 if let ImplItemKind::Type(ty) = impl_item.kind {
91 let impl_self_ty = tcx.type_of(ty.hir_id.owner).skip_binder();
92 if let ty::Adt(impl_self_adt_def, _impl_substs) = impl_self_ty.kind() {
93 map.entry(impl_self_adt_def.did())
94 .or_insert_with(Vec::new)
95 .push((impl_item_id.owner_id.to_def_id(), impl_self_ty));
96 }
97 }
98 }
99 map
100}