frs/cmds/rsl/rules/common/
module_idx.rs1use std::collections::HashMap;
2use std::collections::HashSet;
3use std::collections::VecDeque;
4
5use syn::Item;
6
7use super::import_resolution::ImportBinding;
8
9pub struct ModuleScope<'ast> {
10 pub path: Vec<String>,
11 pub items: &'ast [Item],
12}
13
14#[derive(Default)]
15pub struct ScopeInfo {
16 pub definitions: HashSet<String>,
17 pub fns: HashSet<String>,
18 pub glob_imports: Vec<Vec<String>>,
19 pub imports: Vec<ImportBinding>,
20 pub unknown_imports: bool,
21}
22
23pub struct ModuleIdx<'ast> {
24 pub scopes: Vec<ModuleScope<'ast>>,
25 pub info: HashMap<Vec<String>, ScopeInfo>,
26 pub modules: HashSet<Vec<String>>,
27}
28
29pub fn module_idx(file: &syn::File) -> ModuleIdx<'_> {
30 let mut idx = ModuleIdx {
31 scopes: Vec::new(),
32 info: HashMap::new(),
33 modules: HashSet::new(),
34 };
35 let mut pending = VecDeque::from([(Vec::new(), file.items.as_slice())]);
36
37 while let Some((path, items)) = pending.pop_front() {
38 let mut info = ScopeInfo::default();
39 for item in items {
40 if let Some(name) = self::item_name(item) {
41 info.definitions.insert(name);
42 }
43 if let Item::Fn(fn_item) = item {
44 info.fns.insert(fn_item.sig.ident.to_string());
45 }
46 if let Item::Mod(module) = item {
47 let mut nested_path = path.clone();
48 nested_path.push(module.ident.to_string());
49 idx.modules.insert(nested_path.clone());
50 if let Some((_, nested_items)) = &module.content {
51 pending.push_back((nested_path, nested_items.as_slice()));
52 }
53 }
54 if let Item::Use(item_use) = item {
55 let bindings = super::import_resolution::use_bindings(&item_use.tree, &path);
56 info.imports.extend(bindings.bindings);
57 info.glob_imports.extend(bindings.glob_imports);
58 info.unknown_imports |= bindings.unknown;
59 }
60 }
61 idx.info.insert(path.clone(), info);
62 idx.scopes.push(ModuleScope { path, items });
63 }
64
65 idx
66}
67
68fn item_name(item: &Item) -> Option<String> {
69 match item {
70 Item::Const(item) => Some(item.ident.to_string()),
71 Item::Enum(item) => Some(item.ident.to_string()),
72 Item::ExternCrate(item) => Some(item.ident.to_string()),
73 Item::Fn(item) => Some(item.sig.ident.to_string()),
74 Item::Mod(item) => Some(item.ident.to_string()),
75 Item::Static(item) => Some(item.ident.to_string()),
76 Item::Struct(item) => Some(item.ident.to_string()),
77 Item::Trait(item) => Some(item.ident.to_string()),
78 Item::TraitAlias(item) => Some(item.ident.to_string()),
79 Item::Type(item) => Some(item.ident.to_string()),
80 Item::Union(item) => Some(item.ident.to_string()),
81 Item::ForeignMod(_) | Item::Impl(_) | Item::Macro(_) | Item::Use(_) | Item::Verbatim(_) | _ => None,
82 }
83}
84
85pub fn is_local_module_path(idx: &ModuleIdx<'_>, path: &[String]) -> bool {
86 path.is_empty() || idx.modules.contains(path)
87}