rapx/analysis/core/
heap_analysis.rs

1pub mod default;
2
3use rustc_abi::VariantIdx;
4use rustc_middle::ty::{Ty, TyCtxt, TyKind};
5use rustc_span::def_id::DefId;
6
7use std::{
8    collections::{HashMap, HashSet},
9    env, fmt,
10};
11
12use crate::{rap_info, Analysis};
13
14#[repr(u8)]
15#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
16pub enum RawTypeOwner {
17    Unowned = 0,
18    Owned = 1,
19    Unknown = 2,
20}
21
22impl Default for RawTypeOwner {
23    fn default() -> Self {
24        Self::Unknown
25    }
26}
27
28impl RawTypeOwner {
29    pub fn is_owned(&self) -> bool {
30        match self {
31            RawTypeOwner::Owned => true,
32            _ => false,
33        }
34    }
35}
36
37impl fmt::Display for RawTypeOwner {
38    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39        let name = match self {
40            RawTypeOwner::Unowned => "0",
41            RawTypeOwner::Owned => "1",
42            RawTypeOwner::Unknown => "2",
43        };
44        write!(f, "{}", name)
45    }
46}
47
48pub type HAResult = HashMap<DefId, Vec<(RawTypeOwner, Vec<bool>)>>;
49
50pub trait HeapAnalysis: Analysis {
51    fn get_all_items(&mut self) -> HAResult;
52}
53
54#[derive(Copy, Clone, Debug)]
55pub struct HeapItem;
56
57impl HeapItem {
58    /// This method is used to check if one adt-def is already a heap item.
59    /// It is a summary of one type which demonstrate that we will consider all the fields/variants,
60    /// although the analyzer will not traverse them (thus overhead is cheap).
61    ///
62    /// # Safety
63    /// If `ty` is not an adt, the result is `Err`.
64    ///
65    /// # Case `ty::Ty`
66    /// Given the adt `MyVec<T, A>` the result is `Ok(true)`.
67    /// ```rust
68    /// pub struct MyVec<T, A: Allocator = Global> {
69    ///    buf: RawVec<T, A>, // this field is a heap item
70    ///    len: usize,
71    /// }
72    /// ```
73    ///
74    /// # Example:
75    /// ```rust
76    ///  use rap::analysis::core::heap_item::HeapItem;
77    ///  let ans = HeapItem::is_adt(rcanary.rcx, vec.ty);
78    /// ```
79    pub fn is_adt<'tcx>(adt_owner: HAResult, ty: Ty<'tcx>) -> Result<bool, &'static str> {
80        match ty.kind() {
81            TyKind::Adt(adtdef, ..) => {
82                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
83                for i in ans.iter() {
84                    if i.0 == RawTypeOwner::Owned {
85                        return Ok(true);
86                    }
87                }
88                Ok(false)
89            }
90            _ => Err("The input is not an ADT"),
91        }
92    }
93
94    /// This method is used to check if one adt-def of the struct is already a heap item.
95    /// It is a summary of one type which demonstrate that we will consider all the fields,
96    /// although the analyzer will not traverse them (thus overhead is cheap).
97    ///
98    /// # Safety
99    /// If `ty` is not an adt, the result is `Err`.
100    /// If the input is the def of an enum type, the result is `Err`.
101    ///
102    /// # Case `ty::Ty`
103    /// Given the adt `MyVec<T, A>` the result is `Ok(true)`.
104    /// ```rust
105    /// pub struct MyVec<T, A: Allocator = Global> {
106    ///    buf: RawVec<T, A>, // this field is a heap item
107    ///    len: usize,
108    /// }
109    /// ```
110    ///
111    /// # Example:
112    /// ```rust
113    /// use rap::analysis::core::heap_item::HeapItem;
114    /// let ans = HeapItem::is_struct(rcanary.rcx, vec.ty);
115    /// ```
116    pub fn is_struct<'tcx>(adt_owner: HAResult, ty: Ty<'tcx>) -> Result<bool, &'static str> {
117        match ty.kind() {
118            TyKind::Adt(adtdef, ..) => {
119                if !adtdef.is_struct() && !adtdef.is_union() {
120                    return Err("The input is not a struct");
121                }
122                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
123                if ans[0].0 == RawTypeOwner::Owned {
124                    return Ok(true);
125                }
126                Ok(false)
127            }
128            _ => Err("The input is not an ADT"),
129        }
130    }
131
132    /// This method is used to check if one adt-def of the enum is already a heap item.
133    /// It is a summary of one type which demonstrate that we will consider all the variants,
134    /// although the analyzer will not traverse them (thus overhead is cheap).
135    /// Note that, even for each variance, the result also analyze all its fields.
136    /// It can be referred to the enum with enum-type variance.
137    ///
138    /// # Safety
139    /// If `ty` is not an adt, the result is `Err`.
140    /// If the input is the def of a struct type, the result is `Err`.
141    ///
142    /// # Case `ty::Ty`
143    /// Given the adt `MyBuf<T>` the result is `Ok(true)`.
144    /// ```rust
145    /// pub enum MyBuf<T> {
146    ///    Buf1(Vec<T>), // this variance is a heap item
147    ///    Buf2(Vec<T>), // this variance is a heap item
148    /// }
149    /// ```
150    ///
151    /// # Example:
152    /// ```rust
153    /// use rap::analysis::core::heap_item::HeapItem;
154    /// let ans = HeapItem::is_enum(rcanary.rcx, vec.ty);
155    /// ```
156    pub fn is_enum<'tcx>(adt_owner: HAResult, ty: Ty<'tcx>) -> Result<bool, &'static str> {
157        match ty.kind() {
158            TyKind::Adt(adtdef, ..) => {
159                if !adtdef.is_enum() {
160                    return Err("The input is not an enum");
161                }
162                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
163                for i in ans.iter() {
164                    if i.0 == RawTypeOwner::Owned {
165                        return Ok(true);
166                    }
167                }
168                Ok(false)
169            }
170            _ => Err("The input is not an ADT"),
171        }
172    }
173
174    /// This method is used to check if one variance of the enum is already a heap item.
175    /// It is a summary of one variance which demonstrate that we will consider all the fields of it,
176    /// although the analyzer will not traverse them (thus overhead is cheap).
177    /// It can be referred to the enum with enum-type variance.
178    ///
179    /// # Safety
180    /// If `ty` is not an adt, the result is `Err`.
181    /// If the input is the def of a struct type, the result is `Err`.
182    /// If the index `idx` is not valid (out of bound), the result is `Err`.
183    ///
184    /// # Case `ty::Ty`
185    /// Given the adt `MyBuf<T>` the result for idx: 0, 1 is `Ok(true)`; the result for idx: 3 is `Err`.
186    /// ```rust
187    /// pub enum MyBuf<T> {
188    ///    Buf1(Vec<T>), // this variance is a heap item
189    ///    Buf2(Vec<T>), // this variance is a heap item
190    /// }
191    /// ```
192    ///
193    /// # Example:
194    /// ```rust
195    /// use rap::analysis::core::heap_item::HeapItem;
196    /// let ans = HeapItem::is_enum_vidx(rcanary.rcx, vec.ty, 1);
197    /// ```
198    pub fn is_enum_vidx<'tcx>(
199        adt_owner: HAResult,
200        ty: Ty<'tcx>,
201        idx: usize,
202    ) -> Result<bool, &'static str> {
203        match ty.kind() {
204            TyKind::Adt(adtdef, ..) => {
205                if !adtdef.is_enum() {
206                    return Err("The input is not an enum");
207                }
208                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
209                if idx > ans.len() {
210                    return Err("The index is not a valid variance");
211                }
212                if ans[idx].0 == RawTypeOwner::Owned {
213                    return Ok(true);
214                }
215                Ok(false)
216            }
217            _ => Err("The input is not an ADT"),
218        }
219    }
220
221    /// This method is used to give the result of all the variances of the enum.
222    /// For each variance, it is a summary that we will consider all the fields of it,
223    /// although the analyzer will not traverse them (thus overhead is cheap).
224    /// It can be referred to the enum with enum-type variance.
225    ///
226    /// # Safety
227    /// If `ty` is not an adt, the result is `Err`.
228    /// If the input is the def of a struct type, the result is `Err`.
229    ///
230    /// # Case `ty::Ty`
231    /// Given the adt `MyBuf<T>` the result is `[true, false]`.
232    /// ```rust
233    /// pub enum MyBuf<T> {
234    ///    Buf1(Vec<T>), // this variance is a heap item
235    ///    Buf2(()), // this variance is a heap item
236    /// }
237    /// ```
238    ///
239    /// # Example:
240    /// ```rust
241    /// use rap::analysis::core::heap_item::HeapItem;
242    /// let ans = HeapItem::is_enum_flattened(rcanary.rcx, vec.ty);
243    /// ```
244    pub fn is_enum_flattened<'tcx>(
245        adt_owner: HAResult,
246        ty: Ty<'tcx>,
247    ) -> Result<Vec<bool>, &'static str> {
248        match ty.kind() {
249            TyKind::Adt(adtdef, ..) => {
250                if !adtdef.is_enum() {
251                    return Err("The input is not an enum");
252                }
253                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
254                let mut v = Vec::with_capacity(ans.len());
255                for i in ans.iter() {
256                    if i.0 == RawTypeOwner::Owned {
257                        v.push(true);
258                    } else {
259                        v.push(false);
260                    }
261                }
262                Ok(v)
263            }
264            _ => Err("The input is not an ADT"),
265        }
266    }
267}
268
269pub struct IsolatedParameter;
270
271impl IsolatedParameter {
272    /// This method is used to check if one adt-def has at least one isolated parameter.
273    /// It is a summary of one type which demonstrate that we will consider all the generics.
274    /// Those generic parameters can be located in different fields/variants, and some of them can be
275    /// found in multiple fields/variants.
276    /// The analyzer will not traverse them to generate the result (thus overhead is cheap).
277    ///
278    /// # Safety
279    /// If `ty` is not an adt, the result is `Err`.
280    ///
281    /// # Case `ty::Ty`
282    /// Given the adt `MyVec<T, A>` the result is `Ok(true)`.
283    /// ```rust
284    /// pub struct MyVec<T, A: Allocator = Global> { // parameter A is an isolated parameter
285    ///    buf: RawVec<T, A>,  // parameter A inside in RawVec
286    ///    len: usize,
287    /// }
288    /// ```
289    ///
290    /// # Example:
291    /// ```rust
292    ///  use rap::analysis::core::heap_item::IsolatedParameter;
293    ///  let ans = IsolatedParameter::is_adt(rcanary.rcx, vec.ty);
294    /// ```
295    pub fn is_adt<'tcx>(adt_owner: HAResult, ty: Ty<'tcx>) -> Result<bool, &'static str> {
296        match ty.kind() {
297            TyKind::Adt(adtdef, ..) => {
298                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
299                for i in ans.iter() {
300                    if i.1.iter().any(|&x| x == true) {
301                        return Ok(true);
302                    }
303                }
304                Ok(false)
305            }
306            _ => Err("The input is not an ADT"),
307        }
308    }
309
310    /// This method is used to check if one adt-def of the struct has at least one isolated parameter.
311    /// It is a summary of one type which demonstrate that we will consider all the generics.
312    /// Those generic parameters can be located in different fields, and some of them can be
313    /// found in multiple fields.
314    /// The analyzer will not traverse them to generate the result (thus overhead is cheap).
315    ///
316    /// # Safety
317    /// If `ty` is not an adt, the result is `Err`.
318    ///
319    /// # Case `ty::Ty`
320    /// Given the adt `MyVec<T, A>` the result is `Ok(true)`.
321    /// ```rust
322    /// pub struct MyVec<T, A: Allocator = Global> { // parameter A is an isolated parameter
323    ///    buf: RawVec<T, A>, // parameter A inside in RawVec
324    ///    len: usize,
325    /// }
326    /// ```
327    ///
328    /// # Example:
329    /// ```rust
330    ///  use rap::analysis::core::heap_item::IsolatedParameter;
331    ///  let ans = IsolatedParameter::is_adt(rcanary.rcx, vec.ty);
332    /// ```
333    pub fn is_struct<'tcx>(adt_owner: HAResult, ty: Ty<'tcx>) -> Result<bool, &'static str> {
334        match ty.kind() {
335            TyKind::Adt(adtdef, ..) => {
336                if !adtdef.is_struct() && !adtdef.is_union() {
337                    return Err("The input is not a struct");
338                }
339                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
340                if ans[0].1.iter().any(|&x| x == true) {
341                    return Ok(true);
342                }
343                Ok(false)
344            }
345            _ => Err("The input is not an ADT"),
346        }
347    }
348
349    /// This method is used to check if one adt-def of the enum has at least one isolated parameter.
350    /// It is a summary of one type which demonstrate that we will consider all the generics in all the variants.
351    /// Those generic parameters can be located in different fields, and some of them can be
352    /// found in multiple fields.
353    /// Note that, even for each variance, the result also analyze all its fields.
354    /// It can be referred to the enum with enum-type variance.
355    ///
356    /// # Safety
357    /// If `ty` is not an adt, the result is `Err`.
358    /// If the input is the def of a struct type, the result is `Err`.
359    ///
360    /// # Case `ty::Ty`
361    /// Given the adt `MyBuf<T, S, F>` the result is `Ok(true)`.
362    /// ```rust
363    /// pub enum MyBuf<T, S, F> { // parameter S F are an isolated parameters
364    ///    Buf1(Vec<T>),
365    ///    Buf2(S), // this variance is an isolated parameter
366    ///    Buf3((F,S)), // this variance has 2 isolated parameters
367    /// }
368    /// ```
369    ///
370    /// # Example:
371    /// ```rust
372    ///  use rap::analysis::core::heap_item::IsolatedParameter;
373    ///  let ans = IsolatedParameter::is_adt(rcanary.rcx, vec.ty);
374    /// ```
375    pub fn is_enum<'tcx>(adt_owner: HAResult, ty: Ty<'tcx>) -> Result<bool, &'static str> {
376        match ty.kind() {
377            TyKind::Adt(adtdef, ..) => {
378                if !adtdef.is_enum() {
379                    return Err("The input is not an enum");
380                }
381                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
382                for i in ans.iter() {
383                    if i.1.iter().any(|&x| x == true) {
384                        return Ok(true);
385                    }
386                }
387                Ok(false)
388            }
389            _ => Err("The input is not an ADT"),
390        }
391    }
392
393    /// This method is used to check if one variance of the enum has at least one isolated parameter.
394    /// It is a summary of one type which demonstrate that we will consider all the generics in the given variance.
395    /// Note that, even for this variance, the result also analyze all its fields.
396    /// It can be referred to the enum with enum-type variance.
397    ///
398    /// # Safety
399    /// If `ty` is not an adt, the result is `Err`.
400    /// If the input is the def of a struct type, the result is `Err`.
401    /// If the index `idx` is not valid (out of bound), the result is `Err`.
402    ///
403    /// # Case `ty::Ty`
404    /// Given the adt `MyBuf<T, S, F>` the result for idx: 0 is `Ok(false)`; the result for idx: 1, 2 is `Ok(true)`; the result for idx: 3 is `Err`.
405    /// ```rust
406    /// pub enum MyBuf<T, S, F> { // parameter S F are an isolated parameters
407    ///    Buf1(Vec<T>),
408    ///    Buf2(S), // this variance is an isolated parameter
409    ///    Buf3((F,S)), // this variance has 2 isolated parameters
410    /// }
411    /// ```
412    ///
413    /// # Example:
414    /// ```rust
415    ///  use rap::analysis::core::heap_item::IsolatedParameter;
416    ///  let ans = IsolatedParameter::is_enum_vidx(rcanary.rcx, vec.ty, 1);
417    /// ```
418    pub fn is_enum_vidx<'tcx>(
419        adt_owner: HAResult,
420        ty: Ty<'tcx>,
421        idx: usize,
422    ) -> Result<bool, &'static str> {
423        match ty.kind() {
424            TyKind::Adt(adtdef, ..) => {
425                if !adtdef.is_enum() {
426                    return Err("The input is not an enum");
427                }
428                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
429                if idx > ans.len() {
430                    return Err("The index is not a valid variance");
431                }
432                if ans[idx].1.iter().any(|&x| x == true) {
433                    return Ok(true);
434                }
435                Ok(false)
436            }
437            _ => Err("The input is not an ADT"),
438        }
439    }
440
441    /// This method is used to check if one adt-def of the enum has at least one isolated parameter.
442    /// It is a summary of one type which demonstrate that we will consider all the generics in all the variants.
443    /// Those generic parameters can be located in different fields, and some of them can be
444    /// found in multiple fields.
445    /// Note that, even for each variance, the result also analyze all its fields.
446    /// It can be referred to the enum with enum-type variance.
447    ///
448    /// # Safety
449    /// If `ty` is not an adt, the result is `Err`.
450    /// If the input is the def of a struct type, the result is `Err`.
451    ///
452    /// # Case `ty::Ty`
453    /// Given the adt `Vec<T, A>` the result is `Ok(true)`.
454    /// ```rust
455    /// pub enum MyBuf<T, S, F> { // parameter S F are an isolated parameters
456    ///    Buf1(Vec<T>),
457    ///    Buf2(S), // this variance is an isolated parameter
458    ///    Buf3((F,S)), // this variance has 2 isolated parameters
459    /// }
460    /// ```
461    ///
462    /// # Example:
463    /// ```rust
464    ///  use rap::analysis::core::heap_item::IsolatedParameter;
465    ///  let ans = IsolatedParameter::is_enum_flattened(rcanary.rcx, vec.ty);
466    /// ```
467    pub fn is_enum_flattened<'tcx>(
468        adt_owner: HAResult,
469        ty: Ty<'tcx>,
470    ) -> Result<Vec<Vec<bool>>, &'static str> {
471        match ty.kind() {
472            TyKind::Adt(adtdef, ..) => {
473                if !adtdef.is_enum() {
474                    return Err("The input is not an enum");
475                }
476                let ans = adt_owner.get(&adtdef.0 .0.did).unwrap();
477                let mut v: Vec<Vec<bool>> = Vec::default();
478                for i in ans.iter() {
479                    v.push(i.1.clone());
480                }
481                Ok(v)
482            }
483            _ => Err("The input is not an ADT"),
484        }
485    }
486}
487
488#[derive(Clone)]
489struct IsolatedParam {
490    record: Vec<bool>,
491}
492
493impl IsolatedParam {
494    pub fn new(len: usize) -> Self {
495        Self {
496            record: vec![false; len],
497        }
498    }
499
500    pub fn record_mut(&mut self) -> &mut Vec<bool> {
501        &mut self.record
502    }
503}
504
505#[derive(Clone)]
506struct IsolatedParamFieldSubst {
507    parameters: HashSet<usize>,
508}
509
510impl<'tcx> IsolatedParamFieldSubst {
511    pub fn new() -> Self {
512        Self {
513            parameters: HashSet::new(),
514        }
515    }
516
517    pub fn parameters(&self) -> &HashSet<usize> {
518        &self.parameters
519    }
520
521    pub fn parameters_mut(&mut self) -> &mut HashSet<usize> {
522        &mut self.parameters
523    }
524
525    pub fn contains_param(&self) -> bool {
526        !self.parameters.is_empty()
527    }
528}
529
530#[derive(Clone)]
531struct IsolatedParamPropagation<'tcx, 'a> {
532    tcx: TyCtxt<'tcx>,
533    record: Vec<bool>,
534    unique: HashSet<DefId>,
535    source_enum: bool,
536    ref_adt_owner: &'a HAResult,
537}
538
539impl<'tcx, 'a> IsolatedParamPropagation<'tcx, 'a> {
540    pub fn new(
541        tcx: TyCtxt<'tcx>,
542        record: Vec<bool>,
543        source_enum: bool,
544        ref_adt_owner: &'a HAResult,
545    ) -> Self {
546        Self {
547            tcx,
548            record,
549            unique: HashSet::new(),
550            source_enum,
551            ref_adt_owner,
552        }
553    }
554
555    pub fn record_mut(&mut self) -> &mut Vec<bool> {
556        &mut self.record
557    }
558
559    pub fn unique_mut(&mut self) -> &mut HashSet<DefId> {
560        &mut self.unique
561    }
562
563    pub fn source_enum(&mut self) -> bool {
564        self.source_enum
565    }
566
567    pub fn owner(&self) -> &'a HAResult {
568        self.ref_adt_owner
569    }
570}
571
572#[derive(Clone)]
573struct OwnerPropagation<'tcx, 'a> {
574    tcx: TyCtxt<'tcx>,
575    ownership: RawTypeOwner,
576    unique: HashSet<DefId>,
577    ref_adt_owner: &'a HAResult,
578}
579
580impl<'tcx, 'a> OwnerPropagation<'tcx, 'a> {
581    pub fn new(tcx: TyCtxt<'tcx>, ownership: RawTypeOwner, ref_adt_owner: &'a HAResult) -> Self {
582        Self {
583            tcx,
584            ownership,
585            unique: HashSet::new(),
586            ref_adt_owner,
587        }
588    }
589
590    pub fn ownership(&self) -> RawTypeOwner {
591        self.ownership
592    }
593
594    pub fn unique_mut(&mut self) -> &mut HashSet<DefId> {
595        &mut self.unique
596    }
597
598    pub fn owner(&self) -> &'a HAResult {
599        self.ref_adt_owner
600    }
601}
602
603#[derive(Clone)]
604pub struct DefaultOwnership<'tcx, 'a> {
605    tcx: TyCtxt<'tcx>,
606    unique: HashSet<DefId>,
607    ref_adt_owner: &'a HAResult,
608    res: RawTypeOwner,
609    param: bool,
610    ptr: bool,
611}
612
613impl<'tcx, 'a> DefaultOwnership<'tcx, 'a> {
614    pub fn new(tcx: TyCtxt<'tcx>, ref_adt_owner: &'a HAResult) -> Self {
615        Self {
616            tcx,
617            unique: HashSet::new(),
618            ref_adt_owner,
619            res: RawTypeOwner::Unowned,
620            param: false,
621            ptr: false,
622        }
623    }
624
625    pub fn tcx(&self) -> TyCtxt<'tcx> {
626        self.tcx
627    }
628
629    pub fn unique(&self) -> &HashSet<DefId> {
630        &self.unique
631    }
632
633    pub fn unique_mut(&mut self) -> &mut HashSet<DefId> {
634        &mut self.unique
635    }
636
637    pub fn get_res(&self) -> RawTypeOwner {
638        self.res
639    }
640
641    pub fn set_res(&mut self, res: RawTypeOwner) {
642        self.res = res;
643    }
644
645    pub fn is_owning_true(&self) -> bool {
646        self.res == RawTypeOwner::Owned
647    }
648
649    pub fn get_param(&self) -> bool {
650        self.param
651    }
652
653    pub fn set_param(&mut self, p: bool) {
654        self.param = p;
655    }
656
657    pub fn is_param_true(&self) -> bool {
658        self.param == true
659    }
660
661    pub fn get_ptr(&self) -> bool {
662        self.ptr
663    }
664
665    pub fn set_ptr(&mut self, p: bool) {
666        self.ptr = p;
667    }
668
669    pub fn is_ptr_true(&self) -> bool {
670        self.ptr == true
671    }
672
673    pub fn owner(&self) -> &'a HAResult {
674        self.ref_adt_owner
675    }
676}
677
678#[derive(Clone)]
679pub struct FindPtr<'tcx> {
680    tcx: TyCtxt<'tcx>,
681    unique: HashSet<DefId>,
682    ptr: bool,
683}
684
685impl<'tcx> FindPtr<'tcx> {
686    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
687        Self {
688            tcx,
689            unique: HashSet::<DefId>::default(),
690            ptr: false,
691        }
692    }
693
694    pub fn tcx(&self) -> TyCtxt<'tcx> {
695        self.tcx
696    }
697
698    pub fn unique(&self) -> &HashSet<DefId> {
699        &self.unique
700    }
701
702    pub fn unique_mut(&mut self) -> &mut HashSet<DefId> {
703        &mut self.unique
704    }
705
706    pub fn has_ptr(&self) -> bool {
707        self.ptr
708    }
709
710    pub fn set_ptr(&mut self, ptr: bool) {
711        self.ptr = ptr;
712    }
713}
714
715pub fn is_display_verbose() -> bool {
716    match env::var_os("ADT_DISPLAY") {
717        Some(_) => true,
718        _ => false,
719    }
720}
721
722#[derive(Debug, Clone, Hash, Eq, PartialEq, Default)]
723pub struct IndexedTy<'tcx>(pub Option<(usize, &'tcx TyKind<'tcx>, Option<usize>, bool)>);
724
725impl<'tcx> IndexedTy<'tcx> {
726    pub fn new(ty: Ty<'tcx>, vidx: Option<VariantIdx>) -> Self {
727        match &ty.kind() {
728            TyKind::Tuple(list) => IndexedTy(Some((list.len(), &ty.kind(), None, true))),
729            TyKind::Adt(adtdef, ..) => {
730                if adtdef.is_enum() {
731                    if vidx.is_none() {
732                        return IndexedTy(None);
733                    }
734                    let idx = vidx.unwrap();
735                    let len = adtdef.variants()[idx].fields.len();
736                    IndexedTy(Some((len, &ty.kind(), Some(idx.index()), true)))
737                } else {
738                    let len = adtdef.variants()[VariantIdx::from_usize(0)].fields.len();
739                    IndexedTy(Some((len, &ty.kind(), None, true)))
740                }
741            }
742            TyKind::Array(..) | TyKind::Param(..) | TyKind::RawPtr(..) | TyKind::Ref(..) => {
743                IndexedTy(Some((1, &ty.kind(), None, true)))
744            }
745            TyKind::Bool
746            | TyKind::Char
747            | TyKind::Int(..)
748            | TyKind::Uint(..)
749            | TyKind::Float(..)
750            | TyKind::Str
751            | TyKind::Slice(..) => IndexedTy(Some((1, &ty.kind(), None, false))),
752            _ => IndexedTy(None),
753        }
754    }
755
756    // 0->unsupported, 1->trivial, 2-> needed
757    pub fn get_priority(&self) -> usize {
758        if self.0.is_none() {
759            return 0;
760        }
761        match self.0.unwrap().0 {
762            0 => 1,
763            _ => match self.0.unwrap().3 {
764                true => 2,
765                false => 1,
766            },
767        }
768    }
769}
770
771
772
773#[derive(Clone, Debug)]
774pub struct OwnershipLayoutResult {
775    layout: Vec<RawTypeOwner>,
776    param: bool,
777    requirement: bool,
778    owned: bool,
779}
780
781impl OwnershipLayoutResult {
782    pub fn new() -> Self {
783        Self {
784            layout: Vec::new(),
785            param: false,
786            requirement: false,
787            owned: false,
788        }
789    }
790
791    pub fn layout(&self) -> &Vec<RawTypeOwner> {
792        &self.layout
793    }
794
795    pub fn layout_mut(&mut self) -> &mut Vec<RawTypeOwner> {
796        &mut self.layout
797    }
798
799    pub fn get_param(&self) -> bool {
800        self.param
801    }
802
803    pub fn set_param(&mut self, p: bool) {
804        self.param = p;
805    }
806
807    pub fn is_param_true(&self) -> bool {
808        self.param == true
809    }
810
811    pub fn get_requirement(&self) -> bool {
812        self.requirement
813    }
814
815    pub fn set_requirement(&mut self, r: bool) {
816        self.requirement = r;
817    }
818
819    pub fn is_requirement_true(&self) -> bool {
820        self.requirement == true
821    }
822
823    pub fn is_empty(&self) -> bool {
824        self.layout.is_empty()
825    }
826
827    pub fn is_owned(&self) -> bool {
828        self.owned == true
829    }
830
831    pub fn set_owned(&mut self, o: bool) {
832        self.owned = o;
833    }
834
835    pub fn update_from_default_ownership_visitor<'tcx, 'a>(
836        &mut self,
837        default_ownership: &mut DefaultOwnership<'tcx, 'a>,
838    ) {
839        if default_ownership.is_owning_true() || default_ownership.is_ptr_true() {
840            self.set_requirement(true);
841        }
842
843        if default_ownership.is_owning_true() {
844            self.set_owned(true);
845        }
846
847        self.layout_mut().push(default_ownership.get_res());
848
849        self.set_param(default_ownership.get_param());
850    }
851}