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.rs99
1 files changed, 95 insertions, 4 deletions
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index 6665d902d..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, ModuleId}; 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,
@@ -84,6 +84,97 @@ impl TestDB {
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();