mun_hir/code_model/
module.rs

1use super::{Function, Package, Struct, TypeAlias};
2use crate::ids::{ItemDefinitionId, ModuleId};
3use crate::primitive_type::PrimitiveType;
4use crate::{DiagnosticSink, FileId, HirDatabase, Name};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
7pub struct Module {
8    pub(crate) id: ModuleId,
9}
10
11impl From<ModuleId> for Module {
12    fn from(id: ModuleId) -> Self {
13        Module { id }
14    }
15}
16
17impl Module {
18    /// Returns the module that corresponds to the given file
19    pub fn from_file(db: &dyn HirDatabase, file: FileId) -> Option<Module> {
20        Package::all(db)
21            .iter()
22            .flat_map(|package| package.modules(db))
23            .find(|m| m.file_id(db) == Some(file))
24    }
25
26    /// Returns the parent module of this module.
27    pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
28        let module_tree = db.module_tree(self.id.package);
29        let parent_id = module_tree[self.id.local_id].parent?;
30        Some(Module {
31            id: ModuleId {
32                package: self.id.package,
33                local_id: parent_id,
34            },
35        })
36    }
37
38    /// Returns the name of this module or None if this is the root module
39    pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
40        let module_tree = db.module_tree(self.id.package);
41        let parent = module_tree[self.id.local_id].parent?;
42        module_tree[parent]
43            .children
44            .iter()
45            .find_map(|(name, module_id)| {
46                if *module_id == self.id.local_id {
47                    Some(name.clone())
48                } else {
49                    None
50                }
51            })
52    }
53
54    /// Returns the file that defines the module
55    pub fn file_id(self, db: &dyn HirDatabase) -> Option<FileId> {
56        db.module_tree(self.id.package).modules[self.id.local_id].file
57    }
58
59    /// Returns all items declared in this module.
60    pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
61        let package_defs = db.package_defs(self.id.package);
62        package_defs.modules[self.id.local_id]
63            .declarations()
64            .map(ModuleDef::from)
65            .collect()
66    }
67
68    /// Iterate over all diagnostics from this `Module` by placing them in the `sink`
69    pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
70        // Add diagnostics from the package definitions
71        let package_defs = db.package_defs(self.id.package);
72        package_defs.add_diagnostics(db.upcast(), self.id.local_id, sink);
73
74        // Add diagnostics from the item tree
75        if let Some(file_id) = self.file_id(db) {
76            let item_tree = db.item_tree(file_id);
77            for diagnostics in item_tree.diagnostics.iter() {
78                diagnostics.add_to(db, &item_tree, sink);
79            }
80        }
81
82        // Add diagnostics from the items
83        for decl in self.declarations(db) {
84            match decl {
85                ModuleDef::Function(f) => f.diagnostics(db, sink),
86                ModuleDef::Struct(s) => s.diagnostics(db, sink),
87                ModuleDef::TypeAlias(t) => t.diagnostics(db, sink),
88                _ => (),
89            }
90        }
91    }
92
93    /// Returns all the child modules of this module
94    pub fn children(self, db: &dyn HirDatabase) -> Vec<Module> {
95        let module_tree = db.module_tree(self.id.package);
96        module_tree[self.id.local_id]
97            .children
98            .iter()
99            .map(|(_, local_id)| Module {
100                id: ModuleId {
101                    package: self.id.package,
102                    local_id: *local_id,
103                },
104            })
105            .collect()
106    }
107
108    /// Returns the path from this module to the root module
109    pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
110        let mut res = vec![self];
111        let mut curr = self;
112        while let Some(next) = curr.parent(db) {
113            res.push(next);
114            curr = next
115        }
116        res
117    }
118
119    /// Returns the name of this module including all parent modules
120    pub fn full_name(self, db: &dyn HirDatabase) -> String {
121        itertools::Itertools::intersperse(
122            self.path_to_root(db)
123                .iter()
124                .filter_map(|&module| module.name(db))
125                .map(|name| name.to_string()),
126            String::from("::"),
127        )
128        .collect()
129    }
130}
131
132#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
133pub enum ModuleDef {
134    Module(Module),
135    Function(Function),
136    PrimitiveType(PrimitiveType),
137    Struct(Struct),
138    TypeAlias(TypeAlias),
139}
140
141impl From<Function> for ModuleDef {
142    fn from(t: Function) -> Self {
143        ModuleDef::Function(t)
144    }
145}
146
147impl From<PrimitiveType> for ModuleDef {
148    fn from(t: PrimitiveType) -> Self {
149        ModuleDef::PrimitiveType(t)
150    }
151}
152
153impl From<Struct> for ModuleDef {
154    fn from(t: Struct) -> Self {
155        ModuleDef::Struct(t)
156    }
157}
158
159impl From<TypeAlias> for ModuleDef {
160    fn from(t: TypeAlias) -> Self {
161        ModuleDef::TypeAlias(t)
162    }
163}
164
165impl From<Module> for ModuleDef {
166    fn from(m: Module) -> Self {
167        ModuleDef::Module(m)
168    }
169}
170
171impl From<ItemDefinitionId> for ModuleDef {
172    fn from(id: ItemDefinitionId) -> Self {
173        match id {
174            ItemDefinitionId::ModuleId(id) => Module { id }.into(),
175            ItemDefinitionId::FunctionId(id) => Function { id }.into(),
176            ItemDefinitionId::StructId(id) => Struct { id }.into(),
177            ItemDefinitionId::TypeAliasId(id) => TypeAlias { id }.into(),
178            ItemDefinitionId::PrimitiveType(id) => id.into(),
179        }
180    }
181}