aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/descriptors
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-10-31 07:56:31 +0000
committerAleksey Kladov <[email protected]>2018-10-31 07:56:31 +0000
commitb67295134bf5c518b39bc88abbe1bc5b9d7d3baf (patch)
treea507432668deef7b216cb7c6360620619e904060 /crates/ra_analysis/src/descriptors
parent3068af79ffd23656ff2d46ac92d9192ce6c813fb (diff)
Move FnDescriptors to analyzer
Diffstat (limited to 'crates/ra_analysis/src/descriptors')
-rw-r--r--crates/ra_analysis/src/descriptors/function/imp.rs26
-rw-r--r--crates/ra_analysis/src/descriptors/function/mod.rs83
-rw-r--r--crates/ra_analysis/src/descriptors/function/scope.rs435
-rw-r--r--crates/ra_analysis/src/descriptors/mod.rs88
-rw-r--r--crates/ra_analysis/src/descriptors/module/imp.rs19
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs28
-rw-r--r--crates/ra_analysis/src/descriptors/module/scope.rs6
7 files changed, 595 insertions, 90 deletions
diff --git a/crates/ra_analysis/src/descriptors/function/imp.rs b/crates/ra_analysis/src/descriptors/function/imp.rs
new file mode 100644
index 000000000..0a006f733
--- /dev/null
+++ b/crates/ra_analysis/src/descriptors/function/imp.rs
@@ -0,0 +1,26 @@
1use std::sync::Arc;
2
3use ra_syntax::{
4 ast::{AstNode, FnDef, FnDefNode},
5};
6
7use crate::{
8 descriptors::{
9 DescriptorDatabase,
10 function::{FnId, FnScopes},
11 },
12};
13
14/// Resolve `FnId` to the corresponding `SyntaxNode`
15/// TODO: this should return something more type-safe then `SyntaxNode`
16pub(crate) fn fn_syntax(db: &impl DescriptorDatabase, fn_id: FnId) -> FnDefNode {
17 let syntax = db.resolve_syntax_ptr(fn_id.0);
18 let fn_def = FnDef::cast(syntax.borrowed()).unwrap();
19 FnDefNode::new(fn_def)
20}
21
22pub(crate) fn fn_scopes(db: &impl DescriptorDatabase, fn_id: FnId) -> Arc<FnScopes> {
23 let syntax = db.fn_syntax(fn_id);
24 let res = FnScopes::new(syntax.ast());
25 Arc::new(res)
26}
diff --git a/crates/ra_analysis/src/descriptors/function/mod.rs b/crates/ra_analysis/src/descriptors/function/mod.rs
new file mode 100644
index 000000000..687413ddc
--- /dev/null
+++ b/crates/ra_analysis/src/descriptors/function/mod.rs
@@ -0,0 +1,83 @@
1pub(super) mod imp;
2mod scope;
3
4use ra_syntax::{
5 ast::{self, AstNode, NameOwner}
6};
7
8use crate::{
9 FileId,
10 syntax_ptr::SyntaxPtr
11};
12
13pub(crate) use self::scope::FnScopes;
14
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub(crate) struct FnId(SyntaxPtr);
18
19impl FnId {
20 pub(crate) fn new(file_id: FileId, fn_def: ast::FnDef) -> FnId {
21 let ptr = SyntaxPtr::new(file_id, fn_def.syntax());
22 FnId(ptr)
23 }
24}
25
26
27#[derive(Debug, Clone)]
28pub struct FnDescriptor {
29 pub name: String,
30 pub label: String,
31 pub ret_type: Option<String>,
32 pub params: Vec<String>,
33}
34
35impl FnDescriptor {
36 pub fn new(node: ast::FnDef) -> Option<Self> {
37 let name = node.name()?.text().to_string();
38
39 // Strip the body out for the label.
40 let label: String = if let Some(body) = node.body() {
41 let body_range = body.syntax().range();
42 let label: String = node
43 .syntax()
44 .children()
45 .filter(|child| !child.range().is_subrange(&body_range))
46 .map(|node| node.text().to_string())
47 .collect();
48 label
49 } else {
50 node.syntax().text().to_string()
51 };
52
53 let params = FnDescriptor::param_list(node);
54 let ret_type = node.ret_type().map(|r| r.syntax().text().to_string());
55
56 Some(FnDescriptor {
57 name,
58 ret_type,
59 params,
60 label,
61 })
62 }
63
64 fn param_list(node: ast::FnDef) -> Vec<String> {
65 let mut res = vec![];
66 if let Some(param_list) = node.param_list() {
67 if let Some(self_param) = param_list.self_param() {
68 res.push(self_param.syntax().text().to_string())
69 }
70
71 // Maybe use param.pat here? See if we can just extract the name?
72 //res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
73 res.extend(
74 param_list
75 .params()
76 .filter_map(|p| p.pat())
77 .map(|pat| pat.syntax().text().to_string()),
78 );
79 }
80 res
81 }
82}
83
diff --git a/crates/ra_analysis/src/descriptors/function/scope.rs b/crates/ra_analysis/src/descriptors/function/scope.rs
new file mode 100644
index 000000000..5333a0a3b
--- /dev/null
+++ b/crates/ra_analysis/src/descriptors/function/scope.rs
@@ -0,0 +1,435 @@
1use rustc_hash::FxHashMap;
2
3use ra_syntax::{
4 algo::generate,
5 ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
6 AstNode, SmolStr, SyntaxNodeRef,
7};
8
9use crate::syntax_ptr::LocalSyntaxPtr;
10
11#[derive(Clone, Copy, PartialEq, Eq, Debug)]
12pub(crate) struct ScopeId(u32);
13
14#[derive(Debug, PartialEq, Eq)]
15pub struct FnScopes {
16 pub(crate) self_param: Option<LocalSyntaxPtr>,
17 scopes: Vec<ScopeData>,
18 scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>,
19}
20
21#[derive(Debug, PartialEq, Eq)]
22pub struct ScopeEntry {
23 name: SmolStr,
24 ptr: LocalSyntaxPtr,
25}
26
27#[derive(Debug, PartialEq, Eq)]
28struct ScopeData {
29 parent: Option<ScopeId>,
30 entries: Vec<ScopeEntry>,
31}
32
33impl FnScopes {
34 pub(crate) fn new(fn_def: ast::FnDef) -> FnScopes {
35 let mut scopes = FnScopes {
36 self_param: fn_def
37 .param_list()
38 .and_then(|it| it.self_param())
39 .map(|it| LocalSyntaxPtr::new(it.syntax())),
40 scopes: Vec::new(),
41 scope_for: FxHashMap::default(),
42 };
43 let root = scopes.root_scope();
44 scopes.add_params_bindings(root, fn_def.param_list());
45 if let Some(body) = fn_def.body() {
46 compute_block_scopes(body, &mut scopes, root)
47 }
48 scopes
49 }
50 pub(crate) fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
51 &self.get(scope).entries
52 }
53 pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
54 generate(self.scope_for(node), move |&scope| {
55 self.get(scope).parent
56 })
57 }
58 fn root_scope(&mut self) -> ScopeId {
59 let res = ScopeId(self.scopes.len() as u32);
60 self.scopes.push(ScopeData {
61 parent: None,
62 entries: vec![],
63 });
64 res
65 }
66 fn new_scope(&mut self, parent: ScopeId) -> ScopeId {
67 let res = ScopeId(self.scopes.len() as u32);
68 self.scopes.push(ScopeData {
69 parent: Some(parent),
70 entries: vec![],
71 });
72 res
73 }
74 fn add_bindings(&mut self, scope: ScopeId, pat: ast::Pat) {
75 let entries = pat
76 .syntax()
77 .descendants()
78 .filter_map(ast::BindPat::cast)
79 .filter_map(ScopeEntry::new);
80 self.get_mut(scope).entries.extend(entries);
81 }
82 fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) {
83 params
84 .into_iter()
85 .flat_map(|it| it.params())
86 .filter_map(|it| it.pat())
87 .for_each(|it| self.add_bindings(scope, it));
88 }
89 fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
90 self.scope_for.insert(LocalSyntaxPtr::new(node), scope);
91 }
92 fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
93 node.ancestors()
94 .map(LocalSyntaxPtr::new)
95 .filter_map(|it| self.scope_for.get(&it).map(|&scope| scope))
96 .next()
97 }
98 fn get(&self, scope: ScopeId) -> &ScopeData {
99 &self.scopes[scope.0 as usize]
100 }
101 fn get_mut(&mut self, scope: ScopeId) -> &mut ScopeData {
102 &mut self.scopes[scope.0 as usize]
103 }
104}
105
106impl ScopeEntry {
107 fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
108 let name = pat.name()?;
109 let res = ScopeEntry {
110 name: name.text(),
111 ptr: LocalSyntaxPtr::new(pat.syntax()),
112 };
113 Some(res)
114 }
115 pub(crate) fn name(&self) -> &SmolStr {
116 &self.name
117 }
118 pub(crate) fn ptr(&self) -> LocalSyntaxPtr {
119 self.ptr
120 }
121}
122
123fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
124 for stmt in block.statements() {
125 match stmt {
126 ast::Stmt::LetStmt(stmt) => {
127 if let Some(expr) = stmt.initializer() {
128 scopes.set_scope(expr.syntax(), scope);
129 compute_expr_scopes(expr, scopes, scope);
130 }
131 scope = scopes.new_scope(scope);
132 if let Some(pat) = stmt.pat() {
133 scopes.add_bindings(scope, pat);
134 }
135 }
136 ast::Stmt::ExprStmt(expr_stmt) => {
137 if let Some(expr) = expr_stmt.expr() {
138 scopes.set_scope(expr.syntax(), scope);
139 compute_expr_scopes(expr, scopes, scope);
140 }
141 }
142 }
143 }
144 if let Some(expr) = block.expr() {
145 scopes.set_scope(expr.syntax(), scope);
146 compute_expr_scopes(expr, scopes, scope);
147 }
148}
149
150fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
151 match expr {
152 ast::Expr::IfExpr(e) => {
153 let cond_scope = e
154 .condition()
155 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
156 if let Some(block) = e.then_branch() {
157 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
158 }
159 if let Some(block) = e.else_branch() {
160 compute_block_scopes(block, scopes, scope);
161 }
162 }
163 ast::Expr::BlockExpr(e) => {
164 if let Some(block) = e.block() {
165 compute_block_scopes(block, scopes, scope);
166 }
167 }
168 ast::Expr::LoopExpr(e) => {
169 if let Some(block) = e.loop_body() {
170 compute_block_scopes(block, scopes, scope);
171 }
172 }
173 ast::Expr::WhileExpr(e) => {
174 let cond_scope = e
175 .condition()
176 .and_then(|cond| compute_cond_scopes(cond, scopes, scope));
177 if let Some(block) = e.loop_body() {
178 compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
179 }
180 }
181 ast::Expr::ForExpr(e) => {
182 if let Some(expr) = e.iterable() {
183 compute_expr_scopes(expr, scopes, scope);
184 }
185 let mut scope = scope;
186 if let Some(pat) = e.pat() {
187 scope = scopes.new_scope(scope);
188 scopes.add_bindings(scope, pat);
189 }
190 if let Some(block) = e.loop_body() {
191 compute_block_scopes(block, scopes, scope);
192 }
193 }
194 ast::Expr::LambdaExpr(e) => {
195 let scope = scopes.new_scope(scope);
196 scopes.add_params_bindings(scope, e.param_list());
197 if let Some(body) = e.body() {
198 scopes.set_scope(body.syntax(), scope);
199 compute_expr_scopes(body, scopes, scope);
200 }
201 }
202 ast::Expr::CallExpr(e) => {
203 compute_call_scopes(e.expr(), e.arg_list(), scopes, scope);
204 }
205 ast::Expr::MethodCallExpr(e) => {
206 compute_call_scopes(e.expr(), e.arg_list(), scopes, scope);
207 }
208 ast::Expr::MatchExpr(e) => {
209 if let Some(expr) = e.expr() {
210 compute_expr_scopes(expr, scopes, scope);
211 }
212 for arm in e.match_arm_list().into_iter().flat_map(|it| it.arms()) {
213 let scope = scopes.new_scope(scope);
214 for pat in arm.pats() {
215 scopes.add_bindings(scope, pat);
216 }
217 if let Some(expr) = arm.expr() {
218 compute_expr_scopes(expr, scopes, scope);
219 }
220 }
221 }
222 _ => expr
223 .syntax()
224 .children()
225 .filter_map(ast::Expr::cast)
226 .for_each(|expr| compute_expr_scopes(expr, scopes, scope)),
227 };
228
229 fn compute_call_scopes(
230 receiver: Option<ast::Expr>,
231 arg_list: Option<ast::ArgList>,
232 scopes: &mut FnScopes,
233 scope: ScopeId,
234 ) {
235 arg_list
236 .into_iter()
237 .flat_map(|it| it.args())
238 .chain(receiver)
239 .for_each(|expr| compute_expr_scopes(expr, scopes, scope));
240 }
241
242 fn compute_cond_scopes(
243 cond: ast::Condition,
244 scopes: &mut FnScopes,
245 scope: ScopeId,
246 ) -> Option<ScopeId> {
247 if let Some(expr) = cond.expr() {
248 compute_expr_scopes(expr, scopes, scope);
249 }
250 if let Some(pat) = cond.pat() {
251 let s = scopes.new_scope(scope);
252 scopes.add_bindings(s, pat);
253 Some(s)
254 } else {
255 None
256 }
257 }
258}
259
260pub fn resolve_local_name<'a>(
261 name_ref: ast::NameRef,
262 scopes: &'a FnScopes,
263) -> Option<&'a ScopeEntry> {
264 use rustc_hash::FxHashSet;
265
266 let mut shadowed = FxHashSet::default();
267 let ret = scopes
268 .scope_chain(name_ref.syntax())
269 .flat_map(|scope| scopes.entries(scope).iter())
270 .filter(|entry| shadowed.insert(entry.name()))
271 .filter(|entry| entry.name() == &name_ref.text())
272 .nth(0);
273 ret
274}
275
276#[cfg(test)]
277mod tests {
278 use ra_syntax::File;
279 use test_utils::extract_offset;
280 use ra_editor::{find_node_at_offset};
281
282 use super::*;
283
284
285 fn do_check(code: &str, expected: &[&str]) {
286 let (off, code) = extract_offset(code);
287 let code = {
288 let mut buf = String::new();
289 let off = u32::from(off) as usize;
290 buf.push_str(&code[..off]);
291 buf.push_str("marker");
292 buf.push_str(&code[off..]);
293 buf
294 };
295 let file = File::parse(&code);
296 let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
297 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
298 let scopes = FnScopes::new(fn_def);
299 let actual = scopes
300 .scope_chain(marker.syntax())
301 .flat_map(|scope| scopes.entries(scope))
302 .map(|it| it.name())
303 .collect::<Vec<_>>();
304 assert_eq!(actual.as_slice(), expected);
305 }
306
307 #[test]
308 fn test_lambda_scope() {
309 do_check(
310 r"
311 fn quux(foo: i32) {
312 let f = |bar, baz: i32| {
313 <|>
314 };
315 }",
316 &["bar", "baz", "foo"],
317 );
318 }
319
320 #[test]
321 fn test_call_scope() {
322 do_check(
323 r"
324 fn quux() {
325 f(|x| <|> );
326 }",
327 &["x"],
328 );
329 }
330
331 #[test]
332 fn test_metod_call_scope() {
333 do_check(
334 r"
335 fn quux() {
336 z.f(|x| <|> );
337 }",
338 &["x"],
339 );
340 }
341
342 #[test]
343 fn test_loop_scope() {
344 do_check(
345 r"
346 fn quux() {
347 loop {
348 let x = ();
349 <|>
350 };
351 }",
352 &["x"],
353 );
354 }
355
356 #[test]
357 fn test_match() {
358 do_check(
359 r"
360 fn quux() {
361 match () {
362 Some(x) => {
363 <|>
364 }
365 };
366 }",
367 &["x"],
368 );
369 }
370
371 #[test]
372 fn test_shadow_variable() {
373 do_check(
374 r"
375 fn foo(x: String) {
376 let x : &str = &x<|>;
377 }",
378 &["x"],
379 );
380 }
381
382 fn do_check_local_name(code: &str, expected_offset: u32) {
383 let (off, code) = extract_offset(code);
384 let file = File::parse(&code);
385 let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
386 let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
387
388 let scopes = FnScopes::new(fn_def);
389
390 let local_name_entry = resolve_local_name(name_ref, &scopes).unwrap();
391 let local_name = local_name_entry.ptr().resolve(&file);
392 let expected_name =
393 find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
394 assert_eq!(local_name.range(), expected_name.syntax().range());
395 }
396
397 #[test]
398 fn test_resolve_local_name() {
399 do_check_local_name(
400 r#"
401 fn foo(x: i32, y: u32) {
402 {
403 let z = x * 2;
404 }
405 {
406 let t = x<|> * 3;
407 }
408 }"#,
409 21,
410 );
411 }
412
413 #[test]
414 fn test_resolve_local_name_declaration() {
415 do_check_local_name(
416 r#"
417 fn foo(x: String) {
418 let x : &str = &x<|>;
419 }"#,
420 21,
421 );
422 }
423
424 #[test]
425 fn test_resolve_local_name_shadow() {
426 do_check_local_name(
427 r"
428 fn foo(x: String) {
429 let x : &str = &x;
430 x<|>
431 }",
432 46,
433 );
434 }
435}
diff --git a/crates/ra_analysis/src/descriptors/mod.rs b/crates/ra_analysis/src/descriptors/mod.rs
index 0220f7d5d..0c4991757 100644
--- a/crates/ra_analysis/src/descriptors/mod.rs
+++ b/crates/ra_analysis/src/descriptors/mod.rs
@@ -1,62 +1,46 @@
1pub(crate) mod module; 1pub(crate) mod module;
2pub(crate) mod function;
3
4use std::sync::Arc;
2 5
3use ra_syntax::{ 6use ra_syntax::{
4 ast::{self, AstNode, NameOwner}, 7 SmolStr,
8 ast::{FnDefNode},
5}; 9};
6 10
7#[derive(Debug, Clone)] 11use crate::{
8pub struct FnDescriptor { 12 FileId, Cancelable,
9 pub name: String, 13 db::SyntaxDatabase,
10 pub label: String, 14 descriptors::module::{ModuleTree, ModuleId, ModuleScope},
11 pub ret_type: Option<String>, 15 descriptors::function::{FnId, FnScopes},
12 pub params: Vec<String>, 16 input::SourceRootId,
13} 17 syntax_ptr::SyntaxPtrDatabase,
14 18};
15impl FnDescriptor {
16 pub fn new(node: ast::FnDef) -> Option<Self> {
17 let name = node.name()?.text().to_string();
18
19 // Strip the body out for the label.
20 let label: String = if let Some(body) = node.body() {
21 let body_range = body.syntax().range();
22 let label: String = node
23 .syntax()
24 .children()
25 .filter(|child| !child.range().is_subrange(&body_range))
26 .map(|node| node.text().to_string())
27 .collect();
28 label
29 } else {
30 node.syntax().text().to_string()
31 };
32
33 let params = FnDescriptor::param_list(node);
34 let ret_type = node.ret_type().map(|r| r.syntax().text().to_string());
35
36 Some(FnDescriptor {
37 name,
38 ret_type,
39 params,
40 label,
41 })
42 }
43 19
44 fn param_list(node: ast::FnDef) -> Vec<String> {
45 let mut res = vec![];
46 if let Some(param_list) = node.param_list() {
47 if let Some(self_param) = param_list.self_param() {
48 res.push(self_param.syntax().text().to_string())
49 }
50 20
51 // Maybe use param.pat here? See if we can just extract the name? 21salsa::query_group! {
52 //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); 22 pub(crate) trait DescriptorDatabase: SyntaxDatabase + SyntaxPtrDatabase {
53 res.extend( 23 fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
54 param_list 24 type ModuleTreeQuery;
55 .params() 25 use fn module::imp::module_tree;
56 .filter_map(|p| p.pat()) 26 }
57 .map(|pat| pat.syntax().text().to_string()), 27 fn submodules(file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> {
58 ); 28 type SubmodulesQuery;
29 use fn module::imp::submodules;
30 }
31 fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> {
32 type ModuleScopeQuery;
33 use fn module::imp::module_scope;
34 }
35 fn fn_syntax(fn_id: FnId) -> FnDefNode {
36 type FnSyntaxQuery;
37 // Don't retain syntax trees in memory
38 storage volatile;
39 use fn function::imp::fn_syntax;
40 }
41 fn fn_scopes(fn_id: FnId) -> Arc<FnScopes> {
42 type FnScopesQuery;
43 use fn function::imp::fn_scopes;
59 } 44 }
60 res
61 } 45 }
62} 46}
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs
index 5fdaad137..dae3a356d 100644
--- a/crates/ra_analysis/src/descriptors/module/imp.rs
+++ b/crates/ra_analysis/src/descriptors/module/imp.rs
@@ -10,14 +10,15 @@ use ra_syntax::{
10use crate::{ 10use crate::{
11 FileId, Cancelable, FileResolverImp, db, 11 FileId, Cancelable, FileResolverImp, db,
12 input::{SourceRoot, SourceRootId}, 12 input::{SourceRoot, SourceRootId},
13 descriptors::DescriptorDatabase,
13}; 14};
14 15
15use super::{ 16use super::{
16 ModuleData, ModuleTree, ModuleId, LinkId, LinkData, Problem, ModulesDatabase, ModuleScope 17 ModuleData, ModuleTree, ModuleId, LinkId, LinkData, Problem, ModuleScope
17}; 18};
18 19
19 20
20pub(super) fn submodules(db: &impl ModulesDatabase, file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> { 21pub(crate) fn submodules(db: &impl DescriptorDatabase, file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> {
21 db::check_canceled(db)?; 22 db::check_canceled(db)?;
22 let file = db.file_syntax(file_id); 23 let file = db.file_syntax(file_id);
23 let root = file.ast(); 24 let root = file.ast();
@@ -25,7 +26,7 @@ pub(super) fn submodules(db: &impl ModulesDatabase, file_id: FileId) -> Cancelab
25 Ok(Arc::new(submodules)) 26 Ok(Arc::new(submodules))
26} 27}
27 28
28pub(super) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast::Module<'_>)> { 29pub(crate) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast::Module<'_>)> {
29 root.modules().filter_map(|module| { 30 root.modules().filter_map(|module| {
30 let name = module.name()?.text(); 31 let name = module.name()?.text();
31 if !module.has_semi() { 32 if !module.has_semi() {
@@ -35,8 +36,8 @@ pub(super) fn modules(root: ast::Root<'_>) -> impl Iterator<Item = (SmolStr, ast
35 }) 36 })
36} 37}
37 38
38pub(super) fn module_scope( 39pub(crate) fn module_scope(
39 db: &impl ModulesDatabase, 40 db: &impl DescriptorDatabase,
40 source_root_id: SourceRootId, 41 source_root_id: SourceRootId,
41 module_id: ModuleId, 42 module_id: ModuleId,
42) -> Cancelable<Arc<ModuleScope>> { 43) -> Cancelable<Arc<ModuleScope>> {
@@ -47,8 +48,8 @@ pub(super) fn module_scope(
47 Ok(Arc::new(res)) 48 Ok(Arc::new(res))
48} 49}
49 50
50pub(super) fn module_tree( 51pub(crate) fn module_tree(
51 db: &impl ModulesDatabase, 52 db: &impl DescriptorDatabase,
52 source_root: SourceRootId, 53 source_root: SourceRootId,
53) -> Cancelable<Arc<ModuleTree>> { 54) -> Cancelable<Arc<ModuleTree>> {
54 db::check_canceled(db)?; 55 db::check_canceled(db)?;
@@ -64,7 +65,7 @@ pub struct Submodule {
64 65
65 66
66fn create_module_tree<'a>( 67fn create_module_tree<'a>(
67 db: &impl ModulesDatabase, 68 db: &impl DescriptorDatabase,
68 source_root: SourceRootId, 69 source_root: SourceRootId,
69) -> Cancelable<ModuleTree> { 70) -> Cancelable<ModuleTree> {
70 let mut tree = ModuleTree { 71 let mut tree = ModuleTree {
@@ -88,7 +89,7 @@ fn create_module_tree<'a>(
88} 89}
89 90
90fn build_subtree( 91fn build_subtree(
91 db: &impl ModulesDatabase, 92 db: &impl DescriptorDatabase,
92 source_root: &SourceRoot, 93 source_root: &SourceRoot,
93 tree: &mut ModuleTree, 94 tree: &mut ModuleTree,
94 visited: &mut FxHashSet<FileId>, 95 visited: &mut FxHashSet<FileId>,
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs
index 9e5d73f94..667553f74 100644
--- a/crates/ra_analysis/src/descriptors/module/mod.rs
+++ b/crates/ra_analysis/src/descriptors/module/mod.rs
@@ -1,37 +1,13 @@
1mod imp; 1pub(super) mod imp;
2pub(crate) mod scope; 2pub(crate) mod scope;
3 3
4use std::sync::Arc;
5
6use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
7use ra_syntax::{ast::{self, NameOwner, AstNode}, SmolStr, SyntaxNode}; 5use ra_syntax::{ast::{self, NameOwner, AstNode}, SmolStr, SyntaxNode};
8 6
9use crate::{ 7use crate::FileId;
10 FileId, Cancelable,
11 db::SyntaxDatabase,
12 input::SourceRootId,
13};
14 8
15pub(crate) use self::scope::ModuleScope; 9pub(crate) use self::scope::ModuleScope;
16 10
17salsa::query_group! {
18 pub(crate) trait ModulesDatabase: SyntaxDatabase {
19 fn module_tree(source_root_id: SourceRootId) -> Cancelable<Arc<ModuleTree>> {
20 type ModuleTreeQuery;
21 use fn imp::module_tree;
22 }
23 fn submodules(file_id: FileId) -> Cancelable<Arc<Vec<SmolStr>>> {
24 type SubmodulesQuery;
25 use fn imp::submodules;
26 }
27 fn module_scope(source_root_id: SourceRootId, module_id: ModuleId) -> Cancelable<Arc<ModuleScope>> {
28 type ModuleScopeQuery;
29 use fn imp::module_scope;
30 }
31 }
32}
33
34
35#[derive(Debug, PartialEq, Eq, Hash)] 11#[derive(Debug, PartialEq, Eq, Hash)]
36pub(crate) struct ModuleTree { 12pub(crate) struct ModuleTree {
37 mods: Vec<ModuleData>, 13 mods: Vec<ModuleData>,
diff --git a/crates/ra_analysis/src/descriptors/module/scope.rs b/crates/ra_analysis/src/descriptors/module/scope.rs
index da58ddce0..0f8f325ab 100644
--- a/crates/ra_analysis/src/descriptors/module/scope.rs
+++ b/crates/ra_analysis/src/descriptors/module/scope.rs
@@ -2,8 +2,8 @@
2 2
3 3
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, AstChildren, ModuleItemOwner}, 5 ast::{self, ModuleItemOwner},
6 File, AstNode, SmolStr, SyntaxNode, SyntaxNodeRef, 6 File, AstNode, SmolStr,
7}; 7};
8 8
9use crate::syntax_ptr::LocalSyntaxPtr; 9use crate::syntax_ptr::LocalSyntaxPtr;
@@ -99,7 +99,7 @@ fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) {
99#[cfg(test)] 99#[cfg(test)]
100mod tests { 100mod tests {
101 use super::*; 101 use super::*;
102 use ra_syntax::{ast::ModuleItemOwner, File}; 102 use ra_syntax::{File};
103 103
104 fn do_check(code: &str, expected: &[&str]) { 104 fn do_check(code: &str, expected: &[&str]) {
105 let file = File::parse(&code); 105 let file = File::parse(&code);