arch_test_core/parser/materials/
module_tree.rs1use 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#[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}