diff options
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r-- | crates/ra_analysis/src/completion.rs | 2 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/imp.rs | 20 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/mod.rs | 95 | ||||
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/scope.rs | 15 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 20 |
5 files changed, 114 insertions, 38 deletions
diff --git a/crates/ra_analysis/src/completion.rs b/crates/ra_analysis/src/completion.rs index 6bd1233f9..6667c06e7 100644 --- a/crates/ra_analysis/src/completion.rs +++ b/crates/ra_analysis/src/completion.rs | |||
@@ -148,7 +148,7 @@ fn complete_module_items( | |||
148 | this_item: Option<ast::NameRef>, | 148 | this_item: Option<ast::NameRef>, |
149 | acc: &mut Vec<CompletionItem>, | 149 | acc: &mut Vec<CompletionItem>, |
150 | ) { | 150 | ) { |
151 | let scope = ModuleScope::from_items(items); | 151 | let scope = ModuleScope::new(items); // FIXME |
152 | acc.extend( | 152 | acc.extend( |
153 | scope | 153 | scope |
154 | .entries() | 154 | .entries() |
diff --git a/crates/ra_analysis/src/descriptors/module/imp.rs b/crates/ra_analysis/src/descriptors/module/imp.rs index 1c102f4e5..3a010ecf5 100644 --- a/crates/ra_analysis/src/descriptors/module/imp.rs +++ b/crates/ra_analysis/src/descriptors/module/imp.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, NameOwner}, | 4 | ast::{self, ModuleItemOwner, NameOwner}, |
5 | SmolStr, | 5 | SmolStr, |
6 | }; | 6 | }; |
7 | use relative_path::RelativePathBuf; | 7 | use relative_path::RelativePathBuf; |
@@ -14,7 +14,10 @@ use crate::{ | |||
14 | Cancelable, FileId, FileResolverImp, | 14 | Cancelable, FileId, FileResolverImp, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | use super::{LinkData, LinkId, ModuleData, ModuleId, ModuleScope, ModuleTree, Problem}; | 17 | use super::{ |
18 | LinkData, LinkId, ModuleData, ModuleId, ModuleScope, ModuleSource, ModuleSourceNode, | ||
19 | ModuleTree, Problem, | ||
20 | }; | ||
18 | 21 | ||
19 | pub(crate) fn submodules( | 22 | pub(crate) fn submodules( |
20 | db: &impl DescriptorDatabase, | 23 | db: &impl DescriptorDatabase, |
@@ -43,9 +46,14 @@ pub(crate) fn module_scope( | |||
43 | module_id: ModuleId, | 46 | module_id: ModuleId, |
44 | ) -> Cancelable<Arc<ModuleScope>> { | 47 | ) -> Cancelable<Arc<ModuleScope>> { |
45 | let tree = db.module_tree(source_root_id)?; | 48 | let tree = db.module_tree(source_root_id)?; |
46 | let file_id = module_id.file_id(&tree); | 49 | let source = module_id.source(&tree).resolve(db); |
47 | let syntax = db.file_syntax(file_id); | 50 | let res = match source { |
48 | let res = ModuleScope::new(&syntax); | 51 | ModuleSourceNode::Root(root) => ModuleScope::new(root.ast().items()), |
52 | ModuleSourceNode::Inline(inline) => match inline.ast().item_list() { | ||
53 | Some(items) => ModuleScope::new(items.items()), | ||
54 | None => ModuleScope::new(std::iter::empty()), | ||
55 | }, | ||
56 | }; | ||
49 | Ok(Arc::new(res)) | 57 | Ok(Arc::new(res)) |
50 | } | 58 | } |
51 | 59 | ||
@@ -106,7 +114,7 @@ fn build_subtree( | |||
106 | ) -> Cancelable<ModuleId> { | 114 | ) -> Cancelable<ModuleId> { |
107 | visited.insert(file_id); | 115 | visited.insert(file_id); |
108 | let id = tree.push_mod(ModuleData { | 116 | let id = tree.push_mod(ModuleData { |
109 | file_id, | 117 | source: ModuleSource::File(file_id), |
110 | parent, | 118 | parent, |
111 | children: Vec::new(), | 119 | children: Vec::new(), |
112 | }); | 120 | }); |
diff --git a/crates/ra_analysis/src/descriptors/module/mod.rs b/crates/ra_analysis/src/descriptors/module/mod.rs index 302e3e81c..e22489fc1 100644 --- a/crates/ra_analysis/src/descriptors/module/mod.rs +++ b/crates/ra_analysis/src/descriptors/module/mod.rs | |||
@@ -7,10 +7,17 @@ use ra_syntax::{ | |||
7 | }; | 7 | }; |
8 | use relative_path::RelativePathBuf; | 8 | use relative_path::RelativePathBuf; |
9 | 9 | ||
10 | use crate::FileId; | 10 | use crate::{db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId}; |
11 | 11 | ||
12 | pub(crate) use self::scope::ModuleScope; | 12 | pub(crate) use self::scope::ModuleScope; |
13 | 13 | ||
14 | /// Phisically, rust source is organized as a set of files, but logically it is | ||
15 | /// organized as a tree of modules. Usually, a single file corresponds to a | ||
16 | /// single module, but it is not nessary the case. | ||
17 | /// | ||
18 | /// Module encapsulate the logic of transitioning from the fuzzy world of files | ||
19 | /// (which can have multiple parents) to the precise world of modules (which | ||
20 | /// always have one parent). | ||
14 | #[derive(Debug, PartialEq, Eq, Hash)] | 21 | #[derive(Debug, PartialEq, Eq, Hash)] |
15 | pub(crate) struct ModuleTree { | 22 | pub(crate) struct ModuleTree { |
16 | mods: Vec<ModuleData>, | 23 | mods: Vec<ModuleData>, |
@@ -22,7 +29,7 @@ impl ModuleTree { | |||
22 | self.mods | 29 | self.mods |
23 | .iter() | 30 | .iter() |
24 | .enumerate() | 31 | .enumerate() |
25 | .filter(|(_idx, it)| it.file_id == file_id) | 32 | .filter(|(_idx, it)| it.source.is_file(file_id)) |
26 | .map(|(idx, _)| ModuleId(idx as u32)) | 33 | .map(|(idx, _)| ModuleId(idx as u32)) |
27 | .collect() | 34 | .collect() |
28 | } | 35 | } |
@@ -32,6 +39,23 @@ impl ModuleTree { | |||
32 | } | 39 | } |
33 | } | 40 | } |
34 | 41 | ||
42 | /// `ModuleSource` is the syntax tree element that produced this module: | ||
43 | /// either a file, or an inlinde module. | ||
44 | /// TODO: we don't produce Inline modules yet | ||
45 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | ||
46 | pub(crate) enum ModuleSource { | ||
47 | File(FileId), | ||
48 | #[allow(dead_code)] | ||
49 | Inline(SyntaxPtr), | ||
50 | } | ||
51 | |||
52 | /// An owned syntax node for a module. Unlike `ModuleSource`, | ||
53 | /// this holds onto the AST for the whole file. | ||
54 | enum ModuleSourceNode { | ||
55 | Root(ast::RootNode), | ||
56 | Inline(ast::ModuleNode), | ||
57 | } | ||
58 | |||
35 | #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] | 59 | #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] |
36 | pub(crate) struct ModuleId(u32); | 60 | pub(crate) struct ModuleId(u32); |
37 | 61 | ||
@@ -50,8 +74,8 @@ pub enum Problem { | |||
50 | } | 74 | } |
51 | 75 | ||
52 | impl ModuleId { | 76 | impl ModuleId { |
53 | pub(crate) fn file_id(self, tree: &ModuleTree) -> FileId { | 77 | pub(crate) fn source(self, tree: &ModuleTree) -> ModuleSource { |
54 | tree.module(self).file_id | 78 | tree.module(self).source |
55 | } | 79 | } |
56 | pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { | 80 | pub(crate) fn parent_link(self, tree: &ModuleTree) -> Option<LinkId> { |
57 | tree.module(self).parent | 81 | tree.module(self).parent |
@@ -82,14 +106,18 @@ impl ModuleId { | |||
82 | .find(|it| it.name == name)?; | 106 | .find(|it| it.name == name)?; |
83 | Some(*link.points_to.first()?) | 107 | Some(*link.points_to.first()?) |
84 | } | 108 | } |
85 | pub(crate) fn problems(self, tree: &ModuleTree, root: ast::Root) -> Vec<(SyntaxNode, Problem)> { | 109 | pub(crate) fn problems( |
110 | self, | ||
111 | tree: &ModuleTree, | ||
112 | db: &impl SyntaxDatabase, | ||
113 | ) -> Vec<(SyntaxNode, Problem)> { | ||
86 | tree.module(self) | 114 | tree.module(self) |
87 | .children | 115 | .children |
88 | .iter() | 116 | .iter() |
89 | .filter_map(|&it| { | 117 | .filter_map(|&it| { |
90 | let p = tree.link(it).problem.clone()?; | 118 | let p = tree.link(it).problem.clone()?; |
91 | let s = it.bind_source(tree, root); | 119 | let s = it.bind_source(tree, db); |
92 | let s = s.name().unwrap().syntax().owned(); | 120 | let s = s.ast().name().unwrap().syntax().owned(); |
93 | Some((s, p)) | 121 | Some((s, p)) |
94 | }) | 122 | }) |
95 | .collect() | 123 | .collect() |
@@ -100,21 +128,62 @@ impl LinkId { | |||
100 | pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { | 128 | pub(crate) fn owner(self, tree: &ModuleTree) -> ModuleId { |
101 | tree.link(self).owner | 129 | tree.link(self).owner |
102 | } | 130 | } |
103 | pub(crate) fn bind_source<'a>(self, tree: &ModuleTree, root: ast::Root<'a>) -> ast::Module<'a> { | 131 | pub(crate) fn bind_source<'a>( |
104 | imp::modules(root) | 132 | self, |
105 | .find(|(name, _)| name == &tree.link(self).name) | 133 | tree: &ModuleTree, |
106 | .unwrap() | 134 | db: &impl SyntaxDatabase, |
107 | .1 | 135 | ) -> ast::ModuleNode { |
136 | let owner = self.owner(tree); | ||
137 | match owner.source(tree).resolve(db) { | ||
138 | ModuleSourceNode::Root(root) => { | ||
139 | let ast = imp::modules(root.ast()) | ||
140 | .find(|(name, _)| name == &tree.link(self).name) | ||
141 | .unwrap() | ||
142 | .1; | ||
143 | ast.into() | ||
144 | } | ||
145 | ModuleSourceNode::Inline(..) => { | ||
146 | unimplemented!("https://github.com/rust-analyzer/rust-analyzer/issues/181") | ||
147 | } | ||
148 | } | ||
108 | } | 149 | } |
109 | } | 150 | } |
110 | 151 | ||
111 | #[derive(Debug, PartialEq, Eq, Hash)] | 152 | #[derive(Debug, PartialEq, Eq, Hash)] |
112 | struct ModuleData { | 153 | struct ModuleData { |
113 | file_id: FileId, | 154 | source: ModuleSource, |
114 | parent: Option<LinkId>, | 155 | parent: Option<LinkId>, |
115 | children: Vec<LinkId>, | 156 | children: Vec<LinkId>, |
116 | } | 157 | } |
117 | 158 | ||
159 | impl ModuleSource { | ||
160 | pub(crate) fn as_file(self) -> Option<FileId> { | ||
161 | match self { | ||
162 | ModuleSource::File(f) => Some(f), | ||
163 | ModuleSource::Inline(..) => None, | ||
164 | } | ||
165 | } | ||
166 | |||
167 | fn resolve(self, db: &impl SyntaxDatabase) -> ModuleSourceNode { | ||
168 | match self { | ||
169 | ModuleSource::File(file_id) => { | ||
170 | let syntax = db.file_syntax(file_id); | ||
171 | ModuleSourceNode::Root(syntax.ast().into()) | ||
172 | } | ||
173 | ModuleSource::Inline(ptr) => { | ||
174 | let syntax = db.resolve_syntax_ptr(ptr); | ||
175 | let syntax = syntax.borrowed(); | ||
176 | let module = ast::Module::cast(syntax).unwrap(); | ||
177 | ModuleSourceNode::Inline(module.into()) | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | |||
182 | fn is_file(self, file_id: FileId) -> bool { | ||
183 | self.as_file() == Some(file_id) | ||
184 | } | ||
185 | } | ||
186 | |||
118 | #[derive(Hash, Debug, PartialEq, Eq)] | 187 | #[derive(Hash, Debug, PartialEq, Eq)] |
119 | struct LinkData { | 188 | struct LinkData { |
120 | owner: ModuleId, | 189 | owner: ModuleId, |
diff --git a/crates/ra_analysis/src/descriptors/module/scope.rs b/crates/ra_analysis/src/descriptors/module/scope.rs index 681e272c2..215b31f8e 100644 --- a/crates/ra_analysis/src/descriptors/module/scope.rs +++ b/crates/ra_analysis/src/descriptors/module/scope.rs | |||
@@ -1,9 +1,6 @@ | |||
1 | //! Backend for module-level scope resolution & completion | 1 | //! Backend for module-level scope resolution & completion |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ast, AstNode, SmolStr}; |
4 | ast::{self, ModuleItemOwner}, | ||
5 | AstNode, File, SmolStr, | ||
6 | }; | ||
7 | 4 | ||
8 | use crate::syntax_ptr::LocalSyntaxPtr; | 5 | use crate::syntax_ptr::LocalSyntaxPtr; |
9 | 6 | ||
@@ -28,11 +25,7 @@ enum EntryKind { | |||
28 | } | 25 | } |
29 | 26 | ||
30 | impl ModuleScope { | 27 | impl ModuleScope { |
31 | pub fn new(file: &File) -> ModuleScope { | 28 | pub(crate) fn new<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope { |
32 | ModuleScope::from_items(file.ast().items()) | ||
33 | } | ||
34 | |||
35 | pub fn from_items<'a>(items: impl Iterator<Item = ast::ModuleItem<'a>>) -> ModuleScope { | ||
36 | let mut entries = Vec::new(); | 29 | let mut entries = Vec::new(); |
37 | for item in items { | 30 | for item in items { |
38 | let entry = match item { | 31 | let entry = match item { |
@@ -102,11 +95,11 @@ fn collect_imports(tree: ast::UseTree, acc: &mut Vec<Entry>) { | |||
102 | #[cfg(test)] | 95 | #[cfg(test)] |
103 | mod tests { | 96 | mod tests { |
104 | use super::*; | 97 | use super::*; |
105 | use ra_syntax::File; | 98 | use ra_syntax::{ast::ModuleItemOwner, File}; |
106 | 99 | ||
107 | fn do_check(code: &str, expected: &[&str]) { | 100 | fn do_check(code: &str, expected: &[&str]) { |
108 | let file = File::parse(&code); | 101 | let file = File::parse(&code); |
109 | let scope = ModuleScope::new(&file); | 102 | let scope = ModuleScope::new(file.ast().items()); |
110 | let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>(); | 103 | let actual = scope.entries.iter().map(|it| it.name()).collect::<Vec<_>>(); |
111 | assert_eq!(expected, actual.as_slice()); | 104 | assert_eq!(expected, actual.as_slice()); |
112 | } | 105 | } |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 0744ea9c8..060e2b606 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -20,7 +20,7 @@ use crate::{ | |||
20 | db::{self, FileSyntaxQuery, SyntaxDatabase}, | 20 | db::{self, FileSyntaxQuery, SyntaxDatabase}, |
21 | descriptors::{ | 21 | descriptors::{ |
22 | function::{FnDescriptor, FnId}, | 22 | function::{FnDescriptor, FnId}, |
23 | module::{ModuleTree, Problem}, | 23 | module::{ModuleSource, ModuleTree, Problem}, |
24 | DeclarationDescriptor, DescriptorDatabase, | 24 | DeclarationDescriptor, DescriptorDatabase, |
25 | }, | 25 | }, |
26 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, | 26 | input::{FilesDatabase, SourceRoot, SourceRootId, WORKSPACE}, |
@@ -222,9 +222,15 @@ impl AnalysisImpl { | |||
222 | .into_iter() | 222 | .into_iter() |
223 | .filter_map(|module_id| { | 223 | .filter_map(|module_id| { |
224 | let link = module_id.parent_link(&module_tree)?; | 224 | let link = module_id.parent_link(&module_tree)?; |
225 | let file_id = link.owner(&module_tree).file_id(&module_tree); | 225 | let file_id = match link.owner(&module_tree).source(&module_tree) { |
226 | let syntax = self.db.file_syntax(file_id); | 226 | ModuleSource::File(file_id) => file_id, |
227 | let decl = link.bind_source(&module_tree, syntax.ast()); | 227 | ModuleSource::Inline(..) => { |
228 | //TODO: https://github.com/rust-analyzer/rust-analyzer/issues/181 | ||
229 | return None; | ||
230 | } | ||
231 | }; | ||
232 | let decl = link.bind_source(&module_tree, &self.db); | ||
233 | let decl = decl.ast(); | ||
228 | 234 | ||
229 | let sym = FileSymbol { | 235 | let sym = FileSymbol { |
230 | name: decl.name().unwrap().text(), | 236 | name: decl.name().unwrap().text(), |
@@ -243,7 +249,7 @@ impl AnalysisImpl { | |||
243 | .modules_for_file(file_id) | 249 | .modules_for_file(file_id) |
244 | .into_iter() | 250 | .into_iter() |
245 | .map(|it| it.root(&module_tree)) | 251 | .map(|it| it.root(&module_tree)) |
246 | .map(|it| it.file_id(&module_tree)) | 252 | .filter_map(|it| it.source(&module_tree).as_file()) |
247 | .filter_map(|it| crate_graph.crate_id_for_crate_root(it)) | 253 | .filter_map(|it| crate_graph.crate_id_for_crate_root(it)) |
248 | .collect(); | 254 | .collect(); |
249 | 255 | ||
@@ -365,7 +371,7 @@ impl AnalysisImpl { | |||
365 | }) | 371 | }) |
366 | .collect::<Vec<_>>(); | 372 | .collect::<Vec<_>>(); |
367 | if let Some(m) = module_tree.any_module_for_file(file_id) { | 373 | if let Some(m) = module_tree.any_module_for_file(file_id) { |
368 | for (name_node, problem) in m.problems(&module_tree, syntax.ast()) { | 374 | for (name_node, problem) in m.problems(&module_tree, &self.db) { |
369 | let diag = match problem { | 375 | let diag = match problem { |
370 | Problem::UnresolvedModule { candidate } => { | 376 | Problem::UnresolvedModule { candidate } => { |
371 | let create_file = FileSystemEdit::CreateFile { | 377 | let create_file = FileSystemEdit::CreateFile { |
@@ -533,7 +539,7 @@ impl AnalysisImpl { | |||
533 | }; | 539 | }; |
534 | module_id | 540 | module_id |
535 | .child(module_tree, name.as_str()) | 541 | .child(module_tree, name.as_str()) |
536 | .map(|it| it.file_id(module_tree)) | 542 | .and_then(|it| it.source(&module_tree).as_file()) |
537 | .into_iter() | 543 | .into_iter() |
538 | .collect() | 544 | .collect() |
539 | } | 545 | } |