diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/src/db.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 114 | ||||
-rw-r--r-- | crates/ra_hir/src/lib.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres.rs | 7 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/source_id.rs | 113 |
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 | ||
7 | use ra_db::{LocationInterner, FileId}; | 7 | use ra_db::{LocationInterner, FileId}; |
8 | use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast}; | 8 | use ra_syntax::{TreeArc, SourceFile, AstNode, ast}; |
9 | use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; | 9 | use ra_arena::{RawId, ArenaId, impl_arena_id}; |
10 | use mbe::MacroRules; | 10 | use mbe::MacroRules; |
11 | 11 | ||
12 | use crate::{ | 12 | use 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)] | ||
311 | pub struct SourceFileItemId(RawId); | ||
312 | impl_arena_id!(SourceFileItemId); | ||
313 | |||
314 | impl 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)] | ||
321 | pub 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)] | ||
328 | pub struct SourceFileItems { | ||
329 | file_id: HirFileId, | ||
330 | arena: Arena<SourceFileItemId, SyntaxNodePtr>, | ||
331 | } | ||
332 | |||
333 | impl 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 | |||
395 | impl 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. | ||
403 | fn 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; | |||
23 | mod path; | 23 | mod path; |
24 | pub mod source_binder; | 24 | pub mod source_binder; |
25 | 25 | ||
26 | mod source_id; | ||
26 | mod ids; | 27 | mod ids; |
27 | mod name; | 28 | mod name; |
28 | mod nameres; | 29 | mod nameres; |
@@ -47,12 +48,13 @@ mod marks; | |||
47 | use crate::{ | 48 | use 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 | ||
53 | pub use self::{ | 54 | pub 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}; | |||
61 | use test_utils::tested_by; | 61 | use test_utils::tested_by; |
62 | 62 | ||
63 | use crate::{ | 63 | use 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 | ||
7 | use crate::{ | 7 | use 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 | ||
20 | pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { | 20 | 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 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 | ||
13 | use crate::{ | 13 | use 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 | ||
15 | use crate::{ | 15 | use 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( | |||
75 | fn module_from_source( | 75 | fn 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 @@ | |||
1 | use std::sync::Arc; | ||
2 | |||
3 | use ra_arena::{Arena, RawId, impl_arena_id}; | ||
4 | use ra_syntax::{SyntaxNodePtr, TreeArc, SyntaxNode, SourceFile, AstNode, ast}; | ||
5 | |||
6 | use 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)] | ||
11 | pub(crate) struct SourceFileItemId(RawId); | ||
12 | impl_arena_id!(SourceFileItemId); | ||
13 | |||
14 | impl 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)] | ||
21 | pub 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)] | ||
28 | pub struct SourceFileItems { | ||
29 | file_id: HirFileId, | ||
30 | arena: Arena<SourceFileItemId, SyntaxNodePtr>, | ||
31 | } | ||
32 | |||
33 | impl 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 | |||
95 | impl 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. | ||
103 | fn 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 | } | ||