diff options
Diffstat (limited to 'crates/ra_analysis/src/hir/mod.rs')
-rw-r--r-- | crates/ra_analysis/src/hir/mod.rs | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/crates/ra_analysis/src/hir/mod.rs b/crates/ra_analysis/src/hir/mod.rs new file mode 100644 index 000000000..6bee2b5c4 --- /dev/null +++ b/crates/ra_analysis/src/hir/mod.rs | |||
@@ -0,0 +1,144 @@ | |||
1 | //! HIR (previsouly known as descriptors) provides a high-level OO acess to Rust | ||
2 | //! code. | ||
3 | //! | ||
4 | //! The principal difference between HIR and syntax trees is that HIR is bound | ||
5 | //! to a particular crate instance. That is, it has cfg flags and features | ||
6 | //! applied. So, there relation between syntax and HIR is many-to-one. | ||
7 | |||
8 | pub(crate) mod function; | ||
9 | pub(crate) mod module; | ||
10 | mod path; | ||
11 | |||
12 | use std::sync::Arc; | ||
13 | |||
14 | use ra_syntax::{ | ||
15 | ast::{self, FnDefNode, AstNode}, | ||
16 | TextRange, SyntaxNode, | ||
17 | }; | ||
18 | |||
19 | use crate::{ | ||
20 | FileId, | ||
21 | db::SyntaxDatabase, | ||
22 | hir::function::{resolve_local_name, FnId, FnScopes}, | ||
23 | hir::module::{ | ||
24 | ModuleId, ModuleTree, ModuleSource, ModuleDescriptor, | ||
25 | nameres::{ItemMap, InputModuleItems, FileItems} | ||
26 | }, | ||
27 | input::SourceRootId, | ||
28 | loc2id::{IdDatabase, DefId, DefLoc}, | ||
29 | syntax_ptr::LocalSyntaxPtr, | ||
30 | Cancelable, | ||
31 | }; | ||
32 | |||
33 | pub(crate) use self::path::{Path, PathKind}; | ||
34 | pub(crate) use self::module::nameres::FileItemId; | ||
35 | |||
36 | salsa::query_group! { | ||
37 | pub(crate) trait DescriptorDatabase: SyntaxDatabase + IdDatabase { | ||
38 | fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> { | ||
39 | type FnScopesQuery; | ||
40 | use fn function::imp::fn_scopes; | ||
41 | } | ||
42 | |||
43 | fn _file_items(file_id: FileId) -> Arc<FileItems> { | ||
44 | type FileItemsQuery; | ||
45 | storage dependencies; | ||
46 | use fn module::nameres::file_items; | ||
47 | } | ||
48 | |||
49 | fn _file_item(file_id: FileId, file_item_id: FileItemId) -> SyntaxNode { | ||
50 | type FileItemQuery; | ||
51 | storage dependencies; | ||
52 | use fn module::nameres::file_item; | ||
53 | } | ||
54 | |||
55 | fn _input_module_items(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<InputModuleItems>> { | ||
56 | type InputModuleItemsQuery; | ||
57 | use fn module::nameres::input_module_items; | ||
58 | } | ||
59 | fn _item_map(source_root_id: SourceRootId) -> Cancelable<Arc<ItemMap>> { | ||
60 | type ItemMapQuery; | ||
61 | use fn module::nameres::item_map; | ||
62 | } | ||
63 | fn _module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> { | ||
64 | type ModuleTreeQuery; | ||
65 | use fn module::imp::module_tree; | ||
66 | } | ||
67 | fn _fn_syntax(fn_id: FnId) -> FnDefNode { | ||
68 | type FnSyntaxQuery; | ||
69 | // Don't retain syntax trees in memory | ||
70 | storage dependencies; | ||
71 | use fn function::imp::fn_syntax; | ||
72 | } | ||
73 | fn _submodules(source: ModuleSource) -> Cancelable<Arc<Vec<module::imp::Submodule>>> { | ||
74 | type SubmodulesQuery; | ||
75 | use fn module::imp::submodules; | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | |||
80 | pub(crate) enum Def { | ||
81 | Module(ModuleDescriptor), | ||
82 | Item, | ||
83 | } | ||
84 | |||
85 | impl DefId { | ||
86 | pub(crate) fn resolve(self, db: &impl DescriptorDatabase) -> Cancelable<Def> { | ||
87 | let loc = db.id_maps().def_loc(self); | ||
88 | let res = match loc { | ||
89 | DefLoc::Module { id, source_root } => { | ||
90 | let descr = ModuleDescriptor::new(db, source_root, id)?; | ||
91 | Def::Module(descr) | ||
92 | } | ||
93 | DefLoc::Item { .. } => Def::Item, | ||
94 | }; | ||
95 | Ok(res) | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #[derive(Debug)] | ||
100 | pub struct ReferenceDescriptor { | ||
101 | pub range: TextRange, | ||
102 | pub name: String, | ||
103 | } | ||
104 | |||
105 | #[derive(Debug)] | ||
106 | pub struct DeclarationDescriptor<'a> { | ||
107 | pat: ast::BindPat<'a>, | ||
108 | pub range: TextRange, | ||
109 | } | ||
110 | |||
111 | impl<'a> DeclarationDescriptor<'a> { | ||
112 | pub fn new(pat: ast::BindPat) -> DeclarationDescriptor { | ||
113 | let range = pat.syntax().range(); | ||
114 | |||
115 | DeclarationDescriptor { pat, range } | ||
116 | } | ||
117 | |||
118 | pub fn find_all_refs(&self) -> Vec<ReferenceDescriptor> { | ||
119 | let name_ptr = LocalSyntaxPtr::new(self.pat.syntax()); | ||
120 | |||
121 | let fn_def = match self.pat.syntax().ancestors().find_map(ast::FnDef::cast) { | ||
122 | Some(def) => def, | ||
123 | None => return Default::default(), | ||
124 | }; | ||
125 | |||
126 | let fn_scopes = FnScopes::new(fn_def); | ||
127 | |||
128 | let refs: Vec<_> = fn_def | ||
129 | .syntax() | ||
130 | .descendants() | ||
131 | .filter_map(ast::NameRef::cast) | ||
132 | .filter(|name_ref| match resolve_local_name(*name_ref, &fn_scopes) { | ||
133 | None => false, | ||
134 | Some(entry) => entry.ptr() == name_ptr, | ||
135 | }) | ||
136 | .map(|name_ref| ReferenceDescriptor { | ||
137 | name: name_ref.syntax().text().to_string(), | ||
138 | range: name_ref.syntax().range(), | ||
139 | }) | ||
140 | .collect(); | ||
141 | |||
142 | refs | ||
143 | } | ||
144 | } | ||