aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/hir/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src/hir/mod.rs')
-rw-r--r--crates/ra_analysis/src/hir/mod.rs144
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
8pub(crate) mod function;
9pub(crate) mod module;
10mod path;
11
12use std::sync::Arc;
13
14use ra_syntax::{
15 ast::{self, FnDefNode, AstNode},
16 TextRange, SyntaxNode,
17};
18
19use 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
33pub(crate) use self::path::{Path, PathKind};
34pub(crate) use self::module::nameres::FileItemId;
35
36salsa::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
80pub(crate) enum Def {
81 Module(ModuleDescriptor),
82 Item,
83}
84
85impl 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)]
100pub struct ReferenceDescriptor {
101 pub range: TextRange,
102 pub name: String,
103}
104
105#[derive(Debug)]
106pub struct DeclarationDescriptor<'a> {
107 pat: ast::BindPat<'a>,
108 pub range: TextRange,
109}
110
111impl<'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}