use super::{Function, Package, Struct, TypeAlias};
use crate::ids::{ItemDefinitionId, ModuleId};
use crate::primitive_type::PrimitiveType;
use crate::{DiagnosticSink, FileId, HirDatabase, Name};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct Module {
pub(crate) id: ModuleId,
}
impl From<ModuleId> for Module {
fn from(id: ModuleId) -> Self {
Module { id }
}
}
impl Module {
pub fn from_file(db: &dyn HirDatabase, file: FileId) -> Option<Module> {
Package::all(db)
.iter()
.flat_map(|package| package.modules(db))
.find(|m| m.file_id(db) == Some(file))
}
pub fn parent(self, db: &dyn HirDatabase) -> Option<Module> {
let module_tree = db.module_tree(self.id.package);
let parent_id = module_tree[self.id.local_id].parent?;
Some(Module {
id: ModuleId {
package: self.id.package,
local_id: parent_id,
},
})
}
pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
let module_tree = db.module_tree(self.id.package);
let parent = module_tree[self.id.local_id].parent?;
module_tree[parent]
.children
.iter()
.find_map(|(name, module_id)| {
if *module_id == self.id.local_id {
Some(name.clone())
} else {
None
}
})
}
pub fn file_id(self, db: &dyn HirDatabase) -> Option<FileId> {
db.module_tree(self.id.package).modules[self.id.local_id].file
}
pub fn declarations(self, db: &dyn HirDatabase) -> Vec<ModuleDef> {
let package_defs = db.package_defs(self.id.package);
package_defs.modules[self.id.local_id]
.declarations()
.map(ModuleDef::from)
.collect()
}
pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
let package_defs = db.package_defs(self.id.package);
package_defs.add_diagnostics(db.upcast(), self.id.local_id, sink);
if let Some(file_id) = self.file_id(db) {
let item_tree = db.item_tree(file_id);
for diagnostics in item_tree.diagnostics.iter() {
diagnostics.add_to(db, &item_tree, sink);
}
}
for decl in self.declarations(db) {
match decl {
ModuleDef::Function(f) => f.diagnostics(db, sink),
ModuleDef::Struct(s) => s.diagnostics(db, sink),
ModuleDef::TypeAlias(t) => t.diagnostics(db, sink),
_ => (),
}
}
}
pub fn children(self, db: &dyn HirDatabase) -> Vec<Module> {
let module_tree = db.module_tree(self.id.package);
module_tree[self.id.local_id]
.children
.iter()
.map(|(_, local_id)| Module {
id: ModuleId {
package: self.id.package,
local_id: *local_id,
},
})
.collect()
}
pub fn path_to_root(self, db: &dyn HirDatabase) -> Vec<Module> {
let mut res = vec![self];
let mut curr = self;
while let Some(next) = curr.parent(db) {
res.push(next);
curr = next
}
res
}
pub fn full_name(self, db: &dyn HirDatabase) -> String {
itertools::Itertools::intersperse(
self.path_to_root(db)
.iter()
.filter_map(|&module| module.name(db))
.map(|name| name.to_string()),
String::from("::"),
)
.collect()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ModuleDef {
Module(Module),
Function(Function),
PrimitiveType(PrimitiveType),
Struct(Struct),
TypeAlias(TypeAlias),
}
impl From<Function> for ModuleDef {
fn from(t: Function) -> Self {
ModuleDef::Function(t)
}
}
impl From<PrimitiveType> for ModuleDef {
fn from(t: PrimitiveType) -> Self {
ModuleDef::PrimitiveType(t)
}
}
impl From<Struct> for ModuleDef {
fn from(t: Struct) -> Self {
ModuleDef::Struct(t)
}
}
impl From<TypeAlias> for ModuleDef {
fn from(t: TypeAlias) -> Self {
ModuleDef::TypeAlias(t)
}
}
impl From<Module> for ModuleDef {
fn from(m: Module) -> Self {
ModuleDef::Module(m)
}
}
impl From<ItemDefinitionId> for ModuleDef {
fn from(id: ItemDefinitionId) -> Self {
match id {
ItemDefinitionId::ModuleId(id) => Module { id }.into(),
ItemDefinitionId::FunctionId(id) => Function { id }.into(),
ItemDefinitionId::StructId(id) => Struct { id }.into(),
ItemDefinitionId::TypeAliasId(id) => TypeAlias { id }.into(),
ItemDefinitionId::PrimitiveType(id) => id.into(),
}
}
}