1use crate::{
2    analysis::{
3        core::{
4            alias_analysis::AAResult,
5            ownedheap_analysis::OHAResultMap,
6            range_analysis::{default::RangeAnalyzer, RangeAnalysis},
7        },
8        safedrop::graph::SafeDropGraph,
9        senryx::contracts::property::{CisRangeItem, PropertyContract},
10        utils::{
11            fn_info::{
12                display_hashmap, get_all_std_unsafe_callees, get_all_std_unsafe_callees_block_id,
13                get_callees, get_cleaned_def_path_name, is_ptr, is_ref,
14            },
15            show_mir::display_mir,
16        },
17        Analysis,
18    },
19    rap_debug, rap_warn,
20};
21use rustc_middle::ty::GenericParamDefKind;
22use serde::de;
23use std::{
24    collections::{HashMap, HashSet},
25    fmt::Debug,
26    hash::Hash,
27};
28use syn::Constraint;
29
30use super::contracts::abstract_state::{
31    AbstractStateItem, AlignState, PathInfo, StateType, VType, Value,
32};
33use super::contracts::contract::Contract;
34use super::dominated_graph::DominatedGraph;
35use super::dominated_graph::InterResultNode;
36use super::generic_check::GenericChecker;
37use super::inter_record::InterAnalysisRecord;
38use super::matcher::UnsafeApi;
39use super::matcher::{get_arg_place, parse_unsafe_api};
40use rustc_data_structures::fx::FxHashMap;
41use rustc_hir::def_id::DefId;
42use rustc_middle::{
43    mir::{
44        self, AggregateKind, BasicBlock, BasicBlockData, BinOp, CastKind, Local, Operand, Place,
45        ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
46    },
47    ty::{self, GenericArgKind, PseudoCanonicalInput, Ty, TyCtxt, TyKind},
48};
49use rustc_span::{source_map::Spanned, Span};
50
51pub struct CheckResult {
53    pub func_name: String,
54    pub func_span: Span,
55    pub failed_contracts: HashMap<usize, HashSet<String>>,
56    pub passed_contracts: HashMap<usize, HashSet<String>>,
57}
58
59impl CheckResult {
60    pub fn new(func_name: &str, func_span: Span) -> Self {
61        Self {
62            func_name: func_name.to_string(),
63            func_span,
64            failed_contracts: HashMap::new(),
65            passed_contracts: HashMap::new(),
66        }
67    }
68}
69
70#[derive(Debug, PartialEq, Eq, Clone)]
71pub enum PlaceTy<'tcx> {
72    Ty(usize, usize), GenericTy(String, HashSet<Ty<'tcx>>, HashSet<(usize, usize)>), Unknown,
75}
76
77impl<'tcx> PlaceTy<'tcx> {
78    pub fn possible_aligns(&self) -> HashSet<usize> {
79        match self {
80            PlaceTy::Ty(align, _size) => {
81                let mut set = HashSet::new();
82                set.insert(*align);
83                set
84            }
85            PlaceTy::GenericTy(_, _, tys) => tys.iter().map(|ty| ty.0).collect(),
86            _ => HashSet::new(),
87        }
88    }
89}
90
91impl<'tcx> Hash for PlaceTy<'tcx> {
92    fn hash<H: std::hash::Hasher>(&self, _state: &mut H) {}
93}
94
95pub struct BodyVisitor<'tcx> {
96    pub tcx: TyCtxt<'tcx>,
97    pub def_id: DefId,
98    pub safedrop_graph: SafeDropGraph<'tcx>,
99    pub abstract_states: HashMap<usize, PathInfo<'tcx>>,
101    pub unsafe_callee_report: HashMap<String, usize>,
102    pub local_ty: HashMap<usize, PlaceTy<'tcx>>,
103    pub visit_time: usize,
104    pub check_results: Vec<CheckResult>,
105    pub generic_map: HashMap<String, HashSet<Ty<'tcx>>>,
106    pub global_recorder: HashMap<DefId, InterAnalysisRecord<'tcx>>,
107    pub proj_ty: HashMap<usize, Ty<'tcx>>,
108    pub chains: DominatedGraph<'tcx>,
109    }
111
112impl<'tcx> BodyVisitor<'tcx> {
113    pub fn new(
114        tcx: TyCtxt<'tcx>,
115        def_id: DefId,
116        global_recorder: HashMap<DefId, InterAnalysisRecord<'tcx>>,
117        visit_time: usize,
118    ) -> Self {
119        let body = tcx.optimized_mir(def_id);
120        let param_env = tcx.param_env(def_id);
121        let satisfied_ty_map_for_generic =
122            GenericChecker::new(tcx, param_env).get_satisfied_ty_map();
123        let mut chains = DominatedGraph::new(tcx, def_id);
124        chains.init_arg();
125        Self {
126            tcx,
127            def_id,
128            safedrop_graph: SafeDropGraph::new(body, tcx, def_id, OHAResultMap::default()),
129            abstract_states: HashMap::new(),
130            unsafe_callee_report: HashMap::new(),
131            local_ty: HashMap::new(),
132            visit_time,
133            check_results: Vec::new(),
134            generic_map: satisfied_ty_map_for_generic,
135            global_recorder,
136            proj_ty: HashMap::new(),
137            chains,
138            }
140    }
141
142    pub fn get_ty_by_place(&self, p: usize) -> Ty<'tcx> {
143        let body = self.tcx.optimized_mir(self.def_id);
144        let locals = body.local_decls.clone();
145        return locals[Local::from(p)].ty;
146    }
147
148    pub fn update_fields_states(&mut self, inter_result: InterResultNode<'tcx>) {
149        self.chains.init_self_with_inter(inter_result);
150    }
151
152    pub fn path_forward_check(
153        &mut self,
154        fn_map: &FxHashMap<DefId, AAResult>,
155    ) -> InterResultNode<'tcx> {
156        let mut inter_return_value =
157            InterResultNode::construct_from_var_node(self.chains.clone(), 0);
158        if self.visit_time >= 1000 {
159            return inter_return_value;
160        }
161        let paths = self.get_all_paths();
163        let body = self.tcx.optimized_mir(self.def_id);
165        let target_name = get_cleaned_def_path_name(self.tcx, self.def_id);
166        let locals = body.local_decls.clone();
168        for (idx, local) in locals.iter().enumerate() {
169            let local_ty = local.ty;
170            let layout = self.visit_ty_and_get_layout(local_ty);
171            self.local_ty.insert(idx, layout);
172        }
173
174        let tmp_chain = self.chains.clone();
176        for (index, (path, constraint)) in paths.iter().enumerate() {
177            self.chains = tmp_chain.clone();
178            self.set_constraint(constraint);
179            self.abstract_states.insert(index, PathInfo::new());
180            for block_index in path.iter() {
181                if block_index >= &body.basic_blocks.len() {
182                    continue;
183                }
184                self.path_analyze_block(
185                    &body.basic_blocks[BasicBlock::from_usize(*block_index)].clone(),
186                    index,
187                    *block_index,
188                    fn_map,
189                );
190                let tem_scc_sub_blocks = self.safedrop_graph.blocks[*block_index]
191                    .scc_sub_blocks
192                    .clone();
193                if tem_scc_sub_blocks.len() > 0 {
194                    for sub_block in &tem_scc_sub_blocks {
195                        self.path_analyze_block(
196                            &body.basic_blocks[BasicBlock::from_usize(*sub_block)].clone(),
197                            index,
198                            *block_index,
199                            fn_map,
200                        );
201                    }
202                }
203            }
204            let curr_path_inter_return_value =
206                InterResultNode::construct_from_var_node(self.chains.clone(), 0);
207            inter_return_value.merge(curr_path_inter_return_value);
208        }
209        if self.visit_time == 0 && target_name.contains("into_raw_parts_with_alloc") {
210            display_mir(self.def_id, body);
211            display_hashmap(&self.chains.variables, 1);
212        }
213
214        inter_return_value
215    }
216
217    pub fn path_analyze_block(
218        &mut self,
219        block: &BasicBlockData<'tcx>,
220        path_index: usize,
221        bb_index: usize,
222        fn_map: &FxHashMap<DefId, AAResult>,
223    ) {
224        for statement in block.statements.iter() {
225            self.path_analyze_statement(statement, path_index);
226        }
227        self.path_analyze_terminator(&block.terminator(), path_index, bb_index, fn_map);
228    }
229
230    pub fn path_analyze_statement(&mut self, statement: &Statement<'tcx>, _path_index: usize) {
231        match statement.kind {
232            StatementKind::Assign(box (ref lplace, ref rvalue)) => {
233                self.path_analyze_assign(lplace, rvalue, _path_index);
234            }
235            StatementKind::Intrinsic(box ref intrinsic) => match intrinsic {
236                mir::NonDivergingIntrinsic::CopyNonOverlapping(cno) => {
237                    if cno.src.place().is_some() && cno.dst.place().is_some() {
238                        let _src_pjc_local =
239                            self.handle_proj(true, cno.src.place().unwrap().clone());
240                        let _dst_pjc_local =
241                            self.handle_proj(true, cno.dst.place().unwrap().clone());
242                    }
243                }
244                _ => {}
245            },
246            StatementKind::StorageDead(local) => {
247                }
249            _ => {}
250        }
251    }
252
253    pub fn path_analyze_terminator(
254        &mut self,
255        terminator: &Terminator<'tcx>,
256        path_index: usize,
257        bb_index: usize,
258        fn_map: &FxHashMap<DefId, AAResult>,
259    ) {
260        match &terminator.kind {
261            TerminatorKind::Call {
262                func,
263                args,
264                destination: dst_place,
265                target: _,
266                unwind: _,
267                call_source: _,
268                fn_span,
269            } => {
270                if let Operand::Constant(func_constant) = func {
271                    if let ty::FnDef(ref callee_def_id, raw_list) = func_constant.const_.ty().kind()
272                    {
273                        let mut mapping = FxHashMap::default();
274                        self.get_generic_mapping(raw_list.as_slice(), callee_def_id, &mut mapping);
275                        rap_debug!(
276                            "func {:?}, generic type mapping {:?}",
277                            callee_def_id,
278                            mapping
279                        );
280                        self.handle_call(
281                            dst_place,
282                            callee_def_id,
283                            args,
284                            path_index,
285                            fn_map,
286                            *fn_span,
287                            mapping,
288                        );
289                    }
290                }
291            }
292            TerminatorKind::Drop {
293                place,
294                target: _,
295                unwind: _,
296                replace: _,
297                drop: _,
298                async_fut: _,
299            } => {
300                let drop_local = self.handle_proj(false, *place);
301                if !self.chains.set_drop(drop_local) {
302                    }
307            }
308            _ => {}
309        }
310    }
311
312    fn get_generic_mapping(
317        &self,
318        raw_list: &[rustc_middle::ty::GenericArg<'tcx>],
319        def_id: &DefId,
320        generic_mapping: &mut FxHashMap<String, Ty<'tcx>>,
321    ) {
322        let generics = self.tcx.generics_of(def_id);
323        for param in &generics.own_params {
324            if let GenericParamDefKind::Type {
325                has_default: _,
326                synthetic: _,
327            } = param.kind
328            {
329                if let Some(ty) = raw_list.get(param.index as usize) {
330                    if let GenericArgKind::Type(actual_ty) = (*ty).kind() {
331                        let param_name = param.name.to_string();
332                        generic_mapping.insert(param_name, actual_ty);
333                    }
334                }
335            }
336        }
337        if generics.own_params.len() == 0 && generics.parent.is_some() {
338            let parent_def_id = generics.parent.unwrap();
339            self.get_generic_mapping(raw_list, &parent_def_id, generic_mapping);
340        }
341    }
342
343    pub fn path_analyze_assign(
344        &mut self,
345        lplace: &Place<'tcx>,
346        rvalue: &Rvalue<'tcx>,
347        path_index: usize,
348    ) {
349        let lpjc_local = self.handle_proj(false, lplace.clone());
350        match rvalue {
351            Rvalue::Use(op) => match op {
352                Operand::Move(rplace) => {
353                    let rpjc_local = self.handle_proj(true, rplace.clone());
354                    self.chains.merge(lpjc_local, rpjc_local);
355                }
356                Operand::Copy(rplace) => {
357                    let rpjc_local = self.handle_proj(true, rplace.clone());
358                    self.chains.copy_node(lpjc_local, rpjc_local);
359                }
360                _ => {}
361            },
362            Rvalue::Repeat(op, _const) => match op {
363                Operand::Move(rplace) | Operand::Copy(rplace) => {
364                    let _rpjc_local = self.handle_proj(true, rplace.clone());
365                }
366                _ => {}
367            },
368            Rvalue::Ref(_, _, rplace) | Rvalue::RawPtr(_, rplace) => {
369                let rpjc_local = self.handle_proj(true, rplace.clone());
370                self.chains.point(lpjc_local, rpjc_local);
372            }
373            Rvalue::Cast(cast_kind, op, ty) => match op {
374                Operand::Move(rplace) | Operand::Copy(rplace) => {
375                    let rpjc_local = self.handle_proj(true, rplace.clone());
376                    let r_point_to = self.chains.get_point_to_id(rpjc_local);
377                    if r_point_to == rpjc_local {
378                        self.chains.merge(lpjc_local, rpjc_local);
379                    } else {
380                        self.chains.point(lpjc_local, r_point_to);
381                    }
382                }
383                _ => {}
384            },
385            Rvalue::BinaryOp(_bin_op, box (ref _op1, ref _op2)) => {}
386            Rvalue::ShallowInitBox(op, _ty) => match op {
387                Operand::Move(rplace) | Operand::Copy(rplace) => {
388                    let _rpjc_local = self.handle_proj(true, rplace.clone());
389                }
390                _ => {}
391            },
392            Rvalue::Aggregate(box ref agg_kind, op_vec) => match agg_kind {
393                AggregateKind::Array(_ty) => {}
394                AggregateKind::Adt(_adt_def_id, _, _, _, _) => {
395                    for (idx, op) in op_vec.into_iter().enumerate() {
396                        let (is_const, val) = get_arg_place(op);
397                        if is_const {
398                            self.chains.insert_field_node(
399                                lpjc_local,
400                                idx,
401                                Some(Ty::new_uint(self.tcx, rustc_middle::ty::UintTy::Usize)),
402                            );
403                        } else {
404                            let node = self.chains.get_var_node_mut(lpjc_local).unwrap();
405                            node.field.insert(idx, val);
406                        }
407                    }
408                }
409                _ => {}
410            },
411            Rvalue::Discriminant(_place) => {
412                }
414            _ => {}
415        }
416    }
417
418    pub fn handle_call(
419        &mut self,
420        dst_place: &Place<'tcx>,
421        def_id: &DefId,
422        args: &Box<[Spanned<Operand>]>,
423        path_index: usize,
424        fn_map: &FxHashMap<DefId, AAResult>,
425        fn_span: Span,
426        generic_mapping: FxHashMap<String, Ty<'tcx>>,
427    ) {
428        if !self.tcx.is_mir_available(def_id) {
429            self.insert_path_abstate(
430                path_index,
431                dst_place.local.as_usize(),
432                AbstractStateItem::new_default(),
433            );
434            return;
435        }
436
437        if let Some(fn_result) =
439            parse_unsafe_api(get_cleaned_def_path_name(self.tcx, *def_id).as_str())
440        {
441            self.handle_std_unsafe_call(
442                dst_place,
443                def_id,
444                args,
445                path_index,
446                fn_map,
447                fn_span,
448                fn_result,
449                generic_mapping,
450            );
451        }
452
453        self.set_bound(def_id, dst_place, args);
454
455        self.handle_ret_alias(dst_place, def_id, fn_map, args);
457
458        }
499
500    fn set_bound(
501        &mut self,
502        def_id: &DefId,
503        dst_place: &Place<'tcx>,
504        args: &Box<[Spanned<Operand>]>,
505    ) {
506        if args.len() == 0 || !get_cleaned_def_path_name(self.tcx, *def_id).contains("slice::len") {
507            return;
508        }
509        let d_local = self.handle_proj(false, dst_place.clone());
510        let ptr_local = get_arg_place(&args[0].node).1;
511        let mem_local = self.chains.get_point_to_id(ptr_local);
512        let mem_var = self.chains.get_var_node_mut(mem_local).unwrap();
513        for cis in &mut mem_var.cis.contracts {
514            if let PropertyContract::InBound(cis_ty, len) = cis {
515                *len = CisRangeItem::new_var(d_local);
516            }
517        }
518    }
519
520    pub fn handle_ret_alias(
522        &mut self,
523        dst_place: &Place<'tcx>,
524        def_id: &DefId,
525        fn_map: &FxHashMap<DefId, AAResult>,
526        args: &Box<[Spanned<Operand>]>,
527    ) {
528        let d_local = self.handle_proj(false, dst_place.clone());
529        if let Some(retalias) = fn_map.get(def_id) {
532            for alias_set in retalias.aliases() {
533                let (l, r) = (alias_set.lhs_no, alias_set.rhs_no);
534                let (l_fields, r_fields) =
535                    (alias_set.lhs_fields.clone(), alias_set.rhs_fields.clone());
536                let (l_place, r_place) = (
537                    if l != 0 {
538                        get_arg_place(&args[l - 1].node)
539                    } else {
540                        (false, d_local)
541                    },
542                    if r != 0 {
543                        get_arg_place(&args[r - 1].node)
544                    } else {
545                        (false, d_local)
546                    },
547                );
548                if l_place.0 {
550                    let snd_var = self.chains.find_var_id_with_fields_seq(r_place.1, r_fields);
551                    self.chains
552                        .update_value(self.chains.get_point_to_id(snd_var), l_place.1);
553                    continue;
554                }
555                if r_place.0 {
557                    let fst_var = self.chains.find_var_id_with_fields_seq(l_place.1, l_fields);
558                    self.chains
559                        .update_value(self.chains.get_point_to_id(fst_var), r_place.1);
560                    continue;
561                }
562                let (fst_var, snd_var) = (
563                    self.chains.find_var_id_with_fields_seq(l_place.1, l_fields),
564                    self.chains.find_var_id_with_fields_seq(r_place.1, r_fields),
565                );
566                let fst_to = self.chains.get_point_to_id(fst_var);
568                let snd_to = self.chains.get_point_to_id(snd_var);
569                let is_fst_point = fst_to != fst_var;
570                let is_snd_point = snd_to != snd_var;
571                let fst_node = self.chains.get_var_node(fst_var).unwrap();
572                let snd_node = self.chains.get_var_node(snd_var).unwrap();
573                let is_fst_ptr = is_ptr(fst_node.ty.unwrap()) || is_ref(fst_node.ty.unwrap());
574                let is_snd_ptr = is_ptr(snd_node.ty.unwrap()) || is_ref(snd_node.ty.unwrap());
575                rap_debug!(
576                    "{:?}: {fst_var},{fst_to},{is_fst_ptr} -- {snd_var},{snd_to},{is_snd_ptr}",
577                    def_id
578                );
579                match (is_fst_ptr, is_snd_ptr) {
580                    (false, true) => {
581                        if is_snd_point {
583                            self.chains.point(snd_var, fst_var);
584                        } else {
585                            self.chains.merge(fst_var, snd_to);
586                        }
587                    }
588                    (false, false) => {
589                        self.chains.merge(fst_var, snd_var);
590                    }
591                    (true, true) => {
592                        if is_fst_point && is_snd_point {
593                            self.chains.merge(fst_to, snd_to);
594                        } else if !is_fst_point && is_snd_point {
595                            self.chains.point(fst_var, snd_to);
596                        } else if is_fst_point && !is_snd_point {
597                            self.chains.point(snd_var, fst_to);
598                        } else {
599                            self.chains.merge(fst_var, snd_var);
600                        }
601                    }
602                    (true, false) => {
603                        if is_fst_point {
604                            self.chains.point(fst_var, snd_var);
605                        } else {
606                            self.chains.merge(snd_var, fst_to);
607                        }
608                    }
609                }
610            }
611        }
612        else {
614            let d_ty = self.chains.get_local_ty_by_place(d_local);
615            if d_ty.is_some() && (is_ptr(d_ty.unwrap()) || is_ref(d_ty.unwrap())) {
616                self.chains
617                    .generate_ptr_with_obj_node(d_ty.unwrap(), d_local);
618            }
619        }
620    }
621
622    pub fn update_post_state(
624        &mut self,
625        post_state: &HashMap<usize, AbstractStateItem<'tcx>>,
626        args: &Box<[Spanned<Operand>]>,
627        path_index: usize,
628    ) {
629        for (idx, arg) in args.iter().enumerate() {
630            let arg_place = get_arg_place(&arg.node);
631            if let Some(state_item) = post_state.get(&idx) {
632                self.insert_path_abstate(path_index, arg_place.1, state_item.clone());
633            }
634        }
635    }
636
637    pub fn get_args_post_states(&mut self) -> HashMap<usize, AbstractStateItem<'tcx>> {
638        let tcx = self.tcx;
639        let def_id = self.def_id;
640        let final_states = self.abstract_states_mop();
641        let mut result_states = HashMap::new();
642        let fn_sig = tcx.fn_sig(def_id).skip_binder();
643        let num_params = fn_sig.inputs().skip_binder().len();
644        for i in 0..num_params + 1 {
645            if let Some(state) = final_states.state_map.get(&(i)) {
646                result_states.insert(i, state.clone());
647            } else {
648                result_states.insert(i, AbstractStateItem::new_default());
649            }
650        }
651        result_states
652    }
653
654    pub fn get_all_paths(&mut self) -> HashMap<Vec<usize>, Vec<(Place<'tcx>, Place<'tcx>, BinOp)>> {
655        let mut range_analyzer = RangeAnalyzer::<i128>::new(self.tcx, false);
656        let path_constraints_option =
657            range_analyzer.start_path_constraints_analysis_for_defid(self.def_id); let mut path_constraints: HashMap<Vec<usize>, Vec<(_, _, _)>> =
659            if path_constraints_option.is_none() {
660                let mut results = HashMap::new();
661                let paths: Vec<Vec<usize>> = self.safedrop_graph.get_paths();
662                for path in paths {
663                    results.insert(path, Vec::new());
664                }
665                results
666            } else {
667                path_constraints_option.unwrap()
668            };
669        self.safedrop_graph.solve_scc();
670        if self.visit_time == 0 {
672            let contains_unsafe_blocks = get_all_std_unsafe_callees_block_id(self.tcx, self.def_id);
673            path_constraints.retain(|path, cons| {
674                path.iter()
675                    .any(|block_id| contains_unsafe_blocks.contains(block_id))
676            });
677        }
678        path_constraints
680    }
681
682    pub fn abstract_states_mop(&mut self) -> PathInfo<'tcx> {
697        let mut result_state = PathInfo {
698            state_map: HashMap::new(),
699        };
700
701        for (_path_idx, abstract_state) in &self.abstract_states {
702            for (var_index, state_item) in &abstract_state.state_map {
703                if let Some(existing_state_item) = result_state.state_map.get_mut(&var_index) {
704                    existing_state_item
705                        .clone()
706                        .meet_state_item(&state_item.clone());
707                } else {
708                    result_state
709                        .state_map
710                        .insert(*var_index, state_item.clone());
711                }
712            }
713        }
714        result_state
715    }
716
717    pub fn update_callee_report_level(&mut self, unsafe_callee: String, report_level: usize) {
718        self.unsafe_callee_report
719            .entry(unsafe_callee)
720            .and_modify(|e| {
721                if report_level < *e {
722                    *e = report_level;
723                }
724            })
725            .or_insert(report_level);
726    }
727
728    pub fn output_results(&self, threshold: usize) {
731        for (unsafe_callee, report_level) in &self.unsafe_callee_report {
732            if *report_level == 0 {
733                rap_warn!("Find one bug in {:?}!", unsafe_callee);
734            } else if *report_level <= threshold {
735                rap_warn!("Find an unsoundness issue in {:?}!", unsafe_callee);
736            }
737        }
738    }
739
740    pub fn insert_path_abstate(
741        &mut self,
742        path_index: usize,
743        place: usize,
744        abitem: AbstractStateItem<'tcx>,
745    ) {
746        self.abstract_states
747            .entry(path_index)
748            .or_insert_with(|| PathInfo {
749                state_map: HashMap::new(),
750            })
751            .state_map
752            .insert(place, abitem);
753    }
754
755    pub fn set_constraint(&mut self, constraint: &Vec<(Place<'tcx>, Place<'tcx>, BinOp)>) {
756        for (p1, p2, op) in constraint {
757            let p1_num = self.handle_proj(false, p1.clone());
758            let p2_num = self.handle_proj(false, p2.clone());
759            self.chains.insert_patial_op(p1_num, p2_num, op);
760        }
761    }
762
763    pub fn get_layout_by_place_usize(&self, place: usize) -> PlaceTy<'tcx> {
764        if let Some(ty) = self.chains.get_obj_ty_through_chain(place) {
765            return self.visit_ty_and_get_layout(ty);
766        } else {
767            return PlaceTy::Unknown;
768        }
769    }
770
771    pub fn visit_ty_and_get_layout(&self, ty: Ty<'tcx>) -> PlaceTy<'tcx> {
772        match ty.kind() {
773            TyKind::RawPtr(ty, _)
774            | TyKind::Ref(_, ty, _)
775            | TyKind::Slice(ty)
776            | TyKind::Array(ty, _) => self.visit_ty_and_get_layout(*ty),
777            TyKind::Param(param_ty) => {
778                let generic_name = param_ty.name.to_string();
779                let mut layout_set: HashSet<(usize, usize)> = HashSet::new();
780                let ty_set = self.generic_map.get(&generic_name.clone());
781                if ty_set.is_none() {
782                    if self.visit_time == 0 {
783                        rap_warn!(
784                            "Can not get generic type set: {:?}, def_id:{:?}",
785                            generic_name,
786                            self.def_id
787                        );
788                    }
789                    return PlaceTy::GenericTy(generic_name, HashSet::new(), layout_set);
790                }
791                for ty in ty_set.unwrap().clone() {
792                    if let PlaceTy::Ty(align, size) = self.visit_ty_and_get_layout(ty) {
793                        layout_set.insert((align, size));
794                    }
795                }
796                return PlaceTy::GenericTy(generic_name, ty_set.unwrap().clone(), layout_set);
797            }
798            TyKind::Adt(def, _list) => {
799                if def.is_enum() {
800                    return PlaceTy::Unknown;
801                } else {
802                    PlaceTy::Unknown
803                }
804            }
805            TyKind::Closure(_, _) => PlaceTy::Unknown,
806            TyKind::Alias(_, ty) => {
807                return self.visit_ty_and_get_layout(ty.self_ty());
809            }
810            _ => {
811                let param_env = self.tcx.param_env(self.def_id);
812                let ty_env = ty::TypingEnv::post_analysis(self.tcx, self.def_id);
813                let input = PseudoCanonicalInput {
814                    typing_env: ty_env,
815                    value: ty,
816                };
817                if let Ok(layout) = self.tcx.layout_of(input) {
818                    let align = layout.align.abi.bytes_usize();
820                    let size = layout.size.bytes() as usize;
821                    return PlaceTy::Ty(align, size);
822                } else {
823                    PlaceTy::Unknown
825                }
826            }
827        }
828    }
829
830    pub fn get_abstate_by_place_in_path(
831        &self,
832        place: usize,
833        path_index: usize,
834    ) -> AbstractStateItem<'tcx> {
835        if let Some(abstate) = self.abstract_states.get(&path_index) {
836            if let Some(abs) = abstate.state_map.get(&place).cloned() {
837                return abs;
838            }
839        }
840        AbstractStateItem::new_default()
841    }
842
843    pub fn handle_cast(
844        &mut self,
845        rpjc_local: usize,
846        lpjc_local: usize,
847        ty: &Ty<'tcx>,
848        path_index: usize,
849        cast_kind: &CastKind,
850    ) {
851        let mut src_ty = self.get_layout_by_place_usize(rpjc_local);
852        match cast_kind {
853            CastKind::PtrToPtr | CastKind::PointerCoercion(_, _) => {
854                let r_abitem = self.get_abstate_by_place_in_path(rpjc_local, path_index);
855                for state in &r_abitem.state {
856                    if let StateType::AlignState(r_align_state) = state.clone() {
857                        match r_align_state {
858                            AlignState::Cast(from, _to) => {
859                                src_ty = from.clone();
860                            }
861                            _ => {}
862                        }
863                    }
864                }
865
866                let dst_ty = self.visit_ty_and_get_layout(*ty);
867                let align_state =
868                    StateType::AlignState(AlignState::Cast(src_ty.clone(), dst_ty.clone()));
869                let abitem = AbstractStateItem::new(
870                    (Value::None, Value::None),
871                    VType::Pointer(dst_ty),
872                    HashSet::from([align_state]),
873                );
874                self.insert_path_abstate(path_index, lpjc_local, abitem);
875            }
876            _ => {}
877        }
878    }
879
880    pub fn handle_binary_op(
881        &mut self,
882        first_op: &Operand,
883        bin_op: &BinOp,
884        second_op: &Operand,
885        path_index: usize,
886    ) {
887        match bin_op {
888            BinOp::Offset => {
889                let _first_place = get_arg_place(first_op);
890                let _second_place = get_arg_place(second_op);
891            }
892            _ => {}
893        }
894    }
895
896    pub fn handle_proj(&mut self, is_right: bool, place: Place<'tcx>) -> usize {
897        let mut proj_id = place.local.as_usize();
898        for proj in place.projection {
899            match proj {
900                ProjectionElem::Deref => {
901                    proj_id = self.chains.get_point_to_id(place.local.as_usize());
902                    if proj_id == place.local.as_usize() {
903                        proj_id = self.chains.check_ptr(proj_id);
904                    }
905                }
906                ProjectionElem::Field(field, ty) => {
907                    proj_id = self
908                        .chains
909                        .get_field_node_id(proj_id, field.as_usize(), Some(ty));
910                }
911                _ => {}
912            }
913        }
914        proj_id
915    }
916}