aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/completion.rs2
-rw-r--r--crates/ra_analysis/src/descriptors/module/imp.rs20
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs95
-rw-r--r--crates/ra_analysis/src/descriptors/module/scope.rs15
-rw-r--r--crates/ra_analysis/src/imp.rs20
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 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, NameOwner}, 4 ast::{self, ModuleItemOwner, NameOwner},
5 SmolStr, 5 SmolStr,
6}; 6};
7use relative_path::RelativePathBuf; 7use relative_path::RelativePathBuf;
@@ -14,7 +14,10 @@ use crate::{
14 Cancelable, FileId, FileResolverImp, 14 Cancelable, FileId, FileResolverImp,
15}; 15};
16 16
17use super::{LinkData, LinkId, ModuleData, ModuleId, ModuleScope, ModuleTree, Problem}; 17use super::{
18 LinkData, LinkId, ModuleData, ModuleId, ModuleScope, ModuleSource, ModuleSourceNode,
19 ModuleTree, Problem,
20};
18 21
19pub(crate) fn submodules( 22pub(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};
8use relative_path::RelativePathBuf; 8use relative_path::RelativePathBuf;
9 9
10use crate::FileId; 10use crate::{db::SyntaxDatabase, syntax_ptr::SyntaxPtr, FileId};
11 11
12pub(crate) use self::scope::ModuleScope; 12pub(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)]
15pub(crate) struct ModuleTree { 22pub(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)]
46pub(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.
54enum 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)]
36pub(crate) struct ModuleId(u32); 60pub(crate) struct ModuleId(u32);
37 61
@@ -50,8 +74,8 @@ pub enum Problem {
50} 74}
51 75
52impl ModuleId { 76impl 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)]
112struct ModuleData { 153struct 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
159impl 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)]
119struct LinkData { 188struct 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
3use ra_syntax::{ 3use ra_syntax::{ast, AstNode, SmolStr};
4 ast::{self, ModuleItemOwner},
5 AstNode, File, SmolStr,
6};
7 4
8use crate::syntax_ptr::LocalSyntaxPtr; 5use crate::syntax_ptr::LocalSyntaxPtr;
9 6
@@ -28,11 +25,7 @@ enum EntryKind {
28} 25}
29 26
30impl ModuleScope { 27impl 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)]
103mod tests { 96mod 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 }