arch_test_core/parser/materials/
module_tree.rs

1use std::collections::HashMap;
2use std::path::Path;
3
4use crate::parser::domain_values::{ObjectType, ObjectUse, UsableObject};
5use crate::parser::entities::ModuleNode;
6use crate::parser::services::parse_main_or_mod_file_into_tree;
7
8/// This object is used to parse the ModuleTree and its use relationships from a directory
9///
10/// Example:
11/// ```ignore
12/// let module_tree = ModuleTree::new("src/lib.rs");
13/// ```
14#[derive(Debug)]
15pub struct ModuleTree {
16    tree: Vec<ModuleNode>,
17    possible_uses: HashMap<String, ObjectUse>,
18}
19
20impl ModuleTree {
21    pub fn new(root_directory: &str) -> Self {
22        let path = Path::new(root_directory);
23        assert!(path.exists(), "Expecting a valid path");
24        assert!(path.is_file(), "Expecting path to be a file!");
25        let file_name = path.file_name().and_then(|os_str| os_str.to_str()).unwrap();
26        let module_name = if file_name == "main.rs" || file_name == "lib.rs" {
27            "crate".to_owned()
28        } else {
29            path.file_name()
30                .and_then(|os_str| os_str.to_str())
31                .unwrap()
32                .trim_end_matches(".rs")
33                .to_owned()
34        };
35
36        let mut module_tree = ModuleTree {
37            tree: vec![],
38            possible_uses: HashMap::default(),
39        };
40        parse_main_or_mod_file_into_tree(&mut module_tree.tree, path, 0, None, module_name);
41        module_tree.correct_fully_qualified_names();
42        module_tree.replace_path_wildcard();
43        module_tree.correct_fully_qualified_names();
44        module_tree.correct_republish_paths();
45        module_tree.filter_primary_types();
46        module_tree.filter_unused_uses();
47        module_tree.filter_covered_implicit_uses();
48        module_tree.construct_possible_use_map();
49        module_tree
50    }
51
52    fn correct_fully_qualified_names(&mut self) {
53        let fully_qualified_names: Vec<String> = self
54            .tree
55            .iter()
56            .map(|node| node.get_fully_qualified_path(&self.tree))
57            .collect();
58        let module_names: Vec<String> = self
59            .tree
60            .iter()
61            .map(|node| node.module_name().clone())
62            .collect();
63        for (index, node) in self.tree.iter_mut().enumerate() {
64            let node_children_module_names: Vec<String> = node
65                .children()
66                .iter()
67                .map(|child_index| module_names[*child_index].clone())
68                .collect();
69            for uses in node.usable_objects.iter_mut().filter(|obj| {
70                obj.object_type() == ObjectType::Use || obj.object_type() == ObjectType::RePublish
71            }) {
72                if uses.object_name.starts_with("self::") {
73                    uses.object_name = uses
74                        .object_name
75                        .replace("self::", &format!("{}::", fully_qualified_names[index]));
76                } else if !uses.object_name.starts_with("crate::") {
77                    let has_mod_prefix = node_children_module_names
78                        .iter()
79                        .any(|module_name| uses.object_name.starts_with(module_name));
80                    if has_mod_prefix {
81                        uses.object_name =
82                            format!("{}::{}", fully_qualified_names[index], uses.object_name);
83                    }
84                }
85            }
86
87            let use_paths: Vec<String> = node
88                .usable_objects
89                .iter()
90                .filter(|obj| {
91                    obj.object_type() == ObjectType::Use
92                        || obj.object_type() == ObjectType::RePublish
93                })
94                .map(|obj| obj.object_name.clone())
95                .collect();
96            for uses in node
97                .usable_objects
98                .iter_mut()
99                .filter(|obj| obj.object_type() == ObjectType::ImplicitUse)
100            {
101                let splits: Vec<&str> = uses.object_name.split("::").collect();
102                if let Some(prefix) = use_paths.iter().find(|prefix| prefix.ends_with(&splits[0])) {
103                    if splits.len() > 1 {
104                        uses.object_name = format!("{}::{}", prefix, splits[1..].join("::"));
105                    } else {
106                        uses.object_name = prefix.clone();
107                    }
108                } else if let Some(prefix) = use_paths
109                    .iter()
110                    .find(|prefix| prefix.ends_with(&uses.object_name))
111                {
112                    uses.object_name = prefix.clone();
113                } else if splits.len() > 1
114                    && node_children_module_names
115                        .iter()
116                        .any(|name| name == splits[0])
117                {
118                    uses.object_name =
119                        format!("{}::{}", fully_qualified_names[index], uses.object_name);
120                }
121            }
122        }
123    }
124
125    fn correct_republish_paths(&mut self) {
126        let mut republish_map = HashMap::new();
127        let fully_qualified_names: Vec<String> = self
128            .tree
129            .iter()
130            .map(|node| node.get_fully_qualified_path(&self.tree))
131            .collect();
132
133        for (index, node) in self.tree.iter().enumerate() {
134            let prefix = fully_qualified_names[index].clone();
135            for path_obj in node
136                .usable_objects
137                .iter()
138                .filter(|obj| obj.object_type() == ObjectType::RePublish)
139            {
140                let split_vec = path_obj.object_name.split("::").collect::<Vec<&str>>();
141                republish_map.insert(
142                    format!("{}::{}", prefix, split_vec.last().unwrap()),
143                    path_obj.object_name.clone(),
144                );
145            }
146        }
147
148        for node in self.tree.iter_mut() {
149            for uses in node.usable_objects.iter_mut().filter(|obj| {
150                obj.object_type() == ObjectType::Use
151                    || obj.object_type() == ObjectType::ImplicitUse
152                    || obj.object_type() == ObjectType::RePublish
153            }) {
154                uses.object_name = republish_map
155                    .get(&uses.object_name)
156                    .cloned()
157                    .unwrap_or_else(|| uses.object_name.clone());
158            }
159        }
160    }
161
162    fn construct_possible_use_map(&mut self) {
163        let fully_qualified_names: Vec<String> = self
164            .tree
165            .iter()
166            .map(|node| node.get_fully_qualified_path(&self.tree))
167            .collect();
168        for (index, node) in self.tree.iter().enumerate() {
169            let prefix = fully_qualified_names[index].clone();
170            for path_obj in node.usable_objects.iter().filter(|obj| {
171                obj.object_type() != ObjectType::RePublish
172                    && obj.object_type() != ObjectType::Use
173                    && obj.object_type() != ObjectType::ImplicitUse
174            }) {
175                let full_path = format!("{}::{}", prefix, path_obj.object_name);
176                self.possible_uses.insert(
177                    full_path.clone(),
178                    ObjectUse::new(index, full_path, path_obj.clone()),
179                );
180            }
181        }
182    }
183
184    fn filter_primary_types(&mut self) {
185        let primary_types = vec![
186            "i8", "i16", "i32", "i64", "i128", "u8", "u16", "u32", "u64", "u128", "isize", "usize",
187            "str", "char", "f32", "f64", "bool", "Self", "self", "_",
188        ];
189        let object_primary_types = vec![
190            "std::collections::HashMap",
191            "std::collections::HashSet",
192            "std::collections::VecDeque",
193            "Vec",
194            "vec",
195            "String",
196            "std::collections::LinkedList",
197            "std::collections::BTreeMap",
198            "std::collections::BTreeSet",
199            "std::collections::BinaryHeap",
200        ];
201
202        for node in self.tree.iter_mut() {
203            for i in (0..node.usable_objects.len()).rev() {
204                if primary_types.contains(&node.usable_objects[i].object_name.as_str()) {
205                    node.usable_objects.remove(i);
206                } else {
207                    let splits: Vec<&str> =
208                        node.usable_objects[i].object_name.split("::").collect();
209                    if object_primary_types.contains(&node.usable_objects[i].object_name.as_str())
210                        || object_primary_types
211                            .contains(&splits[..(splits.len() - 1)].join("::").as_str())
212                    {
213                        node.usable_objects.remove(i);
214                    }
215                }
216            }
217        }
218    }
219
220    fn replace_path_wildcard(&mut self) {
221        loop {
222            let mut wild_card_path: Option<(usize, usize, UsableObject)> = None;
223            for node in self.tree.iter_mut() {
224                for i in (0..node.usable_objects.len()).rev() {
225                    if node.usable_objects[i].object_name.ends_with('*') {
226                        wild_card_path = Some((node.index(), i, node.usable_objects[i].clone()));
227                        break;
228                    }
229                }
230                if wild_card_path.is_some() {
231                    break;
232                }
233            }
234
235            if let Some((node_index, usable_object_index, use_obj)) = wild_card_path {
236                let path = use_obj.object_name.trim_end_matches("::*").to_string();
237                if let Some(matching_node) = self
238                    .tree
239                    .iter()
240                    .find(|node| node.get_fully_qualified_path(&self.tree) == path)
241                    .cloned()
242                {
243                    for obj in matching_node
244                        .usable_objects
245                        .iter()
246                        .filter(|obj| obj.is_public() && obj.object_name.split("::").count() == 1)
247                    {
248                        match obj.object_type() {
249                            ObjectType::Struct
250                            | ObjectType::Trait
251                            | ObjectType::Enum
252                            | ObjectType::Function => {
253                                self.tree[node_index].usable_objects.push(UsableObject::new(
254                                    use_obj.is_public(),
255                                    use_obj.object_type(),
256                                    format!("{}::{}", path, obj.object_name),
257                                    *use_obj.text_range(),
258                                ));
259                            }
260                            _ => continue,
261                        };
262                    }
263                    self.tree[node_index]
264                        .usable_objects
265                        .remove(usable_object_index);
266                } else {
267                    self.tree[node_index].usable_objects[usable_object_index].object_name =
268                        self.tree[node_index].usable_objects[usable_object_index]
269                            .object_name
270                            .trim_end_matches("::*")
271                            .to_string();
272                }
273            } else {
274                break;
275            }
276        }
277    }
278
279    fn filter_covered_implicit_uses(&mut self) {
280        for node in self.tree.iter_mut() {
281            for i in (0..node.usable_objects.len()).rev() {
282                if node.usable_objects[i].object_name.starts_with("crate::") {
283                    continue;
284                }
285
286                if node.usable_objects.iter().any(|obj| {
287                    obj.object_name != node.usable_objects[i].object_name
288                        && obj
289                            .object_name
290                            .ends_with(&node.usable_objects[i].object_name)
291                }) {
292                    node.usable_objects.remove(i);
293                }
294            }
295        }
296    }
297
298    fn filter_unused_uses(&mut self) {
299        for node in self.tree.iter_mut() {
300            for i in (0..node.usable_objects.len()).rev() {
301                if node.usable_objects[i].object_type() != ObjectType::Use
302                    && node.usable_objects[i].object_type() != ObjectType::RePublish
303                {
304                    continue;
305                }
306                if !node.usable_objects.iter().any(|obj| {
307                    obj.object_type() == ObjectType::ImplicitUse
308                        && obj
309                            .object_name
310                            .starts_with(&node.usable_objects[i].object_name)
311                }) {
312                    node.usable_objects.remove(i);
313                }
314            }
315        }
316    }
317
318    pub fn tree(&self) -> &Vec<ModuleNode> {
319        &self.tree
320    }
321
322    pub fn possible_uses(&self) -> &HashMap<String, ObjectUse> {
323        &self.possible_uses
324    }
325}