From 0b820cacab020993b6e1667f491289122f03de04 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 26 Mar 2019 14:40:34 +0300 Subject: [PATCH 1/2] move source_id to a separate file --- crates/ra_hir/src/db.rs | 4 +- crates/ra_hir/src/ids.rs | 114 +------------------------ crates/ra_hir/src/lib.rs | 4 +- crates/ra_hir/src/nameres.rs | 3 +- crates/ra_hir/src/nameres/collector.rs | 4 +- crates/ra_hir/src/nameres/raw.rs | 2 +- crates/ra_hir/src/source_binder.rs | 4 +- crates/ra_hir/src/source_id.rs | 113 ++++++++++++++++++++++++ 8 files changed, 128 insertions(+), 120 deletions(-) create mode 100644 crates/ra_hir/src/source_id.rs diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 492814cbbcb..3296b9b31db 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -34,10 +34,10 @@ pub trait DefDatabase: SourceDatabase + AsRef { #[salsa::invoke(crate::traits::TraitData::trait_data_query)] fn trait_data(&self, t: Trait) -> Arc; - #[salsa::invoke(crate::ids::SourceFileItems::file_items_query)] + #[salsa::invoke(crate::source_id::SourceFileItems::file_items_query)] fn file_items(&self, file_id: HirFileId) -> Arc; - #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)] + #[salsa::invoke(crate::source_id::SourceFileItems::file_item_query)] fn file_item(&self, source_item_id: SourceItemId) -> TreeArc; #[salsa::invoke(RawItems::raw_items_query)] diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs index bac7b9e46b9..e73dd5d21d6 100644 --- a/crates/ra_hir/src/ids.rs +++ b/crates/ra_hir/src/ids.rs @@ -5,13 +5,12 @@ }; use ra_db::{LocationInterner, FileId}; -use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; -use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; +use ra_syntax::{TreeArc, SourceFile, AstNode, ast}; +use ra_arena::{RawId, ArenaId, impl_arena_id}; use mbe::MacroRules; use crate::{ - Module, - DefDatabase, + Module, DefDatabase, SourceItemId, SourceFileItemId, }; #[derive(Debug, Default)] @@ -304,110 +303,3 @@ fn interner(interner: &HirInterner) -> &LocationInterner SourceItemId { - SourceItemId { file_id, item_id: self } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct SourceItemId { - pub(crate) file_id: HirFileId, - pub(crate) item_id: SourceFileItemId, -} - -/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back. -#[derive(Debug, PartialEq, Eq)] -pub struct SourceFileItems { - file_id: HirFileId, - arena: Arena, -} - -impl SourceFileItems { - pub(crate) fn file_items_query( - db: &impl DefDatabase, - file_id: HirFileId, - ) -> Arc { - let source_file = db.hir_parse(file_id); - Arc::new(SourceFileItems::from_source_file(&source_file, file_id)) - } - - pub(crate) fn file_item_query( - db: &impl DefDatabase, - source_item_id: SourceItemId, - ) -> TreeArc { - let source_file = db.hir_parse(source_item_id.file_id); - db.file_items(source_item_id.file_id)[source_item_id.item_id] - .to_node(&source_file) - .to_owned() - } - - pub(crate) fn from_source_file( - source_file: &SourceFile, - file_id: HirFileId, - ) -> SourceFileItems { - let mut res = SourceFileItems { file_id, arena: Arena::default() }; - // By walking the tree in bread-first order we make sure that parents - // get lower ids then children. That is, adding a new child does not - // change parent's id. This means that, say, adding a new function to a - // trait does not change ids of top-level items, which helps caching. - bfs(source_file.syntax(), |it| { - if let Some(module_item) = ast::ModuleItem::cast(it) { - res.alloc(module_item.syntax()); - } else if let Some(macro_call) = ast::MacroCall::cast(it) { - res.alloc(macro_call.syntax()); - } - }); - res - } - - fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { - self.arena.alloc(SyntaxNodePtr::new(item)) - } - pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId { - assert_eq!( - self.file_id, file_id, - "SourceFileItems: wrong file, expected {:?}, got {:?}", - self.file_id, file_id - ); - self.id_of_unchecked(item) - } - pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId { - let ptr = SyntaxNodePtr::new(item); - if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) { - return id; - } - panic!( - "Can't find {:?} in SourceFileItems:\n{:?}", - item, - self.arena.iter().map(|(_id, i)| i).collect::>(), - ); - } -} - -impl std::ops::Index for SourceFileItems { - type Output = SyntaxNodePtr; - fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr { - &self.arena[idx] - } -} - -/// Walks the subtree in bfs order, calling `f` for each node. -fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) { - let mut curr_layer = vec![node]; - let mut next_layer = vec![]; - while !curr_layer.is_empty() { - curr_layer.drain(..).for_each(|node| { - next_layer.extend(node.children()); - f(node); - }); - std::mem::swap(&mut curr_layer, &mut next_layer); - } -} diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 87bc8009d36..ac2585de0fe 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -23,6 +23,7 @@ fn from(it: $v) -> $e { mod path; pub mod source_binder; +mod source_id; mod ids; mod name; mod nameres; @@ -47,12 +48,13 @@ fn from(it: $v) -> $e { use crate::{ db::{HirDatabase, DefDatabase}, name::{AsName, KnownName}, - ids::{SourceItemId, SourceFileItems}, + source_id::SourceFileItemId, }; pub use self::{ path::{Path, PathKind}, name::Name, + source_id::{SourceFileItems, SourceItemId}, ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner}, nameres::{PerNs, Namespace}, ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 93c11f271d6..d8fa2383f52 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -63,7 +63,8 @@ use crate::{ ModuleDef, Name, Crate, Module, DefDatabase, Path, PathKind, HirFileId, Trait, - ids::{SourceItemId, SourceFileItemId, MacroCallId, MacroDefId}, + SourceItemId, SourceFileItemId, + ids::{MacroCallId, MacroDefId}, diagnostics::DiagnosticSink, nameres::diagnostics::DefDiagnostic, }; diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 89300d2eccd..4fb29815507 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs @@ -6,7 +6,7 @@ use crate::{ Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, - DefDatabase, HirFileId, Name, Path, + DefDatabase, HirFileId, Name, Path, SourceItemId, KnownName, nameres::{ Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, @@ -14,7 +14,7 @@ diagnostics::DefDiagnostic, raw, }, - ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId, MacroDefId}, + ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId}, }; pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index ee0719ee0e7..f3200460107 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs @@ -12,7 +12,7 @@ use crate::{ DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, - ids::{SourceFileItemId, SourceFileItems}, + SourceFileItemId, SourceFileItems, }; /// `RawItems` is a set of top-level items in a file (except for impls). diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 3645b73b44d..6e157007f46 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -13,9 +13,9 @@ }; use crate::{ - HirDatabase, Function, Struct, Enum, + HirDatabase, Function, Struct, Enum, SourceFileItemId, AsName, Module, HirFileId, Crate, Trait, Resolver, - ids::{LocationCtx, SourceFileItemId}, + ids::LocationCtx, expr }; diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs new file mode 100644 index 00000000000..f961adf8bd7 --- /dev/null +++ b/crates/ra_hir/src/source_id.rs @@ -0,0 +1,113 @@ +use std::sync::Arc; + +use ra_arena::{Arena, RawId, impl_arena_id}; +use ra_syntax::{SyntaxNodePtr, TreeArc, SyntaxNode, SourceFile, AstNode, ast}; + +use crate::{HirFileId, DefDatabase}; + +/// Identifier of item within a specific file. This is stable over reparses, so +/// it's OK to use it as a salsa key/value. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct SourceFileItemId(RawId); +impl_arena_id!(SourceFileItemId); + +impl SourceFileItemId { + pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId { + SourceItemId { file_id, item_id: self } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SourceItemId { + pub(crate) file_id: HirFileId, + pub(crate) item_id: SourceFileItemId, +} + +/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back. +#[derive(Debug, PartialEq, Eq)] +pub struct SourceFileItems { + file_id: HirFileId, + arena: Arena, +} + +impl SourceFileItems { + pub(crate) fn file_items_query( + db: &impl DefDatabase, + file_id: HirFileId, + ) -> Arc { + let source_file = db.hir_parse(file_id); + Arc::new(SourceFileItems::from_source_file(&source_file, file_id)) + } + + pub(crate) fn file_item_query( + db: &impl DefDatabase, + source_item_id: SourceItemId, + ) -> TreeArc { + let source_file = db.hir_parse(source_item_id.file_id); + db.file_items(source_item_id.file_id)[source_item_id.item_id] + .to_node(&source_file) + .to_owned() + } + + pub(crate) fn from_source_file( + source_file: &SourceFile, + file_id: HirFileId, + ) -> SourceFileItems { + let mut res = SourceFileItems { file_id, arena: Arena::default() }; + // By walking the tree in bread-first order we make sure that parents + // get lower ids then children. That is, adding a new child does not + // change parent's id. This means that, say, adding a new function to a + // trait does not change ids of top-level items, which helps caching. + bfs(source_file.syntax(), |it| { + if let Some(module_item) = ast::ModuleItem::cast(it) { + res.alloc(module_item.syntax()); + } else if let Some(macro_call) = ast::MacroCall::cast(it) { + res.alloc(macro_call.syntax()); + } + }); + res + } + + fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId { + self.arena.alloc(SyntaxNodePtr::new(item)) + } + pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId { + assert_eq!( + self.file_id, file_id, + "SourceFileItems: wrong file, expected {:?}, got {:?}", + self.file_id, file_id + ); + self.id_of_unchecked(item) + } + pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId { + let ptr = SyntaxNodePtr::new(item); + if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) { + return id; + } + panic!( + "Can't find {:?} in SourceFileItems:\n{:?}", + item, + self.arena.iter().map(|(_id, i)| i).collect::>(), + ); + } +} + +impl std::ops::Index for SourceFileItems { + type Output = SyntaxNodePtr; + fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr { + &self.arena[idx] + } +} + +/// Walks the subtree in bfs order, calling `f` for each node. +fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) { + let mut curr_layer = vec![node]; + let mut next_layer = vec![]; + while !curr_layer.is_empty() { + curr_layer.drain(..).for_each(|node| { + next_layer.extend(node.children()); + f(node); + }); + std::mem::swap(&mut curr_layer, &mut next_layer); + } +} From f6f2d69bb8318815ff87cd1bfe504fe5aa09ed63 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 26 Mar 2019 14:54:05 +0300 Subject: [PATCH 2/2] simplify --- crates/ra_hir/src/nameres.rs | 6 ++---- crates/ra_hir/src/source_binder.rs | 6 +++--- crates/ra_hir/src/source_id.rs | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index d8fa2383f52..36ef615a3ae 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -61,9 +61,8 @@ use test_utils::tested_by; use crate::{ - ModuleDef, Name, Crate, Module, + ModuleDef, Name, Crate, Module, SourceItemId, DefDatabase, Path, PathKind, HirFileId, Trait, - SourceItemId, SourceFileItemId, ids::{MacroCallId, MacroDefId}, diagnostics::DiagnosticSink, nameres::diagnostics::DefDiagnostic, @@ -242,9 +241,8 @@ pub(crate) fn add_diagnostics( pub(crate) fn find_module_by_source( &self, file_id: HirFileId, - decl_id: Option, + decl_id: Option, ) -> Option { - let decl_id = decl_id.map(|it| it.with_file_id(file_id)); let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { if decl_id.is_some() { module_data.declaration == decl_id diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 6e157007f46..db9e3a22e78 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -13,7 +13,7 @@ }; use crate::{ - HirDatabase, Function, Struct, Enum, SourceFileItemId, + HirDatabase, Function, Struct, Enum, SourceItemId, AsName, Module, HirFileId, Crate, Trait, Resolver, ids::LocationCtx, expr @@ -55,7 +55,7 @@ fn module_from_inline( assert!(!module.has_semi()); let file_id = file_id.into(); let file_items = db.file_items(file_id); - let item_id = file_items.id_of(file_id, module.syntax()); + let item_id = file_items.id_of(file_id, module.syntax()).with_file_id(file_id); module_from_source(db, file_id, Some(item_id)) } @@ -75,7 +75,7 @@ pub fn module_from_child_node( fn module_from_source( db: &impl HirDatabase, file_id: HirFileId, - decl_id: Option, + decl_id: Option, ) -> Option { let source_root_id = db.file_source_root(file_id.as_original_file()); db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( diff --git a/crates/ra_hir/src/source_id.rs b/crates/ra_hir/src/source_id.rs index f961adf8bd7..62707ba6ac9 100644 --- a/crates/ra_hir/src/source_id.rs +++ b/crates/ra_hir/src/source_id.rs @@ -8,7 +8,7 @@ /// Identifier of item within a specific file. This is stable over reparses, so /// it's OK to use it as a salsa key/value. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SourceFileItemId(RawId); +pub(crate) struct SourceFileItemId(RawId); impl_arena_id!(SourceFileItemId); impl SourceFileItemId {