From c3a4c4429de83450654795534e64e878a774a088 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 18 Feb 2020 18:35:10 +0100 Subject: Refactor primary IDE API This introduces the new type -- Semantics. Semantics maps SyntaxNodes to various semantic info, such as type, name resolution or macro expansions. To do so, Semantics maintains a HashMap which maps every node it saw to the file from which the node originated. This is enough to get all the necessary hir bits just from syntax. --- crates/ra_hir/src/source_binder.rs | 161 ++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 92 deletions(-) (limited to 'crates/ra_hir/src/source_binder.rs') diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index f3150f578..0b8a641f9 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -5,112 +5,85 @@ use hir_def::{ child_by_source::ChildBySource, dyn_map::DynMap, keys::{self, Key}, - resolver::{HasResolver, Resolver}, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId, StaticId, StructFieldId, StructId, TraitId, TypeAliasId, UnionId, VariantId, }; use hir_expand::{name::AsName, AstId, InFile, MacroDefId, MacroDefKind}; +use ra_db::FileId; use ra_prof::profile; use ra_syntax::{ ast::{self, NameOwner}, - match_ast, AstNode, SyntaxNode, TextUnit, + match_ast, AstNode, SyntaxNode, }; use rustc_hash::FxHashMap; -use crate::{db::HirDatabase, Local, Module, SourceAnalyzer, TypeParam}; -use ra_db::FileId; +use crate::{db::HirDatabase, Local, Module, TypeParam}; -pub struct SourceBinder<'a, DB> { - pub db: &'a DB, +pub struct SourceBinder { child_by_source_cache: FxHashMap, } -impl SourceBinder<'_, DB> { - pub fn new(db: &DB) -> SourceBinder { - SourceBinder { db, child_by_source_cache: FxHashMap::default() } - } - - pub fn analyze( - &mut self, - src: InFile<&SyntaxNode>, - offset: Option, - ) -> SourceAnalyzer { - let _p = profile("SourceBinder::analyzer"); - let container = match self.find_container(src) { - Some(it) => it, - None => return SourceAnalyzer::new_for_resolver(Resolver::default(), src), - }; - - let resolver = match container { - ChildContainer::DefWithBodyId(def) => { - return SourceAnalyzer::new_for_body(self.db, def, src, offset) - } - ChildContainer::TraitId(it) => it.resolver(self.db), - ChildContainer::ImplId(it) => it.resolver(self.db), - ChildContainer::ModuleId(it) => it.resolver(self.db), - ChildContainer::EnumId(it) => it.resolver(self.db), - ChildContainer::VariantId(it) => it.resolver(self.db), - ChildContainer::GenericDefId(it) => it.resolver(self.db), - }; - SourceAnalyzer::new_for_resolver(resolver, src) +impl SourceBinder { + pub(crate) fn new() -> SourceBinder { + SourceBinder { child_by_source_cache: FxHashMap::default() } } - pub fn to_def(&mut self, src: InFile) -> Option { - T::to_def(self, src) - } - - pub fn to_module_def(&mut self, file: FileId) -> Option { + pub(crate) fn to_module_def(&mut self, db: &impl HirDatabase, file: FileId) -> Option { let _p = profile("SourceBinder::to_module_def"); - let (krate, local_id) = self.db.relevant_crates(file).iter().find_map(|&crate_id| { - let crate_def_map = self.db.crate_def_map(crate_id); + let (krate, local_id) = db.relevant_crates(file).iter().find_map(|&crate_id| { + let crate_def_map = db.crate_def_map(crate_id); let local_id = crate_def_map.modules_for_file(file).next()?; Some((crate_id, local_id)) })?; Some(Module { id: ModuleId { krate, local_id } }) } - fn to_id(&mut self, src: InFile) -> Option { - T::to_id(self, src) + fn to_id(&mut self, db: &impl HirDatabase, src: InFile) -> Option { + T::to_id(db, self, src) } - fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option { - for container in src.cloned().ancestors_with_macros(self.db).skip(1) { + pub(crate) fn find_container( + &mut self, + db: &impl HirDatabase, + src: InFile<&SyntaxNode>, + ) -> Option { + for container in src.cloned().ancestors_with_macros(db).skip(1) { let res: ChildContainer = match_ast! { match (container.value) { ast::TraitDef(it) => { - let def: TraitId = self.to_id(container.with_value(it))?; + let def: TraitId = self.to_id(db, container.with_value(it))?; def.into() }, ast::ImplBlock(it) => { - let def: ImplId = self.to_id(container.with_value(it))?; + let def: ImplId = self.to_id(db, container.with_value(it))?; def.into() }, ast::FnDef(it) => { - let def: FunctionId = self.to_id(container.with_value(it))?; + let def: FunctionId = self.to_id(db, container.with_value(it))?; DefWithBodyId::from(def).into() }, ast::StaticDef(it) => { - let def: StaticId = self.to_id(container.with_value(it))?; + let def: StaticId = self.to_id(db, container.with_value(it))?; DefWithBodyId::from(def).into() }, ast::ConstDef(it) => { - let def: ConstId = self.to_id(container.with_value(it))?; + let def: ConstId = self.to_id(db, container.with_value(it))?; DefWithBodyId::from(def).into() }, ast::EnumDef(it) => { - let def: EnumId = self.to_id(container.with_value(it))?; + let def: EnumId = self.to_id(db, container.with_value(it))?; def.into() }, ast::StructDef(it) => { - let def: StructId = self.to_id(container.with_value(it))?; + let def: StructId = self.to_id(db, container.with_value(it))?; VariantId::from(def).into() }, ast::UnionDef(it) => { - let def: UnionId = self.to_id(container.with_value(it))?; + let def: UnionId = self.to_id(db, container.with_value(it))?; VariantId::from(def).into() }, ast::Module(it) => { - let def: ModuleId = self.to_id(container.with_value(it))?; + let def: ModuleId = self.to_id(db, container.with_value(it))?; def.into() }, _ => { continue }, @@ -119,12 +92,11 @@ impl SourceBinder<'_, DB> { return Some(res); } - let c = self.to_module_def(src.file_id.original_file(self.db))?; + let c = self.to_module_def(db, src.file_id.original_file(db))?; Some(c.id.into()) } - fn child_by_source(&mut self, container: ChildContainer) -> &DynMap { - let db = self.db; + fn child_by_source(&mut self, db: &impl HirDatabase, container: ChildContainer) -> &DynMap { self.child_by_source_cache.entry(container).or_insert_with(|| match container { ChildContainer::DefWithBodyId(it) => it.child_by_source(db), ChildContainer::ModuleId(it) => it.child_by_source(db), @@ -137,16 +109,20 @@ impl SourceBinder<'_, DB> { } } -pub trait ToId: Sized { +pub(crate) trait ToId: Sized { type ID: Sized + Copy + 'static; - fn to_id(sb: &mut SourceBinder<'_, DB>, src: InFile) - -> Option; + fn to_id( + db: &DB, + sb: &mut SourceBinder, + src: InFile, + ) -> Option; } pub trait ToDef: Sized + AstNode + 'static { type Def; fn to_def( - sb: &mut SourceBinder<'_, DB>, + db: &DB, + sb: &mut SourceBinder, src: InFile, ) -> Option; } @@ -155,9 +131,9 @@ macro_rules! to_def_impls { ($(($def:path, $ast:path)),* ,) => {$( impl ToDef for $ast { type Def = $def; - fn to_def(sb: &mut SourceBinder<'_, DB>, src: InFile) + fn to_def(db: &DB, sb: &mut SourceBinder, src: InFile) -> Option - { sb.to_id(src).map(Into::into) } + { sb.to_id(db, src).map(Into::into) } } )*} } @@ -179,7 +155,7 @@ to_def_impls![ ]; #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -enum ChildContainer { +pub(crate) enum ChildContainer { DefWithBodyId(DefWithBodyId), ModuleId(ModuleId), TraitId(TraitId), @@ -201,7 +177,7 @@ impl_froms! { GenericDefId } -pub trait ToIdByKey: Sized + AstNode + 'static { +pub(crate) trait ToIdByKey: Sized + AstNode + 'static { type ID: Sized + Copy + 'static; const KEY: Key; } @@ -209,11 +185,11 @@ pub trait ToIdByKey: Sized + AstNode + 'static { impl ToId for T { type ID = ::ID; fn to_id( - sb: &mut SourceBinder<'_, DB>, + db: &DB, + sb: &mut SourceBinder, src: InFile, ) -> Option { - let container = sb.find_container(src.as_ref().map(|it| it.syntax()))?; - let db = sb.db; + let container = sb.find_container(db, src.as_ref().map(|it| it.syntax()))?; let dyn_map = &*sb.child_by_source_cache.entry(container).or_insert_with(|| match container { ChildContainer::DefWithBodyId(it) => it.child_by_source(db), @@ -255,15 +231,15 @@ to_id_key_impls![ impl ToId for ast::MacroCall { type ID = MacroDefId; fn to_id( - sb: &mut SourceBinder<'_, DB>, + db: &DB, + sb: &mut SourceBinder, src: InFile, ) -> Option { let kind = MacroDefKind::Declarative; - let krate = sb.to_module_def(src.file_id.original_file(sb.db))?.id.krate; + let krate = sb.to_module_def(db, src.file_id.original_file(db))?.id.krate; - let ast_id = - Some(AstId::new(src.file_id, sb.db.ast_id_map(src.file_id).ast_id(&src.value))); + let ast_id = Some(AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value))); Some(MacroDefId { krate: Some(krate), ast_id, kind }) } @@ -272,20 +248,20 @@ impl ToId for ast::MacroCall { impl ToDef for ast::BindPat { type Def = Local; - fn to_def(sb: &mut SourceBinder<'_, DB>, src: InFile) -> Option { + fn to_def(db: &DB, sb: &mut SourceBinder, src: InFile) -> Option { let file_id = src.file_id; let parent: DefWithBodyId = src.value.syntax().ancestors().find_map(|it| { let res = match_ast! { match it { - ast::ConstDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, - ast::StaticDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, - ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, + ast::ConstDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, + ast::StaticDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, + ast::FnDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, _ => return None, } }; Some(res) })?; - let (_body, source_map) = sb.db.body_with_source_map(parent); + let (_body, source_map) = db.body_with_source_map(parent); let src = src.map(ast::Pat::from); let pat_id = source_map.node_pat(src.as_ref())?; Some(Local { parent: parent.into(), pat_id }) @@ -296,26 +272,26 @@ impl ToDef for ast::TypeParam { type Def = TypeParam; fn to_def( - sb: &mut SourceBinder<'_, DB>, + db: &DB, + sb: &mut SourceBinder, src: InFile, ) -> Option { - let mut sb = SourceBinder::new(sb.db); let file_id = src.file_id; let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| { let res = match_ast! { match it { - ast::FnDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, - ast::StructDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, - ast::EnumDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, - ast::TraitDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, - ast::TypeAliasDef(value) => { sb.to_id(InFile { value, file_id})?.into() }, - ast::ImplBlock(value) => { sb.to_id(InFile { value, file_id})?.into() }, + ast::FnDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, + ast::StructDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, + ast::EnumDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, + ast::TraitDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, + ast::TypeAliasDef(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, + ast::ImplBlock(value) => { sb.to_id(db, InFile { value, file_id})?.into() }, _ => return None, } }; Some(res) })?; - let &id = sb.child_by_source(parent.into())[keys::TYPE_PARAM].get(&src)?; + let &id = sb.child_by_source(db, parent.into())[keys::TYPE_PARAM].get(&src)?; Some(TypeParam { id }) } } @@ -324,7 +300,8 @@ impl ToId for ast::Module { type ID = ModuleId; fn to_id( - sb: &mut SourceBinder<'_, DB>, + db: &DB, + sb: &mut SourceBinder, src: InFile, ) -> Option { { @@ -333,7 +310,7 @@ impl ToId for ast::Module { .as_ref() .map(|it| it.syntax()) .cloned() - .ancestors_with_macros(sb.db) + .ancestors_with_macros(db) .skip(1) .find_map(|it| { let m = ast::Module::cast(it.value.clone())?; @@ -341,15 +318,15 @@ impl ToId for ast::Module { }); let parent_module = match parent_declaration { - Some(parent_declaration) => sb.to_id(parent_declaration)?, + Some(parent_declaration) => sb.to_id(db, parent_declaration)?, None => { - let file_id = src.file_id.original_file(sb.db); - sb.to_module_def(file_id)?.id + let file_id = src.file_id.original_file(db); + sb.to_module_def(db, file_id)?.id } }; let child_name = src.value.name()?.as_name(); - let def_map = sb.db.crate_def_map(parent_module.krate); + let def_map = db.crate_def_map(parent_module.krate); let child_id = *def_map[parent_module.local_id].children.get(&child_name)?; Some(ModuleId { krate: parent_module.krate, local_id: child_id }) } -- cgit v1.2.3