aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def/src/test_db.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_def/src/test_db.rs')
-rw-r--r--crates/hir_def/src/test_db.rs111
1 files changed, 101 insertions, 10 deletions
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index 574c0201a..eda982c85 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -5,17 +5,17 @@ use std::{
5 sync::{Arc, Mutex}, 5 sync::{Arc, Mutex},
6}; 6};
7 7
8use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; 8use base_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, FilePosition, Upcast};
9use base_db::{AnchoredPath, SourceDatabase}; 9use base_db::{AnchoredPath, SourceDatabase};
10use hir_expand::db::AstDatabase;
11use hir_expand::diagnostics::Diagnostic; 10use hir_expand::diagnostics::Diagnostic;
12use hir_expand::diagnostics::DiagnosticSinkBuilder; 11use hir_expand::diagnostics::DiagnosticSinkBuilder;
12use hir_expand::{db::AstDatabase, InFile};
13use rustc_hash::FxHashMap; 13use rustc_hash::FxHashMap;
14use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15use syntax::{TextRange, TextSize}; 15use syntax::{algo, ast, AstNode, TextRange, TextSize};
16use test_utils::extract_annotations; 16use test_utils::extract_annotations;
17 17
18use crate::{db::DefDatabase, ModuleDefId}; 18use crate::{db::DefDatabase, nameres::DefMap, Lookup, ModuleDefId, ModuleId};
19 19
20#[salsa::database( 20#[salsa::database(
21 base_db::SourceDatabaseExtStorage, 21 base_db::SourceDatabaseExtStorage,
@@ -72,18 +72,109 @@ impl FileLoader for TestDB {
72} 72}
73 73
74impl TestDB { 74impl TestDB {
75 pub(crate) fn module_for_file(&self, file_id: FileId) -> crate::ModuleId { 75 pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
76 for &krate in self.relevant_crates(file_id).iter() { 76 for &krate in self.relevant_crates(file_id).iter() {
77 let crate_def_map = self.crate_def_map(krate); 77 let crate_def_map = self.crate_def_map(krate);
78 for (local_id, data) in crate_def_map.modules.iter() { 78 for (local_id, data) in crate_def_map.modules() {
79 if data.origin.file_id() == Some(file_id) { 79 if data.origin.file_id() == Some(file_id) {
80 return crate::ModuleId { krate, local_id }; 80 return crate_def_map.module_id(local_id);
81 } 81 }
82 } 82 }
83 } 83 }
84 panic!("Can't find module for file") 84 panic!("Can't find module for file")
85 } 85 }
86 86
87 pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId {
88 let file_module = self.module_for_file(position.file_id);
89 let mut def_map = file_module.def_map(self);
90
91 def_map = match self.block_at_position(&def_map, position) {
92 Some(it) => it,
93 None => return file_module,
94 };
95 loop {
96 let new_map = self.block_at_position(&def_map, position);
97 match new_map {
98 Some(new_block) if !Arc::ptr_eq(&new_block, &def_map) => {
99 def_map = new_block;
100 }
101 _ => {
102 // FIXME: handle `mod` inside block expression
103 return def_map.module_id(def_map.root());
104 }
105 }
106 }
107 }
108
109 fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> {
110 // Find the smallest (innermost) function in `def_map` containing the cursor.
111 let mut size = None;
112 let mut fn_def = None;
113 for (_, module) in def_map.modules() {
114 let file_id = module.definition_source(self).file_id;
115 if file_id != position.file_id.into() {
116 continue;
117 }
118 let root = self.parse_or_expand(file_id).unwrap();
119 let ast_map = self.ast_id_map(file_id);
120 let item_tree = self.item_tree(file_id);
121 for decl in module.scope.declarations() {
122 if let ModuleDefId::FunctionId(it) = decl {
123 let ast =
124 ast_map.get(item_tree[it.lookup(self).id.value].ast_id).to_node(&root);
125 let range = ast.syntax().text_range();
126
127 if !range.contains(position.offset) {
128 continue;
129 }
130
131 let new_size = match size {
132 None => range.len(),
133 Some(size) => {
134 if range.len() < size {
135 range.len()
136 } else {
137 size
138 }
139 }
140 };
141 if size != Some(new_size) {
142 size = Some(new_size);
143 fn_def = Some(it);
144 }
145 }
146 }
147 }
148
149 // Find the innermost block expression that has a `DefMap`.
150 let def_with_body = fn_def?.into();
151 let (_, source_map) = self.body_with_source_map(def_with_body);
152 let scopes = self.expr_scopes(def_with_body);
153 let root = self.parse(position.file_id);
154
155 let scope_iter = algo::ancestors_at_offset(&root.syntax_node(), position.offset)
156 .filter_map(|node| {
157 let block = ast::BlockExpr::cast(node)?;
158 let expr = ast::Expr::from(block);
159 let expr_id = source_map.node_expr(InFile::new(position.file_id.into(), &expr))?;
160 let scope = scopes.scope_for(expr_id).unwrap();
161 Some(scope)
162 });
163
164 for scope in scope_iter {
165 let containing_blocks =
166 scopes.scope_chain(Some(scope)).filter_map(|scope| scopes.block(scope));
167
168 for block in containing_blocks {
169 if let Some(def_map) = self.block_def_map(block) {
170 return Some(def_map);
171 }
172 }
173 }
174
175 None
176 }
177
87 pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> { 178 pub(crate) fn log(&self, f: impl FnOnce()) -> Vec<salsa::Event> {
88 *self.events.lock().unwrap() = Some(Vec::new()); 179 *self.events.lock().unwrap() = Some(Vec::new());
89 f(); 180 f();
@@ -110,7 +201,7 @@ impl TestDB {
110 let crate_graph = self.crate_graph(); 201 let crate_graph = self.crate_graph();
111 for krate in crate_graph.iter() { 202 for krate in crate_graph.iter() {
112 let crate_def_map = self.crate_def_map(krate); 203 let crate_def_map = self.crate_def_map(krate);
113 for (module_id, _) in crate_def_map.modules.iter() { 204 for (module_id, _) in crate_def_map.modules() {
114 let file_id = crate_def_map[module_id].origin.file_id(); 205 let file_id = crate_def_map[module_id].origin.file_id();
115 files.extend(file_id) 206 files.extend(file_id)
116 } 207 }
@@ -135,7 +226,7 @@ impl TestDB {
135 let crate_def_map = self.crate_def_map(krate); 226 let crate_def_map = self.crate_def_map(krate);
136 227
137 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb); 228 let mut sink = DiagnosticSinkBuilder::new().build(&mut cb);
138 for (module_id, module) in crate_def_map.modules.iter() { 229 for (module_id, module) in crate_def_map.modules() {
139 crate_def_map.add_diagnostics(self, module_id, &mut sink); 230 crate_def_map.add_diagnostics(self, module_id, &mut sink);
140 231
141 for decl in module.scope.declarations() { 232 for decl in module.scope.declarations() {
@@ -161,7 +252,7 @@ impl TestDB {
161 let node = src.map(|ptr| ptr.to_node(&root)); 252 let node = src.map(|ptr| ptr.to_node(&root));
162 let frange = node.as_ref().original_file_range(db); 253 let frange = node.as_ref().original_file_range(db);
163 254
164 let message = d.message().to_owned(); 255 let message = d.message();
165 actual.entry(frange.file_id).or_default().push((frange.range, message)); 256 actual.entry(frange.file_id).or_default().push((frange.range, message));
166 }); 257 });
167 258