1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) 2024 <Wei Li>.
//
// This source code is licensed under the GNU license found in the
// LICENSE file in the root directory of this source tree.

use rustc_hir::def_id::DefId;
use rustc_middle::mir::Promoted;
use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_middle::ty::{Const, Ty};

use crate::mir::context::ContextId;
use std::rc::Rc;

rustc_index::newtype_index! {
    /// The unique identifier for each function reference.
    /// Every unique instantiation of a generic function will have a different func_id.
    #[orderable]
    #[debug_format = "FuncId({})"]
    pub struct FuncId {}
}

/// Context-sensitive function consisting of a context id (cid) and a function id (func_id). 
#[derive(Copy, Clone, Debug, Eq, PartialOrd, PartialEq, Hash, Ord)]
pub struct CSFuncId {
    pub cid: ContextId,
    pub func_id: FuncId,
}

impl CSFuncId {
    pub fn new(cid: ContextId, func_id: FuncId) -> Self {
        Self { cid, func_id }
    }
}

impl From<CSFuncId> for FuncId {
    fn from(f: CSFuncId) -> Self {
        f.func_id
    }
}

/// Information that identifies a function instance.
#[derive(Clone, Debug, Eq, PartialOrd, PartialEq, Hash, Ord)]
pub struct FunctionReference<'tcx> {
    /// The crate specific key that is used to identify the function in the current crate.
    pub def_id: DefId,

    /// The generic argument types with which the referenced function was instantiated, if generic.
    pub generic_args: Vec<GenericArgE<'tcx>>,

    /// Promoteds do not have their own DefId. The body references promoteds by the DefId
    /// and the mir::Promoted index.
    pub promoted: Option<Promoted>,
}

/// Resembles the `GenericArgKind` type in rustc.
#[derive(Clone, Debug, Eq, PartialOrd, PartialEq, Hash, Ord)]
pub enum GenericArgE<'tcx> {
    Region,
    Const(Const<'tcx>),
    Type(Ty<'tcx>),
}

impl<'tcx> From<&GenericArg<'tcx>> for GenericArgE<'tcx> {
    fn from(ga: &GenericArg<'tcx>) -> GenericArgE<'tcx> {
        match ga.unpack() {
            GenericArgKind::Lifetime(_) => GenericArgE::Region,
            // the only supported Const types are integers, `bool` and `char`
            GenericArgKind::Const(c) => GenericArgE::Const(c),
            GenericArgKind::Type(ty) => GenericArgE::Type(ty),
        }
    }
}

impl<'tcx> FunctionReference<'tcx> {
    pub fn new_function_reference(
        def_id: DefId,
        generic_args: Vec<GenericArgE<'tcx>>,
    ) -> Rc<FunctionReference<'tcx>> {
        Rc::new(FunctionReference {
            def_id,
            generic_args,
            promoted: None,
        })
    }

    pub fn new_promoted_reference(
        def_id: DefId,
        generic_args: Vec<GenericArgE<'tcx>>,
        promoted: Promoted,
    ) -> Rc<FunctionReference<'tcx>> {
        Rc::new(FunctionReference {
            def_id,
            generic_args,
            promoted: Some(promoted),
        })
    }
}

impl<'tcx> ToString for FunctionReference<'tcx> {
    fn to_string(&self) -> String {
        let const_to_str = |c: &Const| -> String {
            if let Some(v) = c.try_to_scalar() {
                return v.to_string();
            }
            return "_".to_string();
        };

        let tmp1 = format!("{:?}", self.def_id);
        let crate_name = &tmp1[tmp1.find("~ ").unwrap() + 2..tmp1.find("[").unwrap()];
        let tmp2 = &tmp1[tmp1.find("::").unwrap() + 2..tmp1.len() - 1];
        let mut tmp3 = "".to_string();
        if !self.generic_args.is_empty() {
            tmp3.push('<');
            let tys = self
                .generic_args
                .iter()
                .filter_map(|t| match t {
                    GenericArgE::Type(ty) => Some(format!("{:?}", ty)),
                    GenericArgE::Const(c) => Some(const_to_str(c)),
                    _ => None,
                })
                .collect::<Vec<String>>();
            tmp3.push_str(&tys.join(", "));
            tmp3.push('>');
        }
        if let Some(promoted) = self.promoted {
            format!("{}::{}::promoted[{}]", crate_name, tmp2, promoted.index())
        } else {
            format!("{}::{}{}", crate_name, tmp2, tmp3)
        }
    }
}