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