rapx/analysis/api_dependency/
fuzzable.rs1#[cfg(not(rapx_ge_100))]
2use rustc_hir::LangItem;
3#[cfg(rapx_ge_100)]
4use rustc_hir::attrs::lang_items::LangItem;
5use rustc_middle::ty::{self, Ty, TyCtxt, TyKind};
6use rustc_span::sym;
7
8fn is_fuzzable_std_ty<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, depth: usize) -> bool {
9 match ty.kind() {
10 ty::Adt(def, args) => {
11 if tcx.is_lang_item(def.did(), LangItem::String) {
12 return true;
13 }
14 if tcx.is_diagnostic_item(sym::Vec, def.did())
15 && is_fuzzable_ty(args.type_at(0), tcx, depth + 1)
16 {
17 return true;
18 }
19 if tcx.is_diagnostic_item(sym::Arc, def.did())
20 && is_fuzzable_ty(args.type_at(0), tcx, depth + 1)
21 {
22 return true;
23 }
24 false
25 }
26 _ => false,
27 }
28}
29
30fn is_non_fuzzable_std_ty<'tcx>(ty: Ty<'tcx>, _tcx: TyCtxt<'tcx>) -> bool {
31 let name = format!("{}", ty);
32 match name.as_str() {
33 "core::alloc::LayoutError" => return true,
34 _ => {}
35 }
36 false
37}
38
39const MAX_DEPTH: usize = 64;
40pub fn is_fuzzable_ty<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, depth: usize) -> bool {
41 if depth > MAX_DEPTH {
42 return false;
43 }
44
45 if is_fuzzable_std_ty(ty, tcx, depth + 1) {
46 return true;
47 }
48
49 if is_non_fuzzable_std_ty(ty, tcx) {
50 return false;
51 }
52
53 match ty.kind() {
54 TyKind::Bool
56 | TyKind::Char
57 | TyKind::Int(_)
58 | TyKind::Uint(_)
59 | TyKind::Float(_)
60 | TyKind::Str => true,
61
62 TyKind::Infer(
64 ty::InferTy::IntVar(_)
65 | ty::InferTy::FreshIntTy(_)
66 | ty::InferTy::FloatVar(_)
67 | ty::InferTy::FreshFloatTy(_),
68 ) => true,
69
70 TyKind::Ref(_, inner_ty, _) | TyKind::Slice(inner_ty) => {
72 is_fuzzable_ty(inner_ty.peel_refs(), tcx, depth + 1)
73 }
74
75 TyKind::Array(inner_ty, const_) => {
76 if const_.try_to_value().is_none() {
77 return false;
78 }
79 is_fuzzable_ty(inner_ty.peel_refs(), tcx, depth + 1)
80 }
81
82 TyKind::Tuple(tys) => tys
84 .iter()
85 .all(|inner_ty| is_fuzzable_ty(inner_ty.peel_refs(), tcx, depth + 1)),
86
87 TyKind::Adt(adt_def, args) => {
89 if adt_def.is_union() {
90 return false;
91 }
92
93 if adt_def.is_variant_list_non_exhaustive() {
94 return false;
95 }
96
97 if args.iter().any(|arg| arg.as_region().is_some()) {
99 return false;
100 }
101
102 if !adt_def.all_fields().all(|field| {
104 #[cfg(not(rapx_ge_99))]
105 let field_ty = field.ty(tcx, args);
106 #[cfg(rapx_ge_99)]
107 let field_ty = field.ty(tcx, args).skip_norm_wip();
108 field.vis.is_public() && is_fuzzable_ty(field_ty, tcx, depth + 1)
109 }) {
110 return false;
111 }
112
113 if adt_def.is_enum() && adt_def.variants().is_empty() {
115 return false;
116 }
117
118 true
119 }
120
121 _ => false,
123 }
124}