aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/descriptors/module/mod.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-11-01 10:53:17 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-11-01 10:53:17 +0000
commitf6f9a0bf35f073e554a340f04e213867732d81a1 (patch)
tree9c9cfc3f6868864d7dd1164aaff6b248f81a402b /crates/ra_analysis/src/descriptors/module/mod.rs
parentd685a9b564fe524865cda5713c527aaeb1ca6b1d (diff)
parentf2b654fd443ce1a0a31a9eaf1a1c25e911d0001a (diff)
Merge #182
182: Module source r=matklad a=matklad Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_analysis/src/descriptors/module/mod.rs')
-rw-r--r--crates/ra_analysis/src/descriptors/module/mod.rs95
1 files changed, 82 insertions, 13 deletions
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,