Skip to main content

rapx/analysis/heap_ownership/
mod.rs

1pub mod default;
2
3use rustc_middle::ty::{Ty, TyKind};
4use rustc_span::def_id::DefId;
5
6use std::{
7    collections::{HashMap, HashSet},
8    env,
9    fmt::{self, Display},
10};
11
12use crate::{Analysis, utils::source::get_fn_name_byid};
13
14#[repr(u8)]
15#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
16pub enum HeapOwnership {
17    False = 0,
18    True = 1,
19    Unknown = 2,
20}
21
22impl Default for HeapOwnership {
23    fn default() -> Self {
24        Self::Unknown
25    }
26}
27
28impl HeapOwnership {
29    pub fn is_onheap(&self) -> bool {
30        matches!(self, HeapOwnership::True)
31    }
32}
33
34impl Display for HeapOwnership {
35    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
36        let name = match self {
37            HeapOwnership::False => "0",
38            HeapOwnership::True => "1",
39            HeapOwnership::Unknown => "2",
40        };
41        write!(f, "{}", name)
42    }
43}
44
45/// This is the type for storing the heap analysis results.
46/// The result is represented as a hashmap, where the key is `DefId` and the value contains the
47/// information of whether the type contains data on heap.
48/// Since a type could be a enumerate type, the value is represented as a vec, indicating the heap
49/// information of each variant.
50/// Also, because it may contain type parameters or generic types,
51/// the heap information is a tuple containing the information of each type parameter.
52pub type HeapOwnershipResultMap = HashMap<DefId, Vec<(HeapOwnership, Vec<bool>)>>;
53pub struct HeapOwnershipResultMapWrapper(pub HashMap<DefId, Vec<(HeapOwnership, Vec<bool>)>>);
54
55impl Display for HeapOwnershipResultMapWrapper {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        writeln!(f, "=== Print heap ownership analysis results ===")?;
58        for (def_id, units) in &self.0 {
59            let fn_name = get_fn_name_byid(def_id);
60            let owning = units
61                .iter()
62                .map(Self::format_heap_unit)
63                .collect::<Vec<_>>()
64                .join(", ");
65            writeln!(f, "Type: {:?}: {}", fn_name, owning)?;
66        }
67        Ok(())
68    }
69}
70
71impl HeapOwnershipResultMapWrapper {
72    fn format_heap_unit((heap, bits): &(HeapOwnership, Vec<bool>)) -> String {
73        let bit_str = bits
74            .iter()
75            .map(|b| if *b { "1" } else { "0" })
76            .collect::<Vec<_>>()
77            .join(",");
78        format!("{:?}, <{}>", heap, bit_str)
79    }
80}
81/// This trait provides features for owned heap analysis, which is used to determine if a type owns
82/// memory on heap. Owned heap should be automatically released by default.
83pub trait HeapOwnershipAnalysis: Analysis {
84    /// The function returns the result of owned heap analysis for all types.
85    fn get_all_items(&self) -> HeapOwnershipResultMap;
86
87    /// If a type is a heap owner, the function returns Result<true>. If the specified type is
88    /// illegal, the function returns Err.
89    fn is_heapowner<'tcx>(
90        hares: HeapOwnershipResultMap,
91        ty: Ty<'tcx>,
92    ) -> Result<bool, &'static str> {
93        match ty.kind() {
94            TyKind::Adt(adtdef, ..) => {
95                let heapinfo = hares.get(&adtdef.0.0.did).unwrap();
96                for item in heapinfo {
97                    if item.0 == HeapOwnership::True {
98                        return Ok(true);
99                    }
100                }
101                Ok(false)
102            }
103            _ => Err("The input is not an ADT"),
104        }
105    }
106
107    /// A type might be a heap owner if it is not a heap owner directly but contains type
108    /// parameters that may make the type become a heap owner after monomorphization.
109    fn maybe_heapowner<'tcx>(
110        hares: HeapOwnershipResultMap,
111        ty: Ty<'tcx>,
112    ) -> Result<bool, &'static str> {
113        match ty.kind() {
114            TyKind::Adt(adtdef, ..) => {
115                let heapinfo = hares.get(&adtdef.0.0.did).unwrap();
116                for item in heapinfo {
117                    if item.0 == HeapOwnership::False && item.1.contains(&true) {
118                        return Ok(true);
119                    }
120                }
121                Ok(false)
122            }
123            _ => Err("The input is not an ADT"),
124        }
125    }
126}