rapx/analysis/core/api_dependency/
utils.rs

1use rustc_hir::def_id::DefId;
2use rustc_hir::LangItem;
3use rustc_middle::ty::{self, FnSig, Ty, TyCtxt, TyKind};
4use rustc_span::sym;
5
6fn is_fuzzable_std_ty<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
7    match ty.kind() {
8        ty::Adt(def, _) => {
9            tcx.is_lang_item(def.did(), LangItem::String)
10                || tcx.is_diagnostic_item(sym::Vec, def.did())
11                || tcx.is_diagnostic_item(sym::Arc, def.did())
12        }
13        _ => false,
14    }
15}
16
17pub fn is_fuzzable_ty<'tcx>(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
18    if is_fuzzable_std_ty(ty, tcx) {
19        return true;
20    }
21
22    match ty.kind() {
23        // Basical data type
24        TyKind::Bool
25        | TyKind::Char
26        | TyKind::Int(_)
27        | TyKind::Uint(_)
28        | TyKind::Float(_)
29        | TyKind::Str => true,
30
31        // Infer
32        TyKind::Infer(
33            ty::InferTy::IntVar(_)
34            | ty::InferTy::FreshIntTy(_)
35            | ty::InferTy::FloatVar(_)
36            | ty::InferTy::FreshFloatTy(_),
37        ) => true,
38
39        // Reference, Array, Slice
40        TyKind::Ref(_, inner_ty, _) | TyKind::Array(inner_ty, _) | TyKind::Slice(inner_ty) => {
41            is_fuzzable_ty(inner_ty.peel_refs(), tcx)
42        }
43
44        // Tuple
45        TyKind::Tuple(tys) => tys
46            .iter()
47            .all(|inner_ty| is_fuzzable_ty(inner_ty.peel_refs(), tcx)),
48
49        // ADT
50        TyKind::Adt(adt_def, substs) => {
51            if adt_def.variant_list_has_applicable_non_exhaustive() {
52                return false;
53            }
54            if adt_def.is_struct() {
55                // 检查所有字段是否为 pub 且类型可 Fuzz
56                adt_def.all_fields().all(|field| {
57                    field.vis.is_public() && // 字段必须是 pub
58                    is_fuzzable_ty(field.ty(tcx, substs).peel_refs(), tcx)
59                })
60            } else if adt_def.is_enum() {
61                adt_def.variants().iter().all(|variant| {
62                    variant
63                        .fields
64                        .iter()
65                        .all(|field| is_fuzzable_ty(field.ty(tcx, substs).peel_refs(), tcx))
66                })
67            } else {
68                false // union 暂不处理
69            }
70        }
71
72        // 其他类型默认不可 Fuzz
73        _ => false,
74    }
75}
76
77pub fn fn_sig_without_binders<'tcx>(fn_did: DefId, tcx: TyCtxt<'tcx>) -> FnSig<'tcx> {
78    let early_fn_sig = tcx.fn_sig(fn_did);
79    let binder_fn_sig = early_fn_sig.instantiate_identity();
80    tcx.liberate_late_bound_regions(fn_did, binder_fn_sig)
81}
82
83pub fn fn_sig_with_generic_args<'tcx>(
84    fn_did: DefId,
85    args: &[ty::GenericArg<'tcx>],
86    tcx: TyCtxt<'tcx>,
87) -> FnSig<'tcx> {
88    let early_fn_sig = tcx.fn_sig(fn_did);
89    let binder_fn_sig = early_fn_sig.instantiate(tcx, args);
90    tcx.liberate_late_bound_regions(fn_did, binder_fn_sig)
91}
92
93pub fn fn_requires_monomorphization<'tcx>(fn_did: DefId, tcx: TyCtxt<'_>) -> bool {
94    tcx.generics_of(fn_did).requires_monomorphization(tcx)
95}
96
97pub fn is_ty_eq<'tcx>(ty1: Ty<'tcx>, ty2: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> bool {
98    let ty1 = tcx.erase_and_anonymize_regions(ty1);
99    let ty2 = tcx.erase_and_anonymize_regions(ty2);
100    return ty1 == ty2;
101}
102
103pub fn ty_complexity<'tcx>(ty: Ty<'tcx>) -> usize {
104    match ty.kind() {
105        // Reference, Array, Slice
106        TyKind::Ref(_, inner_ty, _) | TyKind::Array(inner_ty, _) | TyKind::Slice(inner_ty) => {
107            ty_complexity(*inner_ty) + 1
108        }
109
110        // Tuple
111        TyKind::Tuple(tys) => tys.iter().fold(0, |ans, ty| ans.max(ty_complexity(ty))) + 1,
112
113        // ADT
114        TyKind::Adt(_, args) => {
115            args.iter().fold(0, |ans, arg| {
116                if let Some(ty) = arg.as_type() {
117                    ans.max(ty_complexity(ty))
118                } else {
119                    ans
120                }
121            }) + 1
122        }
123
124        // the depth of other primitive type default to 1
125        _ => 1,
126    }
127}