//! When *constructing* `hir`, we start at some parent syntax node and recursively //! lower the children. //! //! This modules allows one to go in the opposite direction: start with a syntax //! node for a *child*, and get its hir. use either::Either; use hir_expand::InFile; use ra_syntax::{ast, AstNode, AstPtr}; use crate::{ db::DefDatabase, src::{HasChildSource, HasSource}, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, ImplId, Lookup, ModuleDefId, ModuleId, StaticId, StructFieldId, TraitId, TypeAliasId, VariantId, }; pub trait ChildFromSource { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option; } impl ChildFromSource for TraitId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let data = db.trait_data(*self); data.items .iter() .filter_map(|(_, item)| match item { AssocItemId::FunctionId(it) => Some(*it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }) } } impl ChildFromSource for ImplId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let data = db.impl_data(*self); data.items .iter() .filter_map(|item| match item { AssocItemId::FunctionId(it) => Some(*it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }) } } impl ChildFromSource for ModuleId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let crate_def_map = db.crate_def_map(self.krate); let res = crate_def_map[self.local_id] .scope .declarations() .filter_map(|item| match item { ModuleDefId::FunctionId(it) => Some(it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }); res } } impl ChildFromSource for TraitId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let data = db.trait_data(*self); data.items .iter() .filter_map(|(_, item)| match item { AssocItemId::ConstId(it) => Some(*it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }) } } impl ChildFromSource for ImplId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let data = db.impl_data(*self); data.items .iter() .filter_map(|item| match item { AssocItemId::ConstId(it) => Some(*it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }) } } impl ChildFromSource for ModuleId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let crate_def_map = db.crate_def_map(self.krate); let res = crate_def_map[self.local_id] .scope .declarations() .filter_map(|item| match item { ModuleDefId::ConstId(it) => Some(it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }); res } } impl ChildFromSource for TraitId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let data = db.trait_data(*self); data.items .iter() .filter_map(|(_, item)| match item { AssocItemId::TypeAliasId(it) => Some(*it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }) } } impl ChildFromSource for ImplId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let data = db.impl_data(*self); data.items .iter() .filter_map(|item| match item { AssocItemId::TypeAliasId(it) => Some(*it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }) } } impl ChildFromSource for ModuleId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let crate_def_map = db.crate_def_map(self.krate); let res = crate_def_map[self.local_id] .scope .declarations() .filter_map(|item| match item { ModuleDefId::TypeAliasId(it) => Some(it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }); res } } impl ChildFromSource for ModuleId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let crate_def_map = db.crate_def_map(self.krate); let res = crate_def_map[self.local_id] .scope .declarations() .filter_map(|item| match item { ModuleDefId::StaticId(it) => Some(it), _ => None, }) .find(|func| { let source = func.lookup(db).source(db); same_source(&source, &child_source) }); res } } impl ChildFromSource> for VariantId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile>, ) -> Option { let arena_map = self.child_source(db); let (local_id, _) = arena_map.as_ref().value.iter().find(|(_local_id, source)| { child_source.file_id == arena_map.file_id && match (source, &child_source.value) { (Either::Left(a), Either::Left(b)) => AstPtr::new(a) == AstPtr::new(b), (Either::Right(a), Either::Right(b)) => AstPtr::new(a) == AstPtr::new(b), _ => false, } })?; Some(StructFieldId { parent: *self, local_id }) } } impl ChildFromSource for EnumId { fn child_from_source( &self, db: &impl DefDatabase, child_source: InFile, ) -> Option { let arena_map = self.child_source(db); let (local_id, _) = arena_map.as_ref().value.iter().find(|(_local_id, source)| { child_source.file_id == arena_map.file_id && AstPtr::new(*source) == AstPtr::new(&child_source.value) })?; Some(EnumVariantId { parent: *self, local_id }) } } /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are /// equal if they point to exactly the same object. /// /// In general, we do not guarantee that we have exactly one instance of a /// syntax tree for each file. We probably should add such guarantee, but, for /// the time being, we will use identity-less AstPtr comparison. fn same_source(s1: &InFile, s2: &InFile) -> bool { s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new) }