aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/db.rs4
-rw-r--r--crates/ra_hir/src/ids.rs114
-rw-r--r--crates/ra_hir/src/lib.rs4
-rw-r--r--crates/ra_hir/src/nameres.rs7
-rw-r--r--crates/ra_hir/src/nameres/collector.rs4
-rw-r--r--crates/ra_hir/src/nameres/raw.rs2
-rw-r--r--crates/ra_hir/src/source_binder.rs8
-rw-r--r--crates/ra_hir/src/source_id.rs113
8 files changed, 131 insertions, 125 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 492814cbb..3296b9b31 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -34,10 +34,10 @@ pub trait DefDatabase: SourceDatabase + AsRef<HirInterner> {
34 #[salsa::invoke(crate::traits::TraitData::trait_data_query)] 34 #[salsa::invoke(crate::traits::TraitData::trait_data_query)]
35 fn trait_data(&self, t: Trait) -> Arc<TraitData>; 35 fn trait_data(&self, t: Trait) -> Arc<TraitData>;
36 36
37 #[salsa::invoke(crate::ids::SourceFileItems::file_items_query)] 37 #[salsa::invoke(crate::source_id::SourceFileItems::file_items_query)]
38 fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>; 38 fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>;
39 39
40 #[salsa::invoke(crate::ids::SourceFileItems::file_item_query)] 40 #[salsa::invoke(crate::source_id::SourceFileItems::file_item_query)]
41 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>; 41 fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>;
42 42
43 #[salsa::invoke(RawItems::raw_items_query)] 43 #[salsa::invoke(RawItems::raw_items_query)]
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index bac7b9e46..e73dd5d21 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -5,13 +5,12 @@ use std::{
5}; 5};
6 6
7use ra_db::{LocationInterner, FileId}; 7use ra_db::{LocationInterner, FileId};
8use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; 8use ra_syntax::{TreeArc, SourceFile, AstNode, ast};
9use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; 9use ra_arena::{RawId, ArenaId, impl_arena_id};
10use mbe::MacroRules; 10use mbe::MacroRules;
11 11
12use crate::{ 12use crate::{
13 Module, 13 Module, DefDatabase, SourceItemId, SourceFileItemId,
14 DefDatabase,
15}; 14};
16 15
17#[derive(Debug, Default)] 16#[derive(Debug, Default)]
@@ -304,110 +303,3 @@ impl AstItemDef<ast::TypeAliasDef> for TypeId {
304 &interner.types 303 &interner.types
305 } 304 }
306} 305}
307
308/// Identifier of item within a specific file. This is stable over reparses, so
309/// it's OK to use it as a salsa key/value.
310#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
311pub struct SourceFileItemId(RawId);
312impl_arena_id!(SourceFileItemId);
313
314impl SourceFileItemId {
315 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
316 SourceItemId { file_id, item_id: self }
317 }
318}
319
320#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
321pub struct SourceItemId {
322 pub(crate) file_id: HirFileId,
323 pub(crate) item_id: SourceFileItemId,
324}
325
326/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back.
327#[derive(Debug, PartialEq, Eq)]
328pub struct SourceFileItems {
329 file_id: HirFileId,
330 arena: Arena<SourceFileItemId, SyntaxNodePtr>,
331}
332
333impl SourceFileItems {
334 pub(crate) fn file_items_query(
335 db: &impl DefDatabase,
336 file_id: HirFileId,
337 ) -> Arc<SourceFileItems> {
338 let source_file = db.hir_parse(file_id);
339 Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
340 }
341
342 pub(crate) fn file_item_query(
343 db: &impl DefDatabase,
344 source_item_id: SourceItemId,
345 ) -> TreeArc<SyntaxNode> {
346 let source_file = db.hir_parse(source_item_id.file_id);
347 db.file_items(source_item_id.file_id)[source_item_id.item_id]
348 .to_node(&source_file)
349 .to_owned()
350 }
351
352 pub(crate) fn from_source_file(
353 source_file: &SourceFile,
354 file_id: HirFileId,
355 ) -> SourceFileItems {
356 let mut res = SourceFileItems { file_id, arena: Arena::default() };
357 // By walking the tree in bread-first order we make sure that parents
358 // get lower ids then children. That is, adding a new child does not
359 // change parent's id. This means that, say, adding a new function to a
360 // trait does not change ids of top-level items, which helps caching.
361 bfs(source_file.syntax(), |it| {
362 if let Some(module_item) = ast::ModuleItem::cast(it) {
363 res.alloc(module_item.syntax());
364 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
365 res.alloc(macro_call.syntax());
366 }
367 });
368 res
369 }
370
371 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
372 self.arena.alloc(SyntaxNodePtr::new(item))
373 }
374 pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId {
375 assert_eq!(
376 self.file_id, file_id,
377 "SourceFileItems: wrong file, expected {:?}, got {:?}",
378 self.file_id, file_id
379 );
380 self.id_of_unchecked(item)
381 }
382 pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId {
383 let ptr = SyntaxNodePtr::new(item);
384 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) {
385 return id;
386 }
387 panic!(
388 "Can't find {:?} in SourceFileItems:\n{:?}",
389 item,
390 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
391 );
392 }
393}
394
395impl std::ops::Index<SourceFileItemId> for SourceFileItems {
396 type Output = SyntaxNodePtr;
397 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
398 &self.arena[idx]
399 }
400}
401
402/// Walks the subtree in bfs order, calling `f` for each node.
403fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
404 let mut curr_layer = vec![node];
405 let mut next_layer = vec![];
406 while !curr_layer.is_empty() {
407 curr_layer.drain(..).for_each(|node| {
408 next_layer.extend(node.children());
409 f(node);
410 });
411 std::mem::swap(&mut curr_layer, &mut next_layer);
412 }
413}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 87bc8009d..ac2585de0 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -23,6 +23,7 @@ pub mod mock;
23mod path; 23mod path;
24pub mod source_binder; 24pub mod source_binder;
25 25
26mod source_id;
26mod ids; 27mod ids;
27mod name; 28mod name;
28mod nameres; 29mod nameres;
@@ -47,12 +48,13 @@ mod marks;
47use crate::{ 48use crate::{
48 db::{HirDatabase, DefDatabase}, 49 db::{HirDatabase, DefDatabase},
49 name::{AsName, KnownName}, 50 name::{AsName, KnownName},
50 ids::{SourceItemId, SourceFileItems}, 51 source_id::SourceFileItemId,
51}; 52};
52 53
53pub use self::{ 54pub use self::{
54 path::{Path, PathKind}, 55 path::{Path, PathKind},
55 name::Name, 56 name::Name,
57 source_id::{SourceFileItems, SourceItemId},
56 ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner}, 58 ids::{HirFileId, MacroDefId, MacroCallId, MacroCallLoc, HirInterner},
57 nameres::{PerNs, Namespace}, 59 nameres::{PerNs, Namespace},
58 ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay}, 60 ty::{Ty, ApplicationTy, TypeCtor, Substs, display::HirDisplay},
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 93c11f271..36ef615a3 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -61,9 +61,9 @@ use ra_db::{FileId, Edition};
61use test_utils::tested_by; 61use test_utils::tested_by;
62 62
63use crate::{ 63use crate::{
64 ModuleDef, Name, Crate, Module, 64 ModuleDef, Name, Crate, Module, SourceItemId,
65 DefDatabase, Path, PathKind, HirFileId, Trait, 65 DefDatabase, Path, PathKind, HirFileId, Trait,
66 ids::{SourceItemId, SourceFileItemId, MacroCallId, MacroDefId}, 66 ids::{MacroCallId, MacroDefId},
67 diagnostics::DiagnosticSink, 67 diagnostics::DiagnosticSink,
68 nameres::diagnostics::DefDiagnostic, 68 nameres::diagnostics::DefDiagnostic,
69}; 69};
@@ -241,9 +241,8 @@ impl CrateDefMap {
241 pub(crate) fn find_module_by_source( 241 pub(crate) fn find_module_by_source(
242 &self, 242 &self,
243 file_id: HirFileId, 243 file_id: HirFileId,
244 decl_id: Option<SourceFileItemId>, 244 decl_id: Option<SourceItemId>,
245 ) -> Option<CrateModuleId> { 245 ) -> Option<CrateModuleId> {
246 let decl_id = decl_id.map(|it| it.with_file_id(file_id));
247 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { 246 let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| {
248 if decl_id.is_some() { 247 if decl_id.is_some() {
249 module_data.declaration == decl_id 248 module_data.declaration == decl_id
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 89300d2ec..4fb298155 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -6,7 +6,7 @@ use ra_db::FileId;
6 6
7use crate::{ 7use crate::{
8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias, 8 Function, Module, Struct, Enum, Const, Static, Trait, TypeAlias,
9 DefDatabase, HirFileId, Name, Path, 9 DefDatabase, HirFileId, Name, Path, SourceItemId,
10 KnownName, 10 KnownName,
11 nameres::{ 11 nameres::{
12 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode, 12 Resolution, PerNs, ModuleDef, ReachedFixedPoint, ResolveMode,
@@ -14,7 +14,7 @@ use crate::{
14 diagnostics::DefDiagnostic, 14 diagnostics::DefDiagnostic,
15 raw, 15 raw,
16 }, 16 },
17 ids::{AstItemDef, LocationCtx, MacroCallLoc, SourceItemId, MacroCallId, MacroDefId}, 17 ids::{AstItemDef, LocationCtx, MacroCallLoc, MacroCallId, MacroDefId},
18}; 18};
19 19
20pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 20pub(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 ee0719ee0..f32004601 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -12,7 +12,7 @@ use ra_syntax::{
12 12
13use crate::{ 13use crate::{
14 DefDatabase, Name, AsName, Path, HirFileId, ModuleSource, 14 DefDatabase, Name, AsName, Path, HirFileId, ModuleSource,
15 ids::{SourceFileItemId, SourceFileItems}, 15 SourceFileItemId, SourceFileItems,
16}; 16};
17 17
18/// `RawItems` is a set of top-level items in a file (except for impls). 18/// `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 3645b73b4..db9e3a22e 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -13,9 +13,9 @@ use ra_syntax::{
13}; 13};
14 14
15use crate::{ 15use crate::{
16 HirDatabase, Function, Struct, Enum, 16 HirDatabase, Function, Struct, Enum, SourceItemId,
17 AsName, Module, HirFileId, Crate, Trait, Resolver, 17 AsName, Module, HirFileId, Crate, Trait, Resolver,
18 ids::{LocationCtx, SourceFileItemId}, 18 ids::LocationCtx,
19 expr 19 expr
20}; 20};
21 21
@@ -55,7 +55,7 @@ fn module_from_inline(
55 assert!(!module.has_semi()); 55 assert!(!module.has_semi());
56 let file_id = file_id.into(); 56 let file_id = file_id.into();
57 let file_items = db.file_items(file_id); 57 let file_items = db.file_items(file_id);
58 let item_id = file_items.id_of(file_id, module.syntax()); 58 let item_id = file_items.id_of(file_id, module.syntax()).with_file_id(file_id);
59 module_from_source(db, file_id, Some(item_id)) 59 module_from_source(db, file_id, Some(item_id))
60} 60}
61 61
@@ -75,7 +75,7 @@ pub fn module_from_child_node(
75fn module_from_source( 75fn module_from_source(
76 db: &impl HirDatabase, 76 db: &impl HirDatabase,
77 file_id: HirFileId, 77 file_id: HirFileId,
78 decl_id: Option<SourceFileItemId>, 78 decl_id: Option<SourceItemId>,
79) -> Option<Module> { 79) -> Option<Module> {
80 let source_root_id = db.file_source_root(file_id.as_original_file()); 80 let source_root_id = db.file_source_root(file_id.as_original_file());
81 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( 81 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
new file mode 100644
index 000000000..62707ba6a
--- /dev/null
+++ b/crates/ra_hir/src/source_id.rs
@@ -0,0 +1,113 @@
1use std::sync::Arc;
2
3use ra_arena::{Arena, RawId, impl_arena_id};
4use ra_syntax::{SyntaxNodePtr, TreeArc, SyntaxNode, SourceFile, AstNode, ast};
5
6use crate::{HirFileId, DefDatabase};
7
8/// Identifier of item within a specific file. This is stable over reparses, so
9/// it's OK to use it as a salsa key/value.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub(crate) struct SourceFileItemId(RawId);
12impl_arena_id!(SourceFileItemId);
13
14impl SourceFileItemId {
15 pub(crate) fn with_file_id(self, file_id: HirFileId) -> SourceItemId {
16 SourceItemId { file_id, item_id: self }
17 }
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21pub struct SourceItemId {
22 pub(crate) file_id: HirFileId,
23 pub(crate) item_id: SourceFileItemId,
24}
25
26/// Maps items' `SyntaxNode`s to `SourceFileItemId`s and back.
27#[derive(Debug, PartialEq, Eq)]
28pub struct SourceFileItems {
29 file_id: HirFileId,
30 arena: Arena<SourceFileItemId, SyntaxNodePtr>,
31}
32
33impl SourceFileItems {
34 pub(crate) fn file_items_query(
35 db: &impl DefDatabase,
36 file_id: HirFileId,
37 ) -> Arc<SourceFileItems> {
38 let source_file = db.hir_parse(file_id);
39 Arc::new(SourceFileItems::from_source_file(&source_file, file_id))
40 }
41
42 pub(crate) fn file_item_query(
43 db: &impl DefDatabase,
44 source_item_id: SourceItemId,
45 ) -> TreeArc<SyntaxNode> {
46 let source_file = db.hir_parse(source_item_id.file_id);
47 db.file_items(source_item_id.file_id)[source_item_id.item_id]
48 .to_node(&source_file)
49 .to_owned()
50 }
51
52 pub(crate) fn from_source_file(
53 source_file: &SourceFile,
54 file_id: HirFileId,
55 ) -> SourceFileItems {
56 let mut res = SourceFileItems { file_id, arena: Arena::default() };
57 // By walking the tree in bread-first order we make sure that parents
58 // get lower ids then children. That is, adding a new child does not
59 // change parent's id. This means that, say, adding a new function to a
60 // trait does not change ids of top-level items, which helps caching.
61 bfs(source_file.syntax(), |it| {
62 if let Some(module_item) = ast::ModuleItem::cast(it) {
63 res.alloc(module_item.syntax());
64 } else if let Some(macro_call) = ast::MacroCall::cast(it) {
65 res.alloc(macro_call.syntax());
66 }
67 });
68 res
69 }
70
71 fn alloc(&mut self, item: &SyntaxNode) -> SourceFileItemId {
72 self.arena.alloc(SyntaxNodePtr::new(item))
73 }
74 pub(crate) fn id_of(&self, file_id: HirFileId, item: &SyntaxNode) -> SourceFileItemId {
75 assert_eq!(
76 self.file_id, file_id,
77 "SourceFileItems: wrong file, expected {:?}, got {:?}",
78 self.file_id, file_id
79 );
80 self.id_of_unchecked(item)
81 }
82 pub(crate) fn id_of_unchecked(&self, item: &SyntaxNode) -> SourceFileItemId {
83 let ptr = SyntaxNodePtr::new(item);
84 if let Some((id, _)) = self.arena.iter().find(|(_id, i)| **i == ptr) {
85 return id;
86 }
87 panic!(
88 "Can't find {:?} in SourceFileItems:\n{:?}",
89 item,
90 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
91 );
92 }
93}
94
95impl std::ops::Index<SourceFileItemId> for SourceFileItems {
96 type Output = SyntaxNodePtr;
97 fn index(&self, idx: SourceFileItemId) -> &SyntaxNodePtr {
98 &self.arena[idx]
99 }
100}
101
102/// Walks the subtree in bfs order, calling `f` for each node.
103fn bfs(node: &SyntaxNode, mut f: impl FnMut(&SyntaxNode)) {
104 let mut curr_layer = vec![node];
105 let mut next_layer = vec![];
106 while !curr_layer.is_empty() {
107 curr_layer.drain(..).for_each(|node| {
108 next_layer.extend(node.children());
109 f(node);
110 });
111 std::mem::swap(&mut curr_layer, &mut next_layer);
112 }
113}