aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r--crates/ra_analysis/src/db.rs21
-rw-r--r--crates/ra_analysis/src/descriptors.rs108
-rw-r--r--crates/ra_analysis/src/imp.rs207
-rw-r--r--crates/ra_analysis/src/job.rs14
-rw-r--r--crates/ra_analysis/src/lib.rs78
-rw-r--r--crates/ra_analysis/src/module_map.rs13
-rw-r--r--crates/ra_analysis/src/roots.rs63
-rw-r--r--crates/ra_analysis/src/symbol_index.rs29
-rw-r--r--crates/ra_analysis/tests/tests.rs82
9 files changed, 332 insertions, 283 deletions
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs
index c69577233..042dde1ac 100644
--- a/crates/ra_analysis/src/db.rs
+++ b/crates/ra_analysis/src/db.rs
@@ -1,17 +1,18 @@
1use std::{
2 fmt,
3 sync::Arc,
4 hash::{Hash, Hasher},
5};
6use salsa;
7use rustc_hash::FxHashSet;
8use ra_syntax::File;
9use ra_editor::{LineIndex};
10use crate::{ 1use crate::{
2 module_map::{ModuleDescriptorQuery, ModuleTreeQuery, ModulesDatabase},
11 symbol_index::SymbolIndex, 3 symbol_index::SymbolIndex,
12 module_map::{ModulesDatabase, ModuleTreeQuery, ModuleDescriptorQuery},
13 FileId, FileResolverImp, 4 FileId, FileResolverImp,
14}; 5};
6use ra_editor::LineIndex;
7use ra_syntax::File;
8use rustc_hash::FxHashSet;
9use salsa;
10
11use std::{
12 fmt,
13 hash::{Hash, Hasher},
14 sync::Arc,
15};
15 16
16#[derive(Default)] 17#[derive(Default)]
17pub(crate) struct RootDatabase { 18pub(crate) struct RootDatabase {
diff --git a/crates/ra_analysis/src/descriptors.rs b/crates/ra_analysis/src/descriptors.rs
index 8d9f38ca5..6f26f9935 100644
--- a/crates/ra_analysis/src/descriptors.rs
+++ b/crates/ra_analysis/src/descriptors.rs
@@ -1,41 +1,34 @@
1use std::{ 1use crate::{imp::FileResolverImp, FileId};
2 collections::BTreeMap,
3};
4use relative_path::RelativePathBuf;
5use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, AstNode, NameOwner},
4 text_utils::is_subrange,
6 SmolStr, 5 SmolStr,
7 ast::{self, NameOwner, AstNode},
8 text_utils::is_subrange
9};
10use crate::{
11 FileId,
12 imp::FileResolverImp,
13}; 6};
7use relative_path::RelativePathBuf;
8
9use std::collections::BTreeMap;
14 10
15#[derive(Debug, PartialEq, Eq, Hash)] 11#[derive(Debug, PartialEq, Eq, Hash)]
16pub struct ModuleDescriptor { 12pub struct ModuleDescriptor {
17 pub submodules: Vec<Submodule> 13 pub submodules: Vec<Submodule>,
18} 14}
19 15
20impl ModuleDescriptor { 16impl ModuleDescriptor {
21 pub fn new(root: ast::Root) -> ModuleDescriptor { 17 pub fn new(root: ast::Root) -> ModuleDescriptor {
22 let submodules = modules(root) 18 let submodules = modules(root).map(|(name, _)| Submodule { name }).collect();
23 .map(|(name, _)| Submodule { name })
24 .collect();
25 19
26 ModuleDescriptor { submodules } } 20 ModuleDescriptor { submodules }
21 }
27} 22}
28 23
29fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item=(SmolStr, ast::Module<'a>)> { 24fn modules<'a>(root: ast::Root<'a>) -> impl Iterator<Item = (SmolStr, ast::Module<'a>)> {
30 root 25 root.modules().filter_map(|module| {
31 .modules() 26 let name = module.name()?.text();
32 .filter_map(|module| { 27 if !module.has_semi() {
33 let name = module.name()?.text(); 28 return None;
34 if !module.has_semi() { 29 }
35 return None; 30 Some((name, module))
36 } 31 })
37 Some((name, module))
38 })
39} 32}
40 33
41#[derive(Clone, Hash, PartialEq, Eq, Debug)] 34#[derive(Clone, Hash, PartialEq, Eq, Debug)]
@@ -56,7 +49,7 @@ struct Node(usize);
56struct NodeData { 49struct NodeData {
57 file_id: FileId, 50 file_id: FileId,
58 links: Vec<Link>, 51 links: Vec<Link>,
59 parents: Vec<Link> 52 parents: Vec<Link>,
60} 53}
61 54
62#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 55#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
@@ -69,7 +62,6 @@ struct LinkData {
69 problem: Option<Problem>, 62 problem: Option<Problem>,
70} 63}
71 64
72
73#[derive(Clone, Debug, Hash, PartialEq, Eq)] 65#[derive(Clone, Debug, Hash, PartialEq, Eq)]
74pub enum Problem { 66pub enum Problem {
75 UnresolvedModule { 67 UnresolvedModule {
@@ -78,16 +70,18 @@ pub enum Problem {
78 NotDirOwner { 70 NotDirOwner {
79 move_to: RelativePathBuf, 71 move_to: RelativePathBuf,
80 candidate: RelativePathBuf, 72 candidate: RelativePathBuf,
81 } 73 },
82} 74}
83 75
84impl ModuleTreeDescriptor { 76impl ModuleTreeDescriptor {
85 pub(crate) fn new<'a>( 77 pub(crate) fn new<'a>(
86 files: impl Iterator<Item=(FileId, &'a ModuleDescriptor)> + Clone, 78 files: impl Iterator<Item = (FileId, &'a ModuleDescriptor)> + Clone,
87 file_resolver: &FileResolverImp, 79 file_resolver: &FileResolverImp,
88 ) -> ModuleTreeDescriptor { 80 ) -> ModuleTreeDescriptor {
89 let mut file_id2node = BTreeMap::new(); 81 let mut file_id2node = BTreeMap::new();
90 let mut nodes: Vec<NodeData> = files.clone().enumerate() 82 let mut nodes: Vec<NodeData> = files
83 .clone()
84 .enumerate()
91 .map(|(idx, (file_id, _))| { 85 .map(|(idx, (file_id, _))| {
92 file_id2node.insert(file_id, Node(idx)); 86 file_id2node.insert(file_id, Node(idx));
93 NodeData { 87 NodeData {
@@ -120,20 +114,19 @@ impl ModuleTreeDescriptor {
120 points_to, 114 points_to,
121 problem, 115 problem,
122 }) 116 })
123
124 } 117 }
125 } 118 }
126 119
127 ModuleTreeDescriptor { 120 ModuleTreeDescriptor {
128 nodes, links, file_id2node 121 nodes,
122 links,
123 file_id2node,
129 } 124 }
130 } 125 }
131 126
132 pub(crate) fn parent_modules(&self, file_id: FileId) -> Vec<Link> { 127 pub(crate) fn parent_modules(&self, file_id: FileId) -> Vec<Link> {
133 let node = self.file_id2node[&file_id]; 128 let node = self.file_id2node[&file_id];
134 self.node(node) 129 self.node(node).parents.clone()
135 .parents
136 .clone()
137 } 130 }
138 pub(crate) fn child_module_by_name(&self, file_id: FileId, name: &str) -> Vec<FileId> { 131 pub(crate) fn child_module_by_name(&self, file_id: FileId, name: &str) -> Vec<FileId> {
139 let node = self.file_id2node[&file_id]; 132 let node = self.file_id2node[&file_id];
@@ -141,10 +134,18 @@ impl ModuleTreeDescriptor {
141 .links 134 .links
142 .iter() 135 .iter()
143 .filter(|it| it.name(self) == name) 136 .filter(|it| it.name(self) == name)
144 .flat_map(|link| link.points_to(self).iter().map(|&node| self.node(node).file_id)) 137 .flat_map(|link| {
138 link.points_to(self)
139 .iter()
140 .map(|&node| self.node(node).file_id)
141 })
145 .collect() 142 .collect()
146 } 143 }
147 pub(crate) fn problems<'a, 'b>(&'b self, file_id: FileId, root: ast::Root<'a>) -> Vec<(ast::Name<'a>, &'b Problem)> { 144 pub(crate) fn problems<'a, 'b>(
145 &'b self,
146 file_id: FileId,
147 root: ast::Root<'a>,
148 ) -> Vec<(ast::Name<'a>, &'b Problem)> {
148 let node = self.file_id2node[&file_id]; 149 let node = self.file_id2node[&file_id];
149 self.node(node) 150 self.node(node)
150 .links 151 .links
@@ -176,7 +177,11 @@ impl Link {
176 fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] { 177 fn points_to(self, tree: &ModuleTreeDescriptor) -> &[Node] {
177 &tree.link(self).points_to 178 &tree.link(self).points_to
178 } 179 }
179 pub(crate) fn bind_source<'a>(self, tree: &ModuleTreeDescriptor, root: ast::Root<'a>) -> ast::Module<'a> { 180 pub(crate) fn bind_source<'a>(
181 self,
182 tree: &ModuleTreeDescriptor,
183 root: ast::Root<'a>,
184 ) -> ast::Module<'a> {
180 modules(root) 185 modules(root)
181 .filter(|(name, _)| name == &tree.link(self).name) 186 .filter(|(name, _)| name == &tree.link(self).name)
182 .next() 187 .next()
@@ -185,22 +190,21 @@ impl Link {
185 } 190 }
186} 191}
187 192
188
189fn resolve_submodule( 193fn resolve_submodule(
190 file_id: FileId, 194 file_id: FileId,
191 name: &SmolStr, 195 name: &SmolStr,
192 file_resolver: &FileResolverImp 196 file_resolver: &FileResolverImp,
193) -> (Vec<FileId>, Option<Problem>) { 197) -> (Vec<FileId>, Option<Problem>) {
194 let mod_name = file_resolver.file_stem(file_id); 198 let mod_name = file_resolver.file_stem(file_id);
195 let is_dir_owner = 199 let is_dir_owner = mod_name == "mod" || mod_name == "lib" || mod_name == "main";
196 mod_name == "mod" || mod_name == "lib" || mod_name == "main";
197 200
198 let file_mod = RelativePathBuf::from(format!("../{}.rs", name)); 201 let file_mod = RelativePathBuf::from(format!("../{}.rs", name));
199 let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name)); 202 let dir_mod = RelativePathBuf::from(format!("../{}/mod.rs", name));
200 let points_to: Vec<FileId>; 203 let points_to: Vec<FileId>;
201 let problem: Option<Problem>; 204 let problem: Option<Problem>;
202 if is_dir_owner { 205 if is_dir_owner {
203 points_to = [&file_mod, &dir_mod].iter() 206 points_to = [&file_mod, &dir_mod]
207 .iter()
204 .filter_map(|path| file_resolver.resolve(file_id, path)) 208 .filter_map(|path| file_resolver.resolve(file_id, path))
205 .collect(); 209 .collect();
206 problem = if points_to.is_empty() { 210 problem = if points_to.is_empty() {
@@ -223,7 +227,7 @@ fn resolve_submodule(
223#[derive(Debug, Clone)] 227#[derive(Debug, Clone)]
224pub struct FnDescriptor { 228pub struct FnDescriptor {
225 pub name: String, 229 pub name: String,
226 pub label : String, 230 pub label: String,
227 pub ret_type: Option<String>, 231 pub ret_type: Option<String>,
228 pub params: Vec<String>, 232 pub params: Vec<String>,
229} 233}
@@ -233,9 +237,11 @@ impl FnDescriptor {
233 let name = node.name()?.text().to_string(); 237 let name = node.name()?.text().to_string();
234 238
235 // Strip the body out for the label. 239 // Strip the body out for the label.
236 let label : String = if let Some(body) = node.body() { 240 let label: String = if let Some(body) = node.body() {
237 let body_range = body.syntax().range(); 241 let body_range = body.syntax().range();
238 let label : String = node.syntax().children() 242 let label: String = node
243 .syntax()
244 .children()
239 .filter(|child| !is_subrange(body_range, child.range())) 245 .filter(|child| !is_subrange(body_range, child.range()))
240 .map(|node| node.text().to_string()) 246 .map(|node| node.text().to_string())
241 .collect(); 247 .collect();
@@ -251,7 +257,7 @@ impl FnDescriptor {
251 name, 257 name,
252 ret_type, 258 ret_type,
253 params, 259 params,
254 label 260 label,
255 }) 261 })
256 } 262 }
257 263
@@ -264,9 +270,11 @@ impl FnDescriptor {
264 270
265 // Maybe use param.pat here? See if we can just extract the name? 271 // Maybe use param.pat here? See if we can just extract the name?
266 //res.extend(param_list.params().map(|p| p.syntax().text().to_string())); 272 //res.extend(param_list.params().map(|p| p.syntax().text().to_string()));
267 res.extend(param_list.params() 273 res.extend(
268 .filter_map(|p| p.pat()) 274 param_list
269 .map(|pat| pat.syntax().text().to_string()) 275 .params()
276 .filter_map(|p| p.pat())
277 .map(|pat| pat.syntax().text().to_string()),
270 ); 278 );
271 } 279 }
272 res 280 res
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index 5efcaeca0..f1403cb5d 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -1,32 +1,31 @@
1use std::{ 1use std::{
2 sync::{
3 Arc,
4 },
5 hash::{Hash, Hasher},
6 fmt,
7 collections::VecDeque, 2 collections::VecDeque,
3 fmt,
4 hash::{Hash, Hasher},
8 iter, 5 iter,
6 sync::Arc,
9}; 7};
10 8
11use relative_path::RelativePath; 9use ra_editor::{self, find_node_at_offset, resolve_local_name, FileSymbol, LineIndex, LocalEdit};
12use rustc_hash::FxHashSet;
13use ra_editor::{self, FileSymbol, LineIndex, find_node_at_offset, LocalEdit, resolve_local_name};
14use ra_syntax::{ 10use ra_syntax::{
15 TextUnit, TextRange, SmolStr, File, AstNode, SyntaxNodeRef, 11 ast::{self, ArgListOwner, Expr, NameOwner},
12 AstNode, File, SmolStr,
16 SyntaxKind::*, 13 SyntaxKind::*,
17 ast::{self, NameOwner, ArgListOwner, Expr}, 14 SyntaxNodeRef, TextRange, TextUnit,
18}; 15};
16use relative_path::RelativePath;
17use rustc_hash::FxHashSet;
19 18
20use crate::{ 19use crate::{
21 FileId, FileResolver, Query, Diagnostic, SourceChange, SourceFileEdit, Position, FileSystemEdit,
22 JobToken, CrateGraph, CrateId,
23 roots::{SourceRoot, ReadonlySourceRoot, WritableSourceRoot},
24 descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem}, 20 descriptors::{FnDescriptor, ModuleTreeDescriptor, Problem},
21 roots::{ReadonlySourceRoot, SourceRoot, WritableSourceRoot},
22 CrateGraph, CrateId, Diagnostic, FileId, FileResolver, FileSystemEdit, JobToken, Position,
23 Query, SourceChange, SourceFileEdit,
25}; 24};
26 25
27#[derive(Clone, Debug)] 26#[derive(Clone, Debug)]
28pub(crate) struct FileResolverImp { 27pub(crate) struct FileResolverImp {
29 inner: Arc<FileResolver> 28 inner: Arc<FileResolver>,
30} 29}
31 30
32impl PartialEq for FileResolverImp { 31impl PartialEq for FileResolverImp {
@@ -35,8 +34,7 @@ impl PartialEq for FileResolverImp {
35 } 34 }
36} 35}
37 36
38impl Eq for FileResolverImp { 37impl Eq for FileResolverImp {}
39}
40 38
41impl Hash for FileResolverImp { 39impl Hash for FileResolverImp {
42 fn hash<H: Hasher>(&self, hasher: &mut H) { 40 fn hash<H: Hasher>(&self, hasher: &mut H) {
@@ -67,17 +65,23 @@ impl Default for FileResolverImp {
67 fn file_stem(&self, _file_: FileId) -> String { 65 fn file_stem(&self, _file_: FileId) -> String {
68 panic!("file resolver not set") 66 panic!("file resolver not set")
69 } 67 }
70 fn resolve(&self, _file_id: FileId, _path: &::relative_path::RelativePath) -> Option<FileId> { 68 fn resolve(
69 &self,
70 _file_id: FileId,
71 _path: &::relative_path::RelativePath,
72 ) -> Option<FileId> {
71 panic!("file resolver not set") 73 panic!("file resolver not set")
72 } 74 }
73 } 75 }
74 FileResolverImp { inner: Arc::new(DummyResolver) } 76 FileResolverImp {
77 inner: Arc::new(DummyResolver),
78 }
75 } 79 }
76} 80}
77 81
78#[derive(Debug)] 82#[derive(Debug)]
79pub(crate) struct AnalysisHostImpl { 83pub(crate) struct AnalysisHostImpl {
80 data: WorldData 84 data: WorldData,
81} 85}
82 86
83impl AnalysisHostImpl { 87impl AnalysisHostImpl {
@@ -91,13 +95,13 @@ impl AnalysisHostImpl {
91 data: self.data.clone(), 95 data: self.data.clone(),
92 } 96 }
93 } 97 }
94 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item=(FileId, Option<String>)>) { 98 pub fn change_files(&mut self, changes: &mut dyn Iterator<Item = (FileId, Option<String>)>) {
95 self.data_mut() 99 self.data_mut().root.apply_changes(changes, None);
96 .root.apply_changes(changes, None);
97 } 100 }
98 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) { 101 pub fn set_file_resolver(&mut self, resolver: FileResolverImp) {
99 self.data_mut() 102 self.data_mut()
100 .root.apply_changes(&mut iter::empty(), Some(resolver)); 103 .root
104 .apply_changes(&mut iter::empty(), Some(resolver));
101 } 105 }
102 pub fn set_crate_graph(&mut self, graph: CrateGraph) { 106 pub fn set_crate_graph(&mut self, graph: CrateGraph) {
103 let mut visited = FxHashSet::default(); 107 let mut visited = FxHashSet::default();
@@ -131,7 +135,12 @@ impl AnalysisImpl {
131 if self.data.root.contains(file_id) { 135 if self.data.root.contains(file_id) {
132 return &self.data.root; 136 return &self.data.root;
133 } 137 }
134 &**self.data.libs.iter().find(|it| it.contains(file_id)).unwrap() 138 &**self
139 .data
140 .libs
141 .iter()
142 .find(|it| it.contains(file_id))
143 .unwrap()
135 } 144 }
136 pub fn file_syntax(&self, file_id: FileId) -> File { 145 pub fn file_syntax(&self, file_id: FileId) -> File {
137 self.root(file_id).syntax(file_id) 146 self.root(file_id).syntax(file_id)
@@ -142,18 +151,17 @@ impl AnalysisImpl {
142 pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 151 pub fn world_symbols(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
143 let mut buf = Vec::new(); 152 let mut buf = Vec::new();
144 if query.libs { 153 if query.libs {
145 self.data.libs.iter() 154 self.data.libs.iter().for_each(|it| it.symbols(&mut buf));
146 .for_each(|it| it.symbols(&mut buf));
147 } else { 155 } else {
148 self.data.root.symbols(&mut buf); 156 self.data.root.symbols(&mut buf);
149 } 157 }
150 query.search(&buf, token) 158 query.search(&buf, token)
151
152 } 159 }
153 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { 160 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
154 let root = self.root(file_id); 161 let root = self.root(file_id);
155 let module_tree = root.module_tree(); 162 let module_tree = root.module_tree();
156 module_tree.parent_modules(file_id) 163 module_tree
164 .parent_modules(file_id)
157 .iter() 165 .iter()
158 .map(|link| { 166 .map(|link| {
159 let file_id = link.owner(&module_tree); 167 let file_id = link.owner(&module_tree);
@@ -203,15 +211,17 @@ impl AnalysisImpl {
203 let file = root.syntax(file_id); 211 let file = root.syntax(file_id);
204 let syntax = file.syntax(); 212 let syntax = file.syntax();
205 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) { 213 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, offset) {
206
207 // First try to resolve the symbol locally 214 // First try to resolve the symbol locally
208 if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) { 215 if let Some((name, range)) = resolve_local_name(&file, offset, name_ref) {
209 let mut vec = vec![]; 216 let mut vec = vec![];
210 vec.push((file_id, FileSymbol { 217 vec.push((
211 name, 218 file_id,
212 node_range: range, 219 FileSymbol {
213 kind : NAME 220 name,
214 })); 221 node_range: range,
222 kind: NAME,
223 },
224 ));
215 225
216 return vec; 226 return vec;
217 } else { 227 } else {
@@ -224,17 +234,21 @@ impl AnalysisImpl {
224 if module.has_semi() { 234 if module.has_semi() {
225 let file_ids = self.resolve_module(&*module_tree, file_id, module); 235 let file_ids = self.resolve_module(&*module_tree, file_id, module);
226 236
227 let res = file_ids.into_iter().map(|id| { 237 let res = file_ids
228 let name = module.name() 238 .into_iter()
229 .map(|n| n.text()) 239 .map(|id| {
230 .unwrap_or_else(|| SmolStr::new("")); 240 let name = module
231 let symbol = FileSymbol { 241 .name()
232 name, 242 .map(|n| n.text())
233 node_range: TextRange::offset_len(0.into(), 0.into()), 243 .unwrap_or_else(|| SmolStr::new(""));
234 kind: MODULE, 244 let symbol = FileSymbol {
235 }; 245 name,
236 (id, symbol) 246 node_range: TextRange::offset_len(0.into(), 0.into()),
237 }).collect(); 247 kind: MODULE,
248 };
249 (id, symbol)
250 })
251 .collect();
238 252
239 return res; 253 return res;
240 } 254 }
@@ -245,12 +259,16 @@ impl AnalysisImpl {
245 259
246 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { 260 pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> {
247 let root = self.root(file_id); 261 let root = self.root(file_id);
248 let module_tree = root.module_tree(); 262 let module_tree = root.module_tree();
249 let syntax = root.syntax(file_id); 263 let syntax = root.syntax(file_id);
250 264
251 let mut res = ra_editor::diagnostics(&syntax) 265 let mut res = ra_editor::diagnostics(&syntax)
252 .into_iter() 266 .into_iter()
253 .map(|d| Diagnostic { range: d.range, message: d.msg, fix: None }) 267 .map(|d| Diagnostic {
268 range: d.range,
269 message: d.msg,
270 fix: None,
271 })
254 .collect::<Vec<_>>(); 272 .collect::<Vec<_>>();
255 273
256 for (name_node, problem) in module_tree.problems(file_id, syntax.ast()) { 274 for (name_node, problem) in module_tree.problems(file_id, syntax.ast()) {
@@ -273,8 +291,14 @@ impl AnalysisImpl {
273 } 291 }
274 } 292 }
275 Problem::NotDirOwner { move_to, candidate } => { 293 Problem::NotDirOwner { move_to, candidate } => {
276 let move_file = FileSystemEdit::MoveFile { file: file_id, path: move_to.clone() }; 294 let move_file = FileSystemEdit::MoveFile {
277 let create_file = FileSystemEdit::CreateFile { anchor: file_id, path: move_to.join(candidate) }; 295 file: file_id,
296 path: move_to.clone(),
297 };
298 let create_file = FileSystemEdit::CreateFile {
299 anchor: file_id,
300 path: move_to.join(candidate),
301 };
278 let fix = SourceChange { 302 let fix = SourceChange {
279 label: "move file and create module".to_string(), 303 label: "move file and create module".to_string(),
280 source_file_edits: Vec::new(), 304 source_file_edits: Vec::new(),
@@ -297,23 +321,34 @@ impl AnalysisImpl {
297 let file = self.file_syntax(file_id); 321 let file = self.file_syntax(file_id);
298 let offset = range.start(); 322 let offset = range.start();
299 let actions = vec![ 323 let actions = vec![
300 ("flip comma", ra_editor::flip_comma(&file, offset).map(|f| f())), 324 (
301 ("add `#[derive]`", ra_editor::add_derive(&file, offset).map(|f| f())), 325 "flip comma",
326 ra_editor::flip_comma(&file, offset).map(|f| f()),
327 ),
328 (
329 "add `#[derive]`",
330 ra_editor::add_derive(&file, offset).map(|f| f()),
331 ),
302 ("add impl", ra_editor::add_impl(&file, offset).map(|f| f())), 332 ("add impl", ra_editor::add_impl(&file, offset).map(|f| f())),
303 ("introduce variable", ra_editor::introduce_variable(&file, range).map(|f| f())), 333 (
334 "introduce variable",
335 ra_editor::introduce_variable(&file, range).map(|f| f()),
336 ),
304 ]; 337 ];
305 actions.into_iter() 338 actions
339 .into_iter()
306 .filter_map(|(name, local_edit)| { 340 .filter_map(|(name, local_edit)| {
307 Some(SourceChange::from_local_edit( 341 Some(SourceChange::from_local_edit(file_id, name, local_edit?))
308 file_id, name, local_edit?,
309 ))
310 }) 342 })
311 .collect() 343 .collect()
312 } 344 }
313 345
314 pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken) 346 pub fn resolve_callable(
315 -> Option<(FnDescriptor, Option<usize>)> { 347 &self,
316 348 file_id: FileId,
349 offset: TextUnit,
350 token: &JobToken,
351 ) -> Option<(FnDescriptor, Option<usize>)> {
317 let root = self.root(file_id); 352 let root = self.root(file_id);
318 let file = root.syntax(file_id); 353 let file = root.syntax(file_id);
319 let syntax = file.syntax(); 354 let syntax = file.syntax();
@@ -332,9 +367,7 @@ impl AnalysisImpl {
332 let mut current_parameter = None; 367 let mut current_parameter = None;
333 368
334 let num_params = descriptor.params.len(); 369 let num_params = descriptor.params.len();
335 let has_self = fn_def.param_list() 370 let has_self = fn_def.param_list().and_then(|l| l.self_param()).is_some();
336 .and_then(|l| l.self_param())
337 .is_some();
338 371
339 if num_params == 1 { 372 if num_params == 1 {
340 if !has_self { 373 if !has_self {
@@ -350,8 +383,11 @@ impl AnalysisImpl {
350 let start = arg_list.syntax().range().start(); 383 let start = arg_list.syntax().range().start();
351 384
352 let range_search = TextRange::from_to(start, offset); 385 let range_search = TextRange::from_to(start, offset);
353 let mut commas: usize = arg_list.syntax().text() 386 let mut commas: usize = arg_list
354 .slice(range_search).to_string() 387 .syntax()
388 .text()
389 .slice(range_search)
390 .to_string()
355 .matches(",") 391 .matches(",")
356 .count(); 392 .count();
357 393
@@ -381,7 +417,12 @@ impl AnalysisImpl {
381 self.world_symbols(query, token) 417 self.world_symbols(query, token)
382 } 418 }
383 419
384 fn resolve_module(&self, module_tree: &ModuleTreeDescriptor, file_id: FileId, module: ast::Module) -> Vec<FileId> { 420 fn resolve_module(
421 &self,
422 module_tree: &ModuleTreeDescriptor,
423 file_id: FileId,
424 module: ast::Module,
425 ) -> Vec<FileId> {
385 let name = match module.name() { 426 let name = match module.name() {
386 Some(name) => name.text(), 427 Some(name) => name.text(),
387 None => return Vec::new(), 428 None => return Vec::new(),
@@ -407,15 +448,17 @@ impl SourceChange {
407 label: label.to_string(), 448 label: label.to_string(),
408 source_file_edits: vec![file_edit], 449 source_file_edits: vec![file_edit],
409 file_system_edits: vec![], 450 file_system_edits: vec![],
410 cursor_position: edit.cursor_position 451 cursor_position: edit
411 .map(|offset| Position { offset, file_id }) 452 .cursor_position
453 .map(|offset| Position { offset, file_id }),
412 } 454 }
413 } 455 }
414} 456}
415 457
416impl CrateGraph { 458impl CrateGraph {
417 fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> { 459 fn crate_id_for_crate_root(&self, file_id: FileId) -> Option<CrateId> {
418 let (&crate_id, _) = self.crate_roots 460 let (&crate_id, _) = self
461 .crate_roots
419 .iter() 462 .iter()
420 .find(|(_crate_id, &root_id)| root_id == file_id)?; 463 .find(|(_crate_id, &root_id)| root_id == file_id)?;
421 Some(crate_id) 464 Some(crate_id)
@@ -424,7 +467,7 @@ impl CrateGraph {
424 467
425enum FnCallNode<'a> { 468enum FnCallNode<'a> {
426 CallExpr(ast::CallExpr<'a>), 469 CallExpr(ast::CallExpr<'a>),
427 MethodCallExpr(ast::MethodCallExpr<'a>) 470 MethodCallExpr(ast::MethodCallExpr<'a>),
428} 471}
429 472
430impl<'a> FnCallNode<'a> { 473impl<'a> FnCallNode<'a> {
@@ -440,27 +483,23 @@ impl<'a> FnCallNode<'a> {
440 483
441 pub fn name_ref(&self) -> Option<ast::NameRef> { 484 pub fn name_ref(&self) -> Option<ast::NameRef> {
442 match *self { 485 match *self {
443 FnCallNode::CallExpr(call_expr) => { 486 FnCallNode::CallExpr(call_expr) => Some(match call_expr.expr()? {
444 Some(match call_expr.expr()? { 487 Expr::PathExpr(path_expr) => path_expr.path()?.segment()?.name_ref()?,
445 Expr::PathExpr(path_expr) => { 488 _ => return None,
446 path_expr.path()?.segment()?.name_ref()? 489 }),
447 }, 490
448 _ => return None 491 FnCallNode::MethodCallExpr(call_expr) => call_expr
449 }) 492 .syntax()
450 }, 493 .children()
451 494 .filter_map(ast::NameRef::cast)
452 FnCallNode::MethodCallExpr(call_expr) => { 495 .nth(0),
453 call_expr.syntax().children()
454 .filter_map(ast::NameRef::cast)
455 .nth(0)
456 }
457 } 496 }
458 } 497 }
459 498
460 pub fn arg_list(&self) -> Option<ast::ArgList> { 499 pub fn arg_list(&self) -> Option<ast::ArgList> {
461 match *self { 500 match *self {
462 FnCallNode::CallExpr(expr) => expr.arg_list(), 501 FnCallNode::CallExpr(expr) => expr.arg_list(),
463 FnCallNode::MethodCallExpr(expr) => expr.arg_list() 502 FnCallNode::MethodCallExpr(expr) => expr.arg_list(),
464 } 503 }
465 } 504 }
466} 505}
diff --git a/crates/ra_analysis/src/job.rs b/crates/ra_analysis/src/job.rs
index ea1652a26..2871f9839 100644
--- a/crates/ra_analysis/src/job.rs
+++ b/crates/ra_analysis/src/job.rs
@@ -14,15 +14,20 @@ impl JobHandle {
14 pub fn new() -> (JobHandle, JobToken) { 14 pub fn new() -> (JobHandle, JobToken) {
15 let (sender_alive, receiver_alive) = bounded(0); 15 let (sender_alive, receiver_alive) = bounded(0);
16 let (sender_canceled, receiver_canceled) = bounded(0); 16 let (sender_canceled, receiver_canceled) = bounded(0);
17 let token = JobToken { _job_alive: sender_alive, job_canceled: receiver_canceled }; 17 let token = JobToken {
18 let handle = JobHandle { job_alive: receiver_alive, _job_canceled: sender_canceled }; 18 _job_alive: sender_alive,
19 job_canceled: receiver_canceled,
20 };
21 let handle = JobHandle {
22 job_alive: receiver_alive,
23 _job_canceled: sender_canceled,
24 };
19 (handle, token) 25 (handle, token)
20 } 26 }
21 pub fn has_completed(&self) -> bool { 27 pub fn has_completed(&self) -> bool {
22 is_closed(&self.job_alive) 28 is_closed(&self.job_alive)
23 } 29 }
24 pub fn cancel(self) { 30 pub fn cancel(self) {}
25 }
26} 31}
27 32
28impl JobToken { 33impl JobToken {
@@ -31,7 +36,6 @@ impl JobToken {
31 } 36 }
32} 37}
33 38
34
35// We don't actually send messages through the channels, 39// We don't actually send messages through the channels,
36// and instead just check if the channel is closed, 40// and instead just check if the channel is closed,
37// so we use uninhabited enum as a message type 41// so we use uninhabited enum as a message type
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index d8b355a81..2eeacaabe 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -1,44 +1,40 @@
1extern crate parking_lot; 1extern crate parking_lot;
2#[macro_use] 2#[macro_use]
3extern crate log; 3extern crate log;
4extern crate fst;
4extern crate once_cell; 5extern crate once_cell;
5extern crate ra_syntax;
6extern crate ra_editor; 6extern crate ra_editor;
7extern crate fst; 7extern crate ra_syntax;
8extern crate rayon; 8extern crate rayon;
9extern crate relative_path; 9extern crate relative_path;
10#[macro_use] 10#[macro_use]
11extern crate crossbeam_channel; 11extern crate crossbeam_channel;
12extern crate im; 12extern crate im;
13extern crate salsa;
14extern crate rustc_hash; 13extern crate rustc_hash;
14extern crate salsa;
15 15
16mod symbol_index; 16mod db;
17mod module_map; 17mod descriptors;
18mod imp; 18mod imp;
19mod job; 19mod job;
20mod module_map;
20mod roots; 21mod roots;
21mod db; 22mod symbol_index;
22mod descriptors;
23 23
24use std::{ 24use std::{fmt::Debug, sync::Arc};
25 sync::Arc,
26 fmt::Debug,
27};
28 25
26use crate::imp::{AnalysisHostImpl, AnalysisImpl, FileResolverImp};
27use ra_syntax::{AtomEdit, File, TextRange, TextUnit};
29use relative_path::{RelativePath, RelativePathBuf}; 28use relative_path::{RelativePath, RelativePathBuf};
30use ra_syntax::{File, TextRange, TextUnit, AtomEdit};
31use rustc_hash::FxHashMap; 29use rustc_hash::FxHashMap;
32use crate::imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp};
33 30
34pub use ra_editor::{
35 StructureNode, LineIndex, FileSymbol,
36 Runnable, RunnableKind, HighlightedRange, CompletionItem,
37 Fold, FoldKind
38};
39pub use crate::{ 31pub use crate::{
40 job::{JobToken, JobHandle},
41 descriptors::FnDescriptor, 32 descriptors::FnDescriptor,
33 job::{JobHandle, JobToken},
34};
35pub use ra_editor::{
36 CompletionItem, FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, Runnable,
37 RunnableKind, StructureNode,
42}; 38};
43 39
44#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 40#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -59,20 +55,24 @@ pub trait FileResolver: Debug + Send + Sync + 'static {
59 55
60#[derive(Debug)] 56#[derive(Debug)]
61pub struct AnalysisHost { 57pub struct AnalysisHost {
62 imp: AnalysisHostImpl 58 imp: AnalysisHostImpl,
63} 59}
64 60
65impl AnalysisHost { 61impl AnalysisHost {
66 pub fn new() -> AnalysisHost { 62 pub fn new() -> AnalysisHost {
67 AnalysisHost { imp: AnalysisHostImpl::new() } 63 AnalysisHost {
64 imp: AnalysisHostImpl::new(),
65 }
68 } 66 }
69 pub fn analysis(&self) -> Analysis { 67 pub fn analysis(&self) -> Analysis {
70 Analysis { imp: self.imp.analysis() } 68 Analysis {
69 imp: self.imp.analysis(),
70 }
71 } 71 }
72 pub fn change_file(&mut self, file_id: FileId, text: Option<String>) { 72 pub fn change_file(&mut self, file_id: FileId, text: Option<String>) {
73 self.change_files(::std::iter::once((file_id, text))); 73 self.change_files(::std::iter::once((file_id, text)));
74 } 74 }
75 pub fn change_files(&mut self, mut changes: impl Iterator<Item=(FileId, Option<String>)>) { 75 pub fn change_files(&mut self, mut changes: impl Iterator<Item = (FileId, Option<String>)>) {
76 self.imp.change_files(&mut changes) 76 self.imp.change_files(&mut changes)
77 } 77 }
78 pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) { 78 pub fn set_file_resolver(&mut self, resolver: Arc<FileResolver>) {
@@ -115,7 +115,7 @@ pub enum FileSystemEdit {
115 MoveFile { 115 MoveFile {
116 file: FileId, 116 file: FileId,
117 path: RelativePathBuf, 117 path: RelativePathBuf,
118 } 118 },
119} 119}
120 120
121#[derive(Debug)] 121#[derive(Debug)]
@@ -144,7 +144,7 @@ impl Query {
144 only_types: false, 144 only_types: false,
145 libs: false, 145 libs: false,
146 exact: false, 146 exact: false,
147 limit: usize::max_value() 147 limit: usize::max_value(),
148 } 148 }
149 } 149 }
150 pub fn only_types(&mut self) { 150 pub fn only_types(&mut self) {
@@ -163,7 +163,7 @@ impl Query {
163 163
164#[derive(Debug)] 164#[derive(Debug)]
165pub struct Analysis { 165pub struct Analysis {
166 imp: AnalysisImpl 166 imp: AnalysisImpl,
167} 167}
168 168
169impl Analysis { 169impl Analysis {
@@ -195,7 +195,11 @@ impl Analysis {
195 } 195 }
196 pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> { 196 pub fn on_eq_typed(&self, file_id: FileId, offset: TextUnit) -> Option<SourceChange> {
197 let file = self.imp.file_syntax(file_id); 197 let file = self.imp.file_syntax(file_id);
198 Some(SourceChange::from_local_edit(file_id, "add semicolon", ra_editor::on_eq_typed(&file, offset)?)) 198 Some(SourceChange::from_local_edit(
199 file_id,
200 "add semicolon",
201 ra_editor::on_eq_typed(&file, offset)?,
202 ))
199 } 203 }
200 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { 204 pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> {
201 let file = self.imp.file_syntax(file_id); 205 let file = self.imp.file_syntax(file_id);
@@ -204,8 +208,14 @@ impl Analysis {
204 pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 208 pub fn symbol_search(&self, query: Query, token: &JobToken) -> Vec<(FileId, FileSymbol)> {
205 self.imp.world_symbols(query, token) 209 self.imp.world_symbols(query, token)
206 } 210 }
207 pub fn approximately_resolve_symbol(&self, file_id: FileId, offset: TextUnit, token: &JobToken) -> Vec<(FileId, FileSymbol)> { 211 pub fn approximately_resolve_symbol(
208 self.imp.approximately_resolve_symbol(file_id, offset, token) 212 &self,
213 file_id: FileId,
214 offset: TextUnit,
215 token: &JobToken,
216 ) -> Vec<(FileId, FileSymbol)> {
217 self.imp
218 .approximately_resolve_symbol(file_id, offset, token)
209 } 219 }
210 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> { 220 pub fn parent_module(&self, file_id: FileId) -> Vec<(FileId, FileSymbol)> {
211 self.imp.parent_module(file_id) 221 self.imp.parent_module(file_id)
@@ -239,15 +249,19 @@ impl Analysis {
239 ra_editor::folding_ranges(&file) 249 ra_editor::folding_ranges(&file)
240 } 250 }
241 251
242 pub fn resolve_callable(&self, file_id: FileId, offset: TextUnit, token: &JobToken) 252 pub fn resolve_callable(
243 -> Option<(FnDescriptor, Option<usize>)> { 253 &self,
254 file_id: FileId,
255 offset: TextUnit,
256 token: &JobToken,
257 ) -> Option<(FnDescriptor, Option<usize>)> {
244 self.imp.resolve_callable(file_id, offset, token) 258 self.imp.resolve_callable(file_id, offset, token)
245 } 259 }
246} 260}
247 261
248#[derive(Debug)] 262#[derive(Debug)]
249pub struct LibraryData { 263pub struct LibraryData {
250 root: roots::ReadonlySourceRoot 264 root: roots::ReadonlySourceRoot,
251} 265}
252 266
253impl LibraryData { 267impl LibraryData {
diff --git a/crates/ra_analysis/src/module_map.rs b/crates/ra_analysis/src/module_map.rs
index c1799e3d4..ff0ec3cc7 100644
--- a/crates/ra_analysis/src/module_map.rs
+++ b/crates/ra_analysis/src/module_map.rs
@@ -1,10 +1,11 @@
1use std::sync::Arc;
2use crate::{ 1use crate::{
3 FileId, 2 db::SyntaxDatabase,
4 db::{SyntaxDatabase},
5 descriptors::{ModuleDescriptor, ModuleTreeDescriptor}, 3 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
4 FileId,
6}; 5};
7 6
7use std::sync::Arc;
8
8salsa::query_group! { 9salsa::query_group! {
9 pub(crate) trait ModulesDatabase: SyntaxDatabase { 10 pub(crate) trait ModulesDatabase: SyntaxDatabase {
10 fn module_tree(key: ()) -> Arc<ModuleTreeDescriptor> { 11 fn module_tree(key: ()) -> Arc<ModuleTreeDescriptor> {
@@ -16,7 +17,6 @@ salsa::query_group! {
16 } 17 }
17} 18}
18 19
19
20fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> { 20fn module_descriptor(db: &impl ModulesDatabase, file_id: FileId) -> Arc<ModuleDescriptor> {
21 let file = db.file_syntax(file_id); 21 let file = db.file_syntax(file_id);
22 Arc::new(ModuleDescriptor::new(file.ast())) 22 Arc::new(ModuleDescriptor::new(file.ast()))
@@ -29,6 +29,9 @@ fn module_tree(db: &impl ModulesDatabase, (): ()) -> Arc<ModuleTreeDescriptor> {
29 let module_descr = db.module_descriptor(file_id); 29 let module_descr = db.module_descriptor(file_id);
30 files.push((file_id, module_descr)); 30 files.push((file_id, module_descr));
31 } 31 }
32 let res = ModuleTreeDescriptor::new(files.iter().map(|(file_id, descr)| (*file_id, &**descr)), &file_set.resolver); 32 let res = ModuleTreeDescriptor::new(
33 files.iter().map(|(file_id, descr)| (*file_id, &**descr)),
34 &file_set.resolver,
35 );
33 Arc::new(res) 36 Arc::new(res)
34} 37}
diff --git a/crates/ra_analysis/src/roots.rs b/crates/ra_analysis/src/roots.rs
index 76bcecd38..1f2b21b27 100644
--- a/crates/ra_analysis/src/roots.rs
+++ b/crates/ra_analysis/src/roots.rs
@@ -1,22 +1,19 @@
1use std::{ 1use std::{panic, sync::Arc};
2 sync::Arc,
3 panic,
4};
5 2
6use once_cell::sync::OnceCell; 3use once_cell::sync::OnceCell;
7use rayon::prelude::*;
8use salsa::Database;
9use rustc_hash::{FxHashMap, FxHashSet};
10use ra_editor::LineIndex; 4use ra_editor::LineIndex;
11use ra_syntax::File; 5use ra_syntax::File;
6use rayon::prelude::*;
7use rustc_hash::{FxHashMap, FxHashSet};
8use salsa::Database;
12 9
13use crate::{ 10use crate::{
14 FileId,
15 imp::FileResolverImp,
16 symbol_index::SymbolIndex,
17 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
18 db::{self, FilesDatabase, SyntaxDatabase}, 11 db::{self, FilesDatabase, SyntaxDatabase},
12 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
13 imp::FileResolverImp,
19 module_map::ModulesDatabase, 14 module_map::ModulesDatabase,
15 symbol_index::SymbolIndex,
16 FileId,
20}; 17};
21 18
22pub(crate) trait SourceRoot { 19pub(crate) trait SourceRoot {
@@ -35,7 +32,7 @@ pub(crate) struct WritableSourceRoot {
35impl WritableSourceRoot { 32impl WritableSourceRoot {
36 pub fn apply_changes( 33 pub fn apply_changes(
37 &mut self, 34 &mut self,
38 changes: &mut dyn Iterator<Item=(FileId, Option<String>)>, 35 changes: &mut dyn Iterator<Item = (FileId, Option<String>)>,
39 file_resolver: Option<FileResolverImp>, 36 file_resolver: Option<FileResolverImp>,
40 ) { 37 ) {
41 let mut changed = FxHashSet::default(); 38 let mut changed = FxHashSet::default();
@@ -46,22 +43,22 @@ impl WritableSourceRoot {
46 removed.insert(file_id); 43 removed.insert(file_id);
47 } 44 }
48 Some(text) => { 45 Some(text) => {
49 self.db.query(db::FileTextQuery) 46 self.db
47 .query(db::FileTextQuery)
50 .set(file_id, Arc::new(text)); 48 .set(file_id, Arc::new(text));
51 changed.insert(file_id); 49 changed.insert(file_id);
52 } 50 }
53 } 51 }
54 } 52 }
55 let file_set = self.db.file_set(()); 53 let file_set = self.db.file_set(());
56 let mut files: FxHashSet<FileId> = file_set 54 let mut files: FxHashSet<FileId> = file_set.files.clone();
57 .files
58 .clone();
59 for file_id in removed { 55 for file_id in removed {
60 files.remove(&file_id); 56 files.remove(&file_id);
61 } 57 }
62 files.extend(changed); 58 files.extend(changed);
63 let resolver = file_resolver.unwrap_or_else(|| file_set.resolver.clone()); 59 let resolver = file_resolver.unwrap_or_else(|| file_set.resolver.clone());
64 self.db.query(db::FileSetQuery) 60 self.db
61 .query(db::FileSetQuery)
65 .set((), Arc::new(db::FileSet { files, resolver })); 62 .set((), Arc::new(db::FileSet { files, resolver }));
66 } 63 }
67} 64}
@@ -71,9 +68,7 @@ impl SourceRoot for WritableSourceRoot {
71 self.db.module_tree(()) 68 self.db.module_tree(())
72 } 69 }
73 fn contains(&self, file_id: FileId) -> bool { 70 fn contains(&self, file_id: FileId) -> bool {
74 self.db.file_set(()) 71 self.db.file_set(()).files.contains(&file_id)
75 .files
76 .contains(&file_id)
77 } 72 }
78 fn lines(&self, file_id: FileId) -> Arc<LineIndex> { 73 fn lines(&self, file_id: FileId) -> Arc<LineIndex> {
79 self.db.file_lines(file_id) 74 self.db.file_lines(file_id)
@@ -83,7 +78,7 @@ impl SourceRoot for WritableSourceRoot {
83 } 78 }
84 fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) { 79 fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) {
85 let db = &self.db; 80 let db = &self.db;
86 let symbols = db.file_set(()); 81 let symbols = db.file_set(());
87 let symbols = symbols 82 let symbols = symbols
88 .files 83 .files
89 .iter() 84 .iter()
@@ -108,12 +103,15 @@ impl FileData {
108 } 103 }
109 } 104 }
110 fn lines(&self) -> &Arc<LineIndex> { 105 fn lines(&self) -> &Arc<LineIndex> {
111 self.lines.get_or_init(|| Arc::new(LineIndex::new(&self.text))) 106 self.lines
107 .get_or_init(|| Arc::new(LineIndex::new(&self.text)))
112 } 108 }
113 fn syntax(&self) -> &File { 109 fn syntax(&self) -> &File {
114 let text = &self.text; 110 let text = &self.text;
115 let syntax = &self.syntax; 111 let syntax = &self.syntax;
116 match panic::catch_unwind(panic::AssertUnwindSafe(|| syntax.get_or_init(|| File::parse(text)))) { 112 match panic::catch_unwind(panic::AssertUnwindSafe(|| {
113 syntax.get_or_init(|| File::parse(text))
114 })) {
117 Ok(file) => file, 115 Ok(file) => file,
118 Err(err) => { 116 Err(err) => {
119 error!("Parser paniced on:\n------\n{}\n------\n", text); 117 error!("Parser paniced on:\n------\n{}\n------\n", text);
@@ -131,22 +129,23 @@ pub(crate) struct ReadonlySourceRoot {
131} 129}
132 130
133impl ReadonlySourceRoot { 131impl ReadonlySourceRoot {
134 pub(crate) fn new(files: Vec<(FileId, String)>, file_resolver: FileResolverImp) -> ReadonlySourceRoot { 132 pub(crate) fn new(
135 let modules = files.par_iter() 133 files: Vec<(FileId, String)>,
134 file_resolver: FileResolverImp,
135 ) -> ReadonlySourceRoot {
136 let modules = files
137 .par_iter()
136 .map(|(file_id, text)| { 138 .map(|(file_id, text)| {
137 let syntax = File::parse(text); 139 let syntax = File::parse(text);
138 let mod_descr = ModuleDescriptor::new(syntax.ast()); 140 let mod_descr = ModuleDescriptor::new(syntax.ast());
139 (*file_id, syntax, mod_descr) 141 (*file_id, syntax, mod_descr)
140 }) 142 })
141 .collect::<Vec<_>>(); 143 .collect::<Vec<_>>();
142 let module_tree = ModuleTreeDescriptor::new( 144 let module_tree =
143 modules.iter().map(|it| (it.0, &it.2)), 145 ModuleTreeDescriptor::new(modules.iter().map(|it| (it.0, &it.2)), &file_resolver);
144 &file_resolver,
145 );
146 146
147 let symbol_index = SymbolIndex::for_files( 147 let symbol_index =
148 modules.par_iter().map(|it| (it.0, it.1.clone())) 148 SymbolIndex::for_files(modules.par_iter().map(|it| (it.0, it.1.clone())));
149 );
150 let file_map: FxHashMap<FileId, FileData> = files 149 let file_map: FxHashMap<FileId, FileData> = files
151 .into_iter() 150 .into_iter()
152 .map(|(id, text)| (id, FileData::new(text))) 151 .map(|(id, text)| (id, FileData::new(text)))
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index 54672fde4..51eef8170 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -1,15 +1,16 @@
1use std::{ 1use crate::{FileId, JobToken, Query};
2 sync::Arc, 2use fst::{self, Streamer};
3 hash::{Hash, Hasher}, 3use ra_editor::{file_symbols, FileSymbol};
4};
5use ra_editor::{FileSymbol, file_symbols};
6use ra_syntax::{ 4use ra_syntax::{
7 File, 5 File,
8 SyntaxKind::{self, *}, 6 SyntaxKind::{self, *},
9}; 7};
10use fst::{self, Streamer};
11use rayon::prelude::*; 8use rayon::prelude::*;
12use crate::{Query, FileId, JobToken}; 9
10use std::{
11 hash::{Hash, Hasher},
12 sync::Arc,
13};
13 14
14#[derive(Debug)] 15#[derive(Debug)]
15pub(crate) struct SymbolIndex { 16pub(crate) struct SymbolIndex {
@@ -23,8 +24,7 @@ impl PartialEq for SymbolIndex {
23 } 24 }
24} 25}
25 26
26impl Eq for SymbolIndex { 27impl Eq for SymbolIndex {}
27}
28 28
29impl Hash for SymbolIndex { 29impl Hash for SymbolIndex {
30 fn hash<H: Hasher>(&self, hasher: &mut H) { 30 fn hash<H: Hasher>(&self, hasher: &mut H) {
@@ -33,14 +33,12 @@ impl Hash for SymbolIndex {
33} 33}
34 34
35impl SymbolIndex { 35impl SymbolIndex {
36 pub(crate) fn for_files(files: impl ParallelIterator<Item=(FileId, File)>) -> SymbolIndex { 36 pub(crate) fn for_files(files: impl ParallelIterator<Item = (FileId, File)>) -> SymbolIndex {
37 let mut symbols = files 37 let mut symbols = files
38 .flat_map(|(file_id, file)| { 38 .flat_map(|(file_id, file)| {
39 file_symbols(&file) 39 file_symbols(&file)
40 .into_iter() 40 .into_iter()
41 .map(move |symbol| { 41 .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol)))
42 (symbol.name.as_str().to_lowercase(), (file_id, symbol))
43 })
44 .collect::<Vec<_>>() 42 .collect::<Vec<_>>()
45 }) 43 })
46 .collect::<Vec<_>>(); 44 .collect::<Vec<_>>();
@@ -48,9 +46,7 @@ impl SymbolIndex {
48 symbols.dedup_by(|s1, s2| s1.0 == s2.0); 46 symbols.dedup_by(|s1, s2| s1.0 == s2.0);
49 let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = 47 let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) =
50 symbols.into_iter().unzip(); 48 symbols.into_iter().unzip();
51 let map = fst::Map::from_iter( 49 let map = fst::Map::from_iter(names.into_iter().zip(0u64..)).unwrap();
52 names.into_iter().zip(0u64..)
53 ).unwrap();
54 SymbolIndex { symbols, map } 50 SymbolIndex { symbols, map }
55 } 51 }
56 52
@@ -65,7 +61,6 @@ impl Query {
65 indices: &[Arc<SymbolIndex>], 61 indices: &[Arc<SymbolIndex>],
66 token: &JobToken, 62 token: &JobToken,
67 ) -> Vec<(FileId, FileSymbol)> { 63 ) -> Vec<(FileId, FileSymbol)> {
68
69 let mut op = fst::map::OpBuilder::new(); 64 let mut op = fst::map::OpBuilder::new();
70 for file_symbols in indices.iter() { 65 for file_symbols in indices.iter() {
71 let automaton = fst::automaton::Subsequence::new(&self.lowercased); 66 let automaton = fst::automaton::Subsequence::new(&self.lowercased);
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs
index 2d3679fa9..e0c637d65 100644
--- a/crates/ra_analysis/tests/tests.rs
+++ b/crates/ra_analysis/tests/tests.rs
@@ -1,32 +1,31 @@
1extern crate relative_path;
2extern crate ra_analysis; 1extern crate ra_analysis;
3extern crate rustc_hash;
4extern crate ra_editor; 2extern crate ra_editor;
5extern crate ra_syntax; 3extern crate ra_syntax;
4extern crate relative_path;
5extern crate rustc_hash;
6extern crate test_utils; 6extern crate test_utils;
7 7
8use std::{ 8use std::sync::Arc;
9 sync::Arc,
10};
11 9
12use rustc_hash::FxHashMap; 10use ra_analysis::{
11 Analysis, AnalysisHost, CrateGraph, CrateId, FileId, FileResolver, FnDescriptor, JobHandle,
12};
13use relative_path::{RelativePath, RelativePathBuf}; 13use relative_path::{RelativePath, RelativePathBuf};
14use ra_analysis::{Analysis, AnalysisHost, FileId, FileResolver, JobHandle, CrateGraph, CrateId, FnDescriptor}; 14use rustc_hash::FxHashMap;
15use test_utils::{assert_eq_dbg, extract_offset}; 15use test_utils::{assert_eq_dbg, extract_offset};
16 16
17#[derive(Debug)] 17#[derive(Debug)]
18struct FileMap(Vec<(FileId, RelativePathBuf)>); 18struct FileMap(Vec<(FileId, RelativePathBuf)>);
19 19
20impl FileMap { 20impl FileMap {
21 fn iter<'a>(&'a self) -> impl Iterator<Item=(FileId, &'a RelativePath)> + 'a { 21 fn iter<'a>(&'a self) -> impl Iterator<Item = (FileId, &'a RelativePath)> + 'a {
22 self.0.iter().map(|(id, path)| (*id, path.as_relative_path())) 22 self.0
23 .iter()
24 .map(|(id, path)| (*id, path.as_relative_path()))
23 } 25 }
24 26
25 fn path(&self, id: FileId) -> &RelativePath { 27 fn path(&self, id: FileId) -> &RelativePath {
26 self.iter() 28 self.iter().find(|&(it, _)| it == id).unwrap().1
27 .find(|&(it, _)| it == id)
28 .unwrap()
29 .1
30 } 29 }
31} 30}
32 31
@@ -71,10 +70,7 @@ fn get_signature(text: &str) -> (FnDescriptor, Option<usize>) {
71 70
72#[test] 71#[test]
73fn test_resolve_module() { 72fn test_resolve_module() {
74 let snap = analysis(&[ 73 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
75 ("/lib.rs", "mod foo;"),
76 ("/foo.rs", "")
77 ]);
78 let (_handle, token) = JobHandle::new(); 74 let (_handle, token) = JobHandle::new();
79 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); 75 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
80 assert_eq_dbg( 76 assert_eq_dbg(
@@ -82,10 +78,7 @@ fn test_resolve_module() {
82 &symbols, 78 &symbols,
83 ); 79 );
84 80
85 let snap = analysis(&[ 81 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo/mod.rs", "")]);
86 ("/lib.rs", "mod foo;"),
87 ("/foo/mod.rs", "")
88 ]);
89 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token); 82 let symbols = snap.approximately_resolve_symbol(FileId(1), 4.into(), &token);
90 assert_eq_dbg( 83 assert_eq_dbg(
91 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#, 84 r#"[(FileId(2), FileSymbol { name: "foo", node_range: [0; 0), kind: MODULE })]"#,
@@ -114,18 +107,12 @@ fn test_unresolved_module_diagnostic() {
114fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() { 107fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
115 let snap = analysis(&[("/lib.rs", "mod foo {}")]); 108 let snap = analysis(&[("/lib.rs", "mod foo {}")]);
116 let diagnostics = snap.diagnostics(FileId(1)); 109 let diagnostics = snap.diagnostics(FileId(1));
117 assert_eq_dbg( 110 assert_eq_dbg(r#"[]"#, &diagnostics);
118 r#"[]"#,
119 &diagnostics,
120 );
121} 111}
122 112
123#[test] 113#[test]
124fn test_resolve_parent_module() { 114fn test_resolve_parent_module() {
125 let snap = analysis(&[ 115 let snap = analysis(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
126 ("/lib.rs", "mod foo;"),
127 ("/foo.rs", ""),
128 ]);
129 let symbols = snap.parent_module(FileId(2)); 116 let symbols = snap.parent_module(FileId(2));
130 assert_eq_dbg( 117 assert_eq_dbg(
131 r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#, 118 r#"[(FileId(1), FileSymbol { name: "foo", node_range: [0; 8), kind: MODULE })]"#,
@@ -135,10 +122,7 @@ fn test_resolve_parent_module() {
135 122
136#[test] 123#[test]
137fn test_resolve_crate_root() { 124fn test_resolve_crate_root() {
138 let mut host = analysis_host(&[ 125 let mut host = analysis_host(&[("/lib.rs", "mod foo;"), ("/foo.rs", "")]);
139 ("/lib.rs", "mod foo;"),
140 ("/foo.rs", ""),
141 ]);
142 let snap = host.analysis(); 126 let snap = host.analysis();
143 assert!(snap.crate_for(FileId(2)).is_empty()); 127 assert!(snap.crate_for(FileId(2)).is_empty());
144 128
@@ -152,20 +136,18 @@ fn test_resolve_crate_root() {
152 host.set_crate_graph(crate_graph); 136 host.set_crate_graph(crate_graph);
153 let snap = host.analysis(); 137 let snap = host.analysis();
154 138
155 assert_eq!( 139 assert_eq!(snap.crate_for(FileId(2)), vec![CrateId(1)],);
156 snap.crate_for(FileId(2)),
157 vec![CrateId(1)],
158 );
159} 140}
160 141
161#[test] 142#[test]
162fn test_fn_signature_two_args_first() { 143fn test_fn_signature_two_args_first() {
163 let (desc, param) = get_signature( 144 let (desc, param) = get_signature(
164r#"fn foo(x: u32, y: u32) -> u32 {x + y} 145 r#"fn foo(x: u32, y: u32) -> u32 {x + y}
165fn bar() { foo(<|>3, ); }"#); 146fn bar() { foo(<|>3, ); }"#,
147 );
166 148
167 assert_eq!(desc.name, "foo".to_string()); 149 assert_eq!(desc.name, "foo".to_string());
168 assert_eq!(desc.params, vec!("x".to_string(),"y".to_string())); 150 assert_eq!(desc.params, vec!("x".to_string(), "y".to_string()));
169 assert_eq!(desc.ret_type, Some("-> u32".into())); 151 assert_eq!(desc.ret_type, Some("-> u32".into()));
170 assert_eq!(param, Some(0)); 152 assert_eq!(param, Some(0));
171} 153}
@@ -174,10 +156,11 @@ fn bar() { foo(<|>3, ); }"#);
174fn test_fn_signature_two_args_second() { 156fn test_fn_signature_two_args_second() {
175 let (desc, param) = get_signature( 157 let (desc, param) = get_signature(
176 r#"fn foo(x: u32, y: u32) -> u32 {x + y} 158 r#"fn foo(x: u32, y: u32) -> u32 {x + y}
177fn bar() { foo(3, <|>); }"#); 159fn bar() { foo(3, <|>); }"#,
160 );
178 161
179 assert_eq!(desc.name, "foo".to_string()); 162 assert_eq!(desc.name, "foo".to_string());
180 assert_eq!(desc.params, vec!("x".to_string(),"y".to_string())); 163 assert_eq!(desc.params, vec!("x".to_string(), "y".to_string()));
181 assert_eq!(desc.ret_type, Some("-> u32".into())); 164 assert_eq!(desc.ret_type, Some("-> u32".into()));
182 assert_eq!(param, Some(1)); 165 assert_eq!(param, Some(1));
183} 166}
@@ -185,8 +168,9 @@ fn bar() { foo(3, <|>); }"#);
185#[test] 168#[test]
186fn test_fn_signature_for_impl() { 169fn test_fn_signature_for_impl() {
187 let (desc, param) = get_signature( 170 let (desc, param) = get_signature(
188r#"struct F; impl F { pub fn new() { F{}} } 171 r#"struct F; impl F { pub fn new() { F{}} }
189fn bar() {let _ : F = F::new(<|>);}"#); 172fn bar() {let _ : F = F::new(<|>);}"#,
173 );
190 174
191 assert_eq!(desc.name, "new".to_string()); 175 assert_eq!(desc.name, "new".to_string());
192 assert_eq!(desc.params, Vec::<String>::new()); 176 assert_eq!(desc.params, Vec::<String>::new());
@@ -197,7 +181,7 @@ fn bar() {let _ : F = F::new(<|>);}"#);
197#[test] 181#[test]
198fn test_fn_signature_for_method_self() { 182fn test_fn_signature_for_method_self() {
199 let (desc, param) = get_signature( 183 let (desc, param) = get_signature(
200r#"struct F; 184 r#"struct F;
201impl F { 185impl F {
202 pub fn new() -> F{ 186 pub fn new() -> F{
203 F{} 187 F{}
@@ -209,7 +193,8 @@ impl F {
209fn bar() { 193fn bar() {
210 let f : F = F::new(); 194 let f : F = F::new();
211 f.do_it(<|>); 195 f.do_it(<|>);
212}"#); 196}"#,
197 );
213 198
214 assert_eq!(desc.name, "do_it".to_string()); 199 assert_eq!(desc.name, "do_it".to_string());
215 assert_eq!(desc.params, vec!["&self".to_string()]); 200 assert_eq!(desc.params, vec!["&self".to_string()]);
@@ -220,7 +205,7 @@ fn bar() {
220#[test] 205#[test]
221fn test_fn_signature_for_method_with_arg() { 206fn test_fn_signature_for_method_with_arg() {
222 let (desc, param) = get_signature( 207 let (desc, param) = get_signature(
223r#"struct F; 208 r#"struct F;
224impl F { 209impl F {
225 pub fn new() -> F{ 210 pub fn new() -> F{
226 F{} 211 F{}
@@ -232,7 +217,8 @@ impl F {
232fn bar() { 217fn bar() {
233 let f : F = F::new(); 218 let f : F = F::new();
234 f.do_it(<|>); 219 f.do_it(<|>);
235}"#); 220}"#,
221 );
236 222
237 assert_eq!(desc.name, "do_it".to_string()); 223 assert_eq!(desc.name, "do_it".to_string());
238 assert_eq!(desc.params, vec!["&self".to_string(), "x".to_string()]); 224 assert_eq!(desc.params, vec!["&self".to_string(), "x".to_string()]);