diff options
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r-- | crates/ra_analysis/src/completion/mod.rs | 7 | ||||
-rw-r--r-- | crates/ra_analysis/src/completion/reference_completion.rs | 14 | ||||
-rw-r--r-- | crates/ra_analysis/src/db.rs | 9 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 70 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_analysis/tests/tests.rs | 17 |
6 files changed, 74 insertions, 45 deletions
diff --git a/crates/ra_analysis/src/completion/mod.rs b/crates/ra_analysis/src/completion/mod.rs index e5ba92acd..0f154112a 100644 --- a/crates/ra_analysis/src/completion/mod.rs +++ b/crates/ra_analysis/src/completion/mod.rs | |||
@@ -9,6 +9,7 @@ use ra_syntax::{ | |||
9 | }; | 9 | }; |
10 | use ra_db::SyntaxDatabase; | 10 | use ra_db::SyntaxDatabase; |
11 | use rustc_hash::{FxHashMap}; | 11 | use rustc_hash::{FxHashMap}; |
12 | use hir::source_binder; | ||
12 | 13 | ||
13 | use crate::{ | 14 | use crate::{ |
14 | db, | 15 | db, |
@@ -36,7 +37,7 @@ pub(crate) fn completions( | |||
36 | original_file.reparse(&edit) | 37 | original_file.reparse(&edit) |
37 | }; | 38 | }; |
38 | 39 | ||
39 | let module = ctry!(hir::Module::guess_from_position(db, position)?); | 40 | let module = ctry!(source_binder::module_from_position(db, position)?); |
40 | 41 | ||
41 | let mut res = Vec::new(); | 42 | let mut res = Vec::new(); |
42 | let mut has_completions = false; | 43 | let mut has_completions = false; |
@@ -427,7 +428,7 @@ mod tests { | |||
427 | // check_snippet_completion(r" | 428 | // check_snippet_completion(r" |
428 | // <|> | 429 | // <|> |
429 | // ", | 430 | // ", |
430 | // r##"[CompletionItem { label: "tfn", lookup: None, snippet: Some("#[test]\nfn $1() {\n $0\n}") }]"##, | 431 | // r##"[CompletionItem { label: "Test function", lookup: None, snippet: Some("#[test]\nfn test_${1:feature}() {\n$0\n}"##, |
431 | // ); | 432 | // ); |
432 | check_snippet_completion(r" | 433 | check_snippet_completion(r" |
433 | #[cfg(test)] | 434 | #[cfg(test)] |
@@ -435,7 +436,7 @@ mod tests { | |||
435 | <|> | 436 | <|> |
436 | } | 437 | } |
437 | ", | 438 | ", |
438 | r##"[CompletionItem { label: "tfn", lookup: None, snippet: Some("#[test]\nfn $1() {\n $0\n}") }, | 439 | r##"[CompletionItem { label: "Test function", lookup: Some("tfn"), snippet: Some("#[test]\nfn ${1:feature}() {\n$0\n}") }, |
439 | CompletionItem { label: "pub(crate)", lookup: None, snippet: Some("pub(crate) $0") }]"##, | 440 | CompletionItem { label: "pub(crate)", lookup: None, snippet: Some("pub(crate) $0") }]"##, |
440 | ); | 441 | ); |
441 | } | 442 | } |
diff --git a/crates/ra_analysis/src/completion/reference_completion.rs b/crates/ra_analysis/src/completion/reference_completion.rs index e1a2d5241..f483ed045 100644 --- a/crates/ra_analysis/src/completion/reference_completion.rs +++ b/crates/ra_analysis/src/completion/reference_completion.rs | |||
@@ -163,7 +163,7 @@ fn complete_path( | |||
163 | }; | 163 | }; |
164 | let target_module = match def_id.resolve(db)? { | 164 | let target_module = match def_id.resolve(db)? { |
165 | Def::Module(it) => it, | 165 | Def::Module(it) => it, |
166 | Def::Item => return Ok(()), | 166 | _ => return Ok(()), |
167 | }; | 167 | }; |
168 | let module_scope = target_module.scope(db)?; | 168 | let module_scope = target_module.scope(db)?; |
169 | let completions = module_scope.entries().map(|(name, _res)| CompletionItem { | 169 | let completions = module_scope.entries().map(|(name, _res)| CompletionItem { |
@@ -177,9 +177,15 @@ fn complete_path( | |||
177 | 177 | ||
178 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { | 178 | fn complete_mod_item_snippets(acc: &mut Vec<CompletionItem>) { |
179 | acc.push(CompletionItem { | 179 | acc.push(CompletionItem { |
180 | label: "tfn".to_string(), | 180 | label: "Test function".to_string(), |
181 | lookup: None, | 181 | lookup: Some("tfn".to_string()), |
182 | snippet: Some("#[test]\nfn $1() {\n $0\n}".to_string()), | 182 | snippet: Some( |
183 | "#[test]\n\ | ||
184 | fn ${1:feature}() {\n\ | ||
185 | $0\n\ | ||
186 | }" | ||
187 | .to_string(), | ||
188 | ), | ||
183 | }); | 189 | }); |
184 | acc.push(CompletionItem { | 190 | acc.push(CompletionItem { |
185 | label: "pub(crate)".to_string(), | 191 | label: "pub(crate)".to_string(), |
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index df2ef293d..b8d774eb5 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | use salsa::{self, Database}; | 2 | use salsa::{self, Database}; |
3 | use ra_db::{LocationIntener, BaseDatabase}; | 3 | use ra_db::{LocationIntener, BaseDatabase}; |
4 | use hir::{self, DefId, DefLoc, FnId, SourceItemId}; | 4 | use hir::{self, DefId, DefLoc}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | symbol_index, | 7 | symbol_index, |
@@ -15,7 +15,6 @@ pub(crate) struct RootDatabase { | |||
15 | 15 | ||
16 | #[derive(Debug, Default)] | 16 | #[derive(Debug, Default)] |
17 | struct IdMaps { | 17 | struct IdMaps { |
18 | fns: LocationIntener<SourceItemId, FnId>, | ||
19 | defs: LocationIntener<DefLoc, DefId>, | 18 | defs: LocationIntener<DefLoc, DefId>, |
20 | } | 19 | } |
21 | 20 | ||
@@ -58,12 +57,6 @@ impl AsRef<LocationIntener<DefLoc, DefId>> for RootDatabase { | |||
58 | } | 57 | } |
59 | } | 58 | } |
60 | 59 | ||
61 | impl AsRef<LocationIntener<hir::SourceItemId, FnId>> for RootDatabase { | ||
62 | fn as_ref(&self) -> &LocationIntener<hir::SourceItemId, FnId> { | ||
63 | &self.id_maps.fns | ||
64 | } | ||
65 | } | ||
66 | |||
67 | salsa::database_storage! { | 60 | salsa::database_storage! { |
68 | pub(crate) struct RootDatabaseStorage for RootDatabase { | 61 | pub(crate) struct RootDatabaseStorage for RootDatabase { |
69 | impl ra_db::FilesDatabase { | 62 | impl ra_db::FilesDatabase { |
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index f5cb3550e..975afc145 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -16,6 +16,7 @@ use rustc_hash::FxHashSet; | |||
16 | use salsa::{Database, ParallelDatabase}; | 16 | use salsa::{Database, ParallelDatabase}; |
17 | use hir::{ | 17 | use hir::{ |
18 | self, | 18 | self, |
19 | source_binder, | ||
19 | FnSignatureInfo, | 20 | FnSignatureInfo, |
20 | Problem, | 21 | Problem, |
21 | }; | 22 | }; |
@@ -166,7 +167,7 @@ impl AnalysisImpl { | |||
166 | /// This return `Vec`: a module may be included from several places. We | 167 | /// This return `Vec`: a module may be included from several places. We |
167 | /// don't handle this case yet though, so the Vec has length at most one. | 168 | /// don't handle this case yet though, so the Vec has length at most one. |
168 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 169 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { |
169 | let descr = match hir::Module::guess_from_position(&*self.db, position)? { | 170 | let descr = match source_binder::module_from_position(&*self.db, position)? { |
170 | None => return Ok(Vec::new()), | 171 | None => return Ok(Vec::new()), |
171 | Some(it) => it, | 172 | Some(it) => it, |
172 | }; | 173 | }; |
@@ -185,15 +186,12 @@ impl AnalysisImpl { | |||
185 | } | 186 | } |
186 | /// Returns `Vec` for the same reason as `parent_module` | 187 | /// Returns `Vec` for the same reason as `parent_module` |
187 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 188 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
188 | let descr = match hir::Module::guess_from_file_id(&*self.db, file_id)? { | 189 | let descr = match source_binder::module_from_file_id(&*self.db, file_id)? { |
189 | None => return Ok(Vec::new()), | 190 | None => return Ok(Vec::new()), |
190 | Some(it) => it, | 191 | Some(it) => it, |
191 | }; | 192 | }; |
192 | let root = descr.crate_root(); | 193 | let root = descr.crate_root(); |
193 | let file_id = root | 194 | let file_id = root.source().file_id(); |
194 | .source() | ||
195 | .as_file() | ||
196 | .expect("root module always has a file as a source"); | ||
197 | 195 | ||
198 | let crate_graph = self.db.crate_graph(); | 196 | let crate_graph = self.db.crate_graph(); |
199 | let crate_id = crate_graph.crate_id_for_crate_root(file_id); | 197 | let crate_id = crate_graph.crate_id_for_crate_root(file_id); |
@@ -212,12 +210,14 @@ impl AnalysisImpl { | |||
212 | let file = self.db.source_file(position.file_id); | 210 | let file = self.db.source_file(position.file_id); |
213 | let syntax = file.syntax(); | 211 | let syntax = file.syntax(); |
214 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { | 212 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { |
215 | if let Some(fn_descr) = | 213 | if let Some(fn_descr) = source_binder::function_from_child_node( |
216 | hir::Function::guess_for_name_ref(&*self.db, position.file_id, name_ref) | 214 | &*self.db, |
217 | { | 215 | position.file_id, |
216 | name_ref.syntax(), | ||
217 | )? { | ||
218 | let scope = fn_descr.scope(&*self.db); | 218 | let scope = fn_descr.scope(&*self.db); |
219 | // First try to resolve the symbol locally | 219 | // First try to resolve the symbol locally |
220 | return if let Some(entry) = scope.resolve_local_name(name_ref) { | 220 | if let Some(entry) = scope.resolve_local_name(name_ref) { |
221 | let mut vec = vec![]; | 221 | let mut vec = vec![]; |
222 | vec.push(( | 222 | vec.push(( |
223 | position.file_id, | 223 | position.file_id, |
@@ -227,18 +227,17 @@ impl AnalysisImpl { | |||
227 | kind: NAME, | 227 | kind: NAME, |
228 | }, | 228 | }, |
229 | )); | 229 | )); |
230 | Ok(vec) | 230 | return Ok(vec); |
231 | } else { | ||
232 | // If that fails try the index based approach. | ||
233 | self.index_resolve(name_ref) | ||
234 | }; | 231 | }; |
235 | } | 232 | } |
233 | // If that fails try the index based approach. | ||
234 | return self.index_resolve(name_ref); | ||
236 | } | 235 | } |
237 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { | 236 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { |
238 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | 237 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { |
239 | if module.has_semi() { | 238 | if module.has_semi() { |
240 | let parent_module = | 239 | let parent_module = |
241 | hir::Module::guess_from_file_id(&*self.db, position.file_id)?; | 240 | source_binder::module_from_file_id(&*self.db, position.file_id)?; |
242 | let child_name = module.name(); | 241 | let child_name = module.name(); |
243 | match (parent_module, child_name) { | 242 | match (parent_module, child_name) { |
244 | (Some(parent_module), Some(child_name)) => { | 243 | (Some(parent_module), Some(child_name)) => { |
@@ -260,11 +259,11 @@ impl AnalysisImpl { | |||
260 | Ok(vec![]) | 259 | Ok(vec![]) |
261 | } | 260 | } |
262 | 261 | ||
263 | pub fn find_all_refs(&self, position: FilePosition) -> Vec<(FileId, TextRange)> { | 262 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { |
264 | let file = self.db.source_file(position.file_id); | 263 | let file = self.db.source_file(position.file_id); |
265 | // Find the binding associated with the offset | 264 | // Find the binding associated with the offset |
266 | let (binding, descr) = match find_binding(&self.db, &file, position) { | 265 | let (binding, descr) = match find_binding(&self.db, &file, position)? { |
267 | None => return Vec::new(), | 266 | None => return Ok(Vec::new()), |
268 | Some(it) => it, | 267 | Some(it) => it, |
269 | }; | 268 | }; |
270 | 269 | ||
@@ -277,25 +276,36 @@ impl AnalysisImpl { | |||
277 | .map(|ref_desc| (position.file_id, ref_desc.range)), | 276 | .map(|ref_desc| (position.file_id, ref_desc.range)), |
278 | ); | 277 | ); |
279 | 278 | ||
280 | return ret; | 279 | return Ok(ret); |
281 | 280 | ||
282 | fn find_binding<'a>( | 281 | fn find_binding<'a>( |
283 | db: &db::RootDatabase, | 282 | db: &db::RootDatabase, |
284 | source_file: &'a SourceFileNode, | 283 | source_file: &'a SourceFileNode, |
285 | position: FilePosition, | 284 | position: FilePosition, |
286 | ) -> Option<(ast::BindPat<'a>, hir::Function)> { | 285 | ) -> Cancelable<Option<(ast::BindPat<'a>, hir::Function)>> { |
287 | let syntax = source_file.syntax(); | 286 | let syntax = source_file.syntax(); |
288 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { | 287 | if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { |
289 | let descr = hir::Function::guess_for_bind_pat(db, position.file_id, binding)?; | 288 | let descr = ctry!(source_binder::function_from_child_node( |
290 | return Some((binding, descr)); | 289 | db, |
290 | position.file_id, | ||
291 | binding.syntax(), | ||
292 | )?); | ||
293 | return Ok(Some((binding, descr))); | ||
291 | }; | 294 | }; |
292 | let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; | 295 | let name_ref = ctry!(find_node_at_offset::<ast::NameRef>(syntax, position.offset)); |
293 | let descr = hir::Function::guess_for_name_ref(db, position.file_id, name_ref)?; | 296 | let descr = ctry!(source_binder::function_from_child_node( |
297 | db, | ||
298 | position.file_id, | ||
299 | name_ref.syntax(), | ||
300 | )?); | ||
294 | let scope = descr.scope(db); | 301 | let scope = descr.scope(db); |
295 | let resolved = scope.resolve_local_name(name_ref)?; | 302 | let resolved = ctry!(scope.resolve_local_name(name_ref)); |
296 | let resolved = resolved.ptr().resolve(source_file); | 303 | let resolved = resolved.ptr().resolve(source_file); |
297 | let binding = find_node_at_offset::<ast::BindPat>(syntax, resolved.range().end())?; | 304 | let binding = ctry!(find_node_at_offset::<ast::BindPat>( |
298 | Some((binding, descr)) | 305 | syntax, |
306 | resolved.range().end() | ||
307 | )); | ||
308 | Ok(Some((binding, descr))) | ||
299 | } | 309 | } |
300 | } | 310 | } |
301 | 311 | ||
@@ -320,7 +330,7 @@ impl AnalysisImpl { | |||
320 | fix: None, | 330 | fix: None, |
321 | }) | 331 | }) |
322 | .collect::<Vec<_>>(); | 332 | .collect::<Vec<_>>(); |
323 | if let Some(m) = hir::Module::guess_from_file_id(&*self.db, file_id)? { | 333 | if let Some(m) = source_binder::module_from_file_id(&*self.db, file_id)? { |
324 | for (name_node, problem) in m.problems(&*self.db) { | 334 | for (name_node, problem) in m.problems(&*self.db) { |
325 | let diag = match problem { | 335 | let diag = match problem { |
326 | Problem::UnresolvedModule { candidate } => { | 336 | Problem::UnresolvedModule { candidate } => { |
@@ -411,7 +421,9 @@ impl AnalysisImpl { | |||
411 | if fs.kind == FN_DEF { | 421 | if fs.kind == FN_DEF { |
412 | let fn_file = self.db.source_file(fn_file_id); | 422 | let fn_file = self.db.source_file(fn_file_id); |
413 | if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { | 423 | if let Some(fn_def) = find_node_at_offset(fn_file.syntax(), fs.node_range.start()) { |
414 | let descr = hir::Function::guess_from_source(&*self.db, fn_file_id, fn_def); | 424 | let descr = ctry!(source_binder::function_from_source( |
425 | &*self.db, fn_file_id, fn_def | ||
426 | )?); | ||
415 | if let Some(descriptor) = descr.signature_info(&*self.db) { | 427 | if let Some(descriptor) = descr.signature_info(&*self.db) { |
416 | // If we have a calling expression let's find which argument we are on | 428 | // If we have a calling expression let's find which argument we are on |
417 | let mut current_parameter = None; | 429 | let mut current_parameter = None; |
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 12df580ba..90528edfd 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -248,7 +248,7 @@ impl Analysis { | |||
248 | self.imp.approximately_resolve_symbol(position) | 248 | self.imp.approximately_resolve_symbol(position) |
249 | } | 249 | } |
250 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { | 250 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { |
251 | Ok(self.imp.find_all_refs(position)) | 251 | self.imp.find_all_refs(position) |
252 | } | 252 | } |
253 | pub fn doc_comment_for( | 253 | pub fn doc_comment_for( |
254 | &self, | 254 | &self, |
diff --git a/crates/ra_analysis/tests/tests.rs b/crates/ra_analysis/tests/tests.rs index fbe89f444..71d20dbe9 100644 --- a/crates/ra_analysis/tests/tests.rs +++ b/crates/ra_analysis/tests/tests.rs | |||
@@ -19,6 +19,23 @@ fn get_signature(text: &str) -> (FnSignatureInfo, Option<usize>) { | |||
19 | } | 19 | } |
20 | 20 | ||
21 | #[test] | 21 | #[test] |
22 | fn approximate_resolve_works_in_items() { | ||
23 | let (analysis, pos) = analysis_and_position( | ||
24 | " | ||
25 | //- /lib.rs | ||
26 | struct Foo; | ||
27 | enum E { X(Foo<|>) } | ||
28 | ", | ||
29 | ); | ||
30 | |||
31 | let symbols = analysis.approximately_resolve_symbol(pos).unwrap(); | ||
32 | assert_eq_dbg( | ||
33 | r#"[(FileId(1), FileSymbol { name: "Foo", node_range: [0; 11), kind: STRUCT_DEF })]"#, | ||
34 | &symbols, | ||
35 | ); | ||
36 | } | ||
37 | |||
38 | #[test] | ||
22 | fn test_resolve_module() { | 39 | fn test_resolve_module() { |
23 | let (analysis, pos) = analysis_and_position( | 40 | let (analysis, pos) = analysis_and_position( |
24 | " | 41 | " |