rapx/analysis/api_dependency/
fuzzable.rs1#[cfg(not(rapx_has_skip_norm_wip))]
2use crate::compat::SkipNormWip;
3use crate::limit::FUZZABLE_MAX_DEPTH;
4#[cfg(rapx_has_attr_ir)]
5use rustc_attr_ir::LangItem;
6#[cfg(all(not(rapx_has_attr_ir), not(rapx_ge_100)))]
7use rustc_hir::LangItem;
8#[cfg(all(not(rapx_has_attr_ir), rapx_ge_100))]
9use rustc_hir::attrs::lang_items::LangItem;
10#[cfg(rapx_has_attr_ir)]
11use rustc_attr_ir::find_attr;
12#[cfg(rapx_has_attr_ir)]
13use rustc_attr_ir::AttributeKind;
14#[cfg(not(rapx_has_attr_ir))]
15use rustc_hir::find_attr;
16#[cfg(not(rapx_has_attr_ir))]
17use rustc_hir::attrs::AttributeKind;
18#[cfg(rapx_const_ext)]
19use rustc_middle::ty::consts::ConstExt;
20use rustc_middle::ty::{self, Ty, TyCtxt, TyKind};
21use rustc_span::sym;
22use rustc_type_ir::TypeVisitable;
23
24fn is_fuzzable_std_ty<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, depth: usize) -> bool {
25 match ty.kind() {
26 ty::Adt(def, args) => {
27 if tcx.is_lang_item(def.did(), LangItem::String) {
28 return true;
29 }
30 if tcx.is_diagnostic_item(sym::Vec, def.did())
31 && is_fuzzable_ty(args.type_at(0), tcx, depth + 1)
32 {
33 return true;
34 }
35 if tcx.is_diagnostic_item(sym::Arc, def.did())
36 && is_fuzzable_ty(args.type_at(0), tcx, depth + 1)
37 {
38 return true;
39 }
40 false
41 }
42 _ => false,
43 }
44}
45
46fn is_non_fuzzable_std_ty<'tcx>(ty: Ty<'tcx>, _tcx: TyCtxt<'tcx>) -> bool {
47 let name = format!("{}", ty);
48 if name.as_str() == "core::alloc::LayoutError" { return true }
49 false
50}
51
52fn ty_contains_region<'tcx>(ty: Ty<'tcx>) -> bool {
53 struct Visitor {
54 contains_region: bool,
55 }
56 impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for Visitor {
57 fn visit_region(&mut self, _: ty::Region<'tcx>) -> Self::Result {
58 self.contains_region = true;
59 }
60 }
61 let mut visitor = Visitor {
62 contains_region: false,
63 };
64 ty.visit_with(&mut visitor);
65 visitor.contains_region
66}
67
68pub fn has_non_exhaustive_attr(tcx: TyCtxt<'_>, adt: ty::AdtDef<'_>) -> bool {
72 adt.is_variant_list_non_exhaustive()
73 || find_attr!(
74 crate::compat::get_all_attrs(tcx, adt.did()),
75 AttributeKind::NonExhaustive(..)
76 )
77 || adt.variants().iter().any(|variant_def| {
78 variant_def.is_field_list_non_exhaustive()
79 || find_attr!(
80 crate::compat::get_all_attrs(tcx, variant_def.def_id),
81 AttributeKind::NonExhaustive(..)
82 )
83 })
84 || adt.all_fields().any(|field_def| {
85 find_attr!(
86 crate::compat::get_all_attrs(tcx, field_def.did),
87 AttributeKind::NonExhaustive(..)
88 )
89 })
90}
91
92pub fn is_fuzzable_ty<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>, depth: usize) -> bool {
93 if depth > FUZZABLE_MAX_DEPTH {
94 return false;
95 }
96
97 if is_fuzzable_std_ty(ty, tcx, depth + 1) {
98 return true;
99 }
100
101 if is_non_fuzzable_std_ty(ty, tcx) {
102 return false;
103 }
104
105 match ty.kind() {
106 TyKind::Bool
108 | TyKind::Char
109 | TyKind::Int(_)
110 | TyKind::Uint(_)
111 | TyKind::Float(_)
112 | TyKind::Str => true,
113
114 TyKind::Infer(
116 ty::InferTy::IntVar(_)
117 | ty::InferTy::FreshIntTy(_)
118 | ty::InferTy::FloatVar(_)
119 | ty::InferTy::FreshFloatTy(_),
120 ) => true,
121
122 TyKind::Ref(_, inner_ty, _) | TyKind::Slice(inner_ty) => {
124 is_fuzzable_ty(inner_ty.peel_refs(), tcx, depth + 1)
125 }
126
127 TyKind::Array(inner_ty, const_) => {
128 if const_.try_to_value().is_none() {
129 return false;
130 }
131 is_fuzzable_ty(inner_ty.peel_refs(), tcx, depth + 1)
132 }
133
134 TyKind::Tuple(tys) => tys
136 .iter()
137 .all(|inner_ty| is_fuzzable_ty(inner_ty.peel_refs(), tcx, depth + 1)),
138
139 TyKind::Adt(adt_def, args) => {
141 if adt_def.is_union() || has_non_exhaustive_attr(tcx, *adt_def) {
142 return false;
143 }
144 if ty_contains_region(ty) {
146 return false;
147 }
148
149 if !adt_def.all_fields().all(|field| {
151 field.vis.is_public()
152 && is_fuzzable_ty(field.ty(tcx, args).skip_norm_wip(), tcx, depth + 1)
153 }) {
154 return false;
155 }
156
157 if adt_def.is_enum() && adt_def.variants().is_empty() {
159 return false;
160 }
161
162 true
163 }
164 _ => false,
165 }
166}