use hir::db::HirDatabase;
use ra_ap_hir::{self as hir};
use ra_ap_ide::Edition;
use crate::{item::Item, tree::Tree};
type Node = Item;
#[derive(Debug)]
pub struct TreeBuilder<'a> {
db: &'a dyn HirDatabase,
krate: hir::Crate,
}
impl<'a> TreeBuilder<'a> {
pub fn new(db: &'a dyn HirDatabase, krate: hir::Crate) -> Self {
Self { db, krate }
}
pub fn build(mut self) -> anyhow::Result<Tree<Node>> {
let _span = tracing::trace_span!("target").entered();
let tree = self
.process_crate(self.krate)
.expect("Expected tree node for crate root module");
Ok(tree)
}
fn process_crate(&mut self, crate_hir: hir::Crate) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"crate",
crate = crate_hir
.display_name(self.db)
.map(|name| name.to_string())
.unwrap_or_else(|| "<ANONYMOUS>".to_owned())
)
.entered();
let module = crate_hir.root_module(self.db);
self.process_module(module)
}
fn process_impl(&mut self, impl_hir: hir::Impl) -> Vec<Tree<Node>> {
let _span = tracing::trace_span!("impl").entered();
impl_hir
.items(self.db)
.into_iter()
.filter_map(|item| match item {
hir::AssocItem::Function(function_hir) => self.process_function(function_hir),
hir::AssocItem::Const(const_hir) => self.process_const(const_hir),
hir::AssocItem::TypeAlias(type_alias_hir) => {
self.process_type_alias(type_alias_hir)
}
})
.collect()
}
fn process_moduledef(&mut self, module_def_hir: hir::ModuleDef) -> Option<Tree<Node>> {
match module_def_hir {
hir::ModuleDef::Module(module_hir) => self.process_module(module_hir),
hir::ModuleDef::Function(function_hir) => self.process_function(function_hir),
hir::ModuleDef::Adt(adt_hir) => self.process_adt(adt_hir),
hir::ModuleDef::EnumVariant(variant_hir) => self.process_variant(variant_hir),
hir::ModuleDef::Const(const_hir) => self.process_const(const_hir),
hir::ModuleDef::Static(static_hir) => self.process_static(static_hir),
hir::ModuleDef::Trait(trait_hir) => self.process_trait(trait_hir),
hir::ModuleDef::TypeAlias(type_alias_hir) => self.process_type_alias(type_alias_hir),
hir::ModuleDef::BuiltinType(builtin_type_hir) => {
self.process_builtin_type(builtin_type_hir)
}
hir::ModuleDef::Macro(macro_hir) => self.process_macro(macro_hir),
}
}
fn process_module(&mut self, module_hir: hir::Module) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"module",
module = module_hir
.name(self.db)
.map(|name| name.display(self.db, Edition::CURRENT).to_string())
.unwrap_or_else(|| "<ROOT>".to_owned())
)
.entered();
let item = Item::new(hir::ModuleDef::Module(module_hir));
let mut node = Tree::new(item, vec![]);
let subtrees = module_hir
.declarations(self.db)
.into_iter()
.filter_map(|module_def_hir| self.process_moduledef(module_def_hir));
for subtree in subtrees {
node.push_subtree(subtree);
}
Some(node)
}
fn process_function(&mut self, function_hir: hir::Function) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"function",
function = function_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string()
)
.entered();
self.simple_node(hir::ModuleDef::Function(function_hir))
}
fn process_adt(&mut self, adt_hir: hir::Adt) -> Option<Tree<Node>> {
let mut node = match adt_hir {
hir::Adt::Struct(struct_hir) => self.process_struct(struct_hir),
hir::Adt::Union(union_hir) => self.process_union(union_hir),
hir::Adt::Enum(enum_hir) => self.process_enum(enum_hir),
};
if let Some(node) = node.as_mut() {
for impl_hir in hir::Impl::all_for_type(self.db, adt_hir.ty(self.db)) {
for subtree in self.process_impl(impl_hir) {
node.push_subtree(subtree);
}
}
}
node
}
fn process_struct(&mut self, struct_hir: hir::Struct) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"struct",
struct = struct_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string()
)
.entered();
self.simple_node(hir::ModuleDef::Adt(hir::Adt::Struct(struct_hir)))
}
fn process_enum(&mut self, enum_hir: hir::Enum) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"enum",
enum = enum_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string()
)
.entered();
self.simple_node(hir::ModuleDef::Adt(hir::Adt::Enum(enum_hir)))
}
fn process_union(&mut self, union_hir: hir::Union) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"union",
union = union_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string()
)
.entered();
self.simple_node(hir::ModuleDef::Adt(hir::Adt::Union(union_hir)))
}
fn process_variant(&mut self, variant_hir: hir::EnumVariant) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"variant",
variant = variant_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string()
)
.entered();
None
}
fn process_const(&mut self, const_hir: hir::Const) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"const",
const = const_hir
.name(self.db)
.map(|name| name.display(self.db, Edition::CURRENT).to_string())
.unwrap_or_else(|| "_".to_owned())
)
.entered();
None
}
fn process_static(&mut self, static_hir: hir::Static) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"static",
static = static_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string()
)
.entered();
self.simple_node(hir::ModuleDef::Static(static_hir))
}
fn process_trait(&mut self, trait_hir: hir::Trait) -> Option<Tree<Node>> {
let _span = tracing::trace_span!("trait",
trait = trait_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string())
.entered();
self.simple_node(hir::ModuleDef::Trait(trait_hir))
}
fn process_type_alias(&mut self, type_alias_hir: hir::TypeAlias) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"type alias",
type_alias = type_alias_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string()
)
.entered();
self.simple_node(hir::ModuleDef::TypeAlias(type_alias_hir))
}
fn process_builtin_type(&mut self, builtin_type_hir: hir::BuiltinType) -> Option<Tree<Node>> {
let _span = tracing::trace_span!(
"builtin type",
builtin_type = builtin_type_hir
.name()
.display(self.db, Edition::CURRENT)
.to_string()
)
.entered();
self.simple_node(hir::ModuleDef::BuiltinType(builtin_type_hir))
}
fn process_macro(&mut self, macro_hir: hir::Macro) -> Option<Tree<Node>> {
let _span = tracing::trace_span!("macro",
macro = macro_hir
.name(self.db)
.display(self.db, Edition::CURRENT)
.to_string())
.entered();
let _ = macro_hir;
None
}
fn simple_node(&mut self, module_def_hir: hir::ModuleDef) -> Option<Tree<Node>> {
let item = Item::new(module_def_hir);
Some(Tree::new(item, vec![]))
}
}