libperl_macrogen/
inline_fn.rs1use std::collections::{HashMap, HashSet};
7
8use crate::apidoc_patches::ApidocPatchSet;
9use crate::ast::FunctionDef;
10use crate::intern::{InternedStr, StringInterner};
11use crate::macro_infer::{convert_assert_calls_in_compound_stmt, MacroInferContext};
12
13#[derive(Debug, Default)]
18pub struct InlineFnDict {
19 fns: HashMap<InternedStr, FunctionDef>,
20 called_functions: HashMap<InternedStr, HashSet<InternedStr>>,
22 calls_unavailable: HashSet<InternedStr>,
24 apidoc_suppressed: HashSet<InternedStr>,
29}
30
31impl InlineFnDict {
32 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn insert(&mut self, name: InternedStr, func_def: FunctionDef) {
39 self.fns.insert(name, func_def);
40 }
41
42 pub fn get(&self, name: InternedStr) -> Option<&FunctionDef> {
44 self.fns.get(&name)
45 }
46
47 pub fn iter(&self) -> impl Iterator<Item = (&InternedStr, &FunctionDef)> {
49 self.fns.iter()
50 }
51
52 pub fn len(&self) -> usize {
54 self.fns.len()
55 }
56
57 pub fn is_empty(&self) -> bool {
59 self.fns.is_empty()
60 }
61
62 pub fn get_called_functions(&self, name: InternedStr) -> Option<&HashSet<InternedStr>> {
64 self.called_functions.get(&name)
65 }
66
67 pub fn is_calls_unavailable(&self, name: InternedStr) -> bool {
69 self.calls_unavailable.contains(&name)
70 }
71
72 pub fn set_calls_unavailable(&mut self, name: InternedStr) {
74 self.calls_unavailable.insert(name);
75 }
76
77 pub fn is_apidoc_suppressed(&self, name: InternedStr) -> bool {
79 self.apidoc_suppressed.contains(&name)
80 }
81
82 pub fn set_apidoc_suppressed(&mut self, name: InternedStr) {
84 self.apidoc_suppressed.insert(name);
85 }
86
87 pub fn is_unavailable_for_codegen(&self, name: InternedStr) -> bool {
93 self.is_calls_unavailable(name) || self.is_apidoc_suppressed(name)
94 }
95
96 pub fn apply_apidoc_suppressions(
103 &mut self,
104 patches: &ApidocPatchSet,
105 interner: &StringInterner,
106 ) -> usize {
107 let mut count = 0usize;
108 for name_str in patches.skip_codegen.keys() {
109 if let Some(interned) = interner.lookup(name_str) {
110 if self.fns.contains_key(&interned) {
111 self.apidoc_suppressed.insert(interned);
112 count += 1;
113 }
114 }
115 }
116 count
117 }
118
119 pub fn called_functions_iter(&self) -> impl Iterator<Item = (&InternedStr, &HashSet<InternedStr>)> {
121 self.called_functions.iter()
122 }
123
124 pub fn collect_from_function_def(&mut self, func_def: &FunctionDef, interner: &StringInterner) {
136 let is_static = func_def.specs.storage == Some(crate::ast::StorageClass::Static);
137 if !func_def.specs.is_inline && !is_static {
138 return;
139 }
140
141 let name = match func_def.declarator.name {
142 Some(n) => n,
143 None => return,
144 };
145
146 let mut func_def = func_def.clone();
148 convert_assert_calls_in_compound_stmt(&mut func_def.body, interner);
149
150 let mut calls = HashSet::new();
152 MacroInferContext::collect_function_calls_from_block_items(
153 &func_def.body.items,
154 &mut calls,
155 );
156 self.called_functions.insert(name, calls);
157
158 self.insert(name, func_def);
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn test_inline_fn_dict_new() {
168 let dict = InlineFnDict::new();
169 assert!(dict.is_empty());
170 assert_eq!(dict.len(), 0);
171 }
172}