diff options
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r-- | crates/ra_analysis/src/completion/complete_dot.rs | 15 | ||||
-rw-r--r-- | crates/ra_analysis/src/db.rs | 1 | ||||
-rw-r--r-- | crates/ra_analysis/src/goto_defenition.rs | 73 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 40 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 13 | ||||
-rw-r--r-- | crates/ra_analysis/src/mock_analysis.rs | 7 | ||||
-rw-r--r-- | crates/ra_analysis/src/symbol_index.rs | 78 | ||||
-rw-r--r-- | crates/ra_analysis/src/syntax_highlighting.rs | 10 |
8 files changed, 170 insertions, 67 deletions
diff --git a/crates/ra_analysis/src/completion/complete_dot.rs b/crates/ra_analysis/src/completion/complete_dot.rs index f24835d17..031d8b98f 100644 --- a/crates/ra_analysis/src/completion/complete_dot.rs +++ b/crates/ra_analysis/src/completion/complete_dot.rs | |||
@@ -73,6 +73,21 @@ mod tests { | |||
73 | } | 73 | } |
74 | 74 | ||
75 | #[test] | 75 | #[test] |
76 | fn test_struct_field_completion_self() { | ||
77 | check_ref_completion( | ||
78 | r" | ||
79 | struct A { the_field: u32 } | ||
80 | impl A { | ||
81 | fn foo(self) { | ||
82 | self.<|> | ||
83 | } | ||
84 | } | ||
85 | ", | ||
86 | r#"the_field"#, | ||
87 | ); | ||
88 | } | ||
89 | |||
90 | #[test] | ||
76 | fn test_no_struct_field_completion_for_method_call() { | 91 | fn test_no_struct_field_completion_for_method_call() { |
77 | check_ref_completion( | 92 | check_ref_completion( |
78 | r" | 93 | r" |
diff --git a/crates/ra_analysis/src/db.rs b/crates/ra_analysis/src/db.rs index d7740f0c4..5422a400b 100644 --- a/crates/ra_analysis/src/db.rs +++ b/crates/ra_analysis/src/db.rs | |||
@@ -105,6 +105,7 @@ salsa::database_storage! { | |||
105 | fn type_for_field() for hir::db::TypeForFieldQuery; | 105 | fn type_for_field() for hir::db::TypeForFieldQuery; |
106 | fn struct_data() for hir::db::StructDataQuery; | 106 | fn struct_data() for hir::db::StructDataQuery; |
107 | fn enum_data() for hir::db::EnumDataQuery; | 107 | fn enum_data() for hir::db::EnumDataQuery; |
108 | fn impls_in_module() for hir::db::ImplsInModuleQuery; | ||
108 | } | 109 | } |
109 | } | 110 | } |
110 | } | 111 | } |
diff --git a/crates/ra_analysis/src/goto_defenition.rs b/crates/ra_analysis/src/goto_defenition.rs new file mode 100644 index 000000000..607a25115 --- /dev/null +++ b/crates/ra_analysis/src/goto_defenition.rs | |||
@@ -0,0 +1,73 @@ | |||
1 | use ra_db::FileId; | ||
2 | use ra_syntax::ast; | ||
3 | |||
4 | use crate::db::RootDatabase; | ||
5 | |||
6 | pub fn goto_defenition(db: &RootDatabase, position: FilePosition, | ||
7 | ) -> Cancelable<Option<Vec<NavigationTarget>>> { | ||
8 | let file = db.source_file(position.file_id); | ||
9 | let syntax = file.syntax(); | ||
10 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { | ||
11 | return Ok(Some(reference_defenition(db, position.file_id, name_ref))); | ||
12 | } | ||
13 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { | ||
14 | return Ok(Some(name_defenition(db, position.file_idname))); | ||
15 | } | ||
16 | Ok(None) | ||
17 | } | ||
18 | |||
19 | fn reference_defenition(db: &RootDatabase, file_id: FileId, name_ref: ast::NameRef) -> Cancelable<Vec<Nav>> { | ||
20 | if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { | ||
21 | let mut rr = ReferenceResolution::new(name_ref.syntax().range()); | ||
22 | if let Some(fn_descr) = | ||
23 | source_binder::function_from_child_node(self, position.file_id, name_ref.syntax())? | ||
24 | { | ||
25 | let scope = fn_descr.scopes(self); | ||
26 | // First try to resolve the symbol locally | ||
27 | if let Some(entry) = scope.resolve_local_name(name_ref) { | ||
28 | rr.resolves_to.push(NavigationTarget { | ||
29 | file_id: position.file_id, | ||
30 | name: entry.name().to_string().into(), | ||
31 | range: entry.ptr().range(), | ||
32 | kind: NAME, | ||
33 | ptr: None, | ||
34 | }); | ||
35 | return Ok(Some(rr)); | ||
36 | }; | ||
37 | } | ||
38 | // If that fails try the index based approach. | ||
39 | rr.resolves_to.extend( | ||
40 | self.index_resolve(name_ref)? | ||
41 | .into_iter() | ||
42 | .map(NavigationTarget::from_symbol), | ||
43 | ); | ||
44 | return Ok(Some(rr)); | ||
45 | } | ||
46 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { | ||
47 | let mut rr = ReferenceResolution::new(name.syntax().range()); | ||
48 | if let Some(module) = name.syntax().parent().and_then(ast::Module::cast) { | ||
49 | if module.has_semi() { | ||
50 | if let Some(child_module) = | ||
51 | source_binder::module_from_declaration(self, position.file_id, module)? | ||
52 | { | ||
53 | let file_id = child_module.file_id(); | ||
54 | let name = match child_module.name() { | ||
55 | Some(name) => name.to_string().into(), | ||
56 | None => "".into(), | ||
57 | }; | ||
58 | let symbol = NavigationTarget { | ||
59 | file_id, | ||
60 | name, | ||
61 | range: TextRange::offset_len(0.into(), 0.into()), | ||
62 | kind: MODULE, | ||
63 | ptr: None, | ||
64 | }; | ||
65 | rr.resolves_to.push(symbol); | ||
66 | return Ok(Some(rr)); | ||
67 | } | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | Ok(None) | ||
72 | |||
73 | } | ||
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index b812c3441..eae73c2c4 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -6,7 +6,7 @@ use hir::{ | |||
6 | self, FnSignatureInfo, Problem, source_binder, | 6 | self, FnSignatureInfo, Problem, source_binder, |
7 | }; | 7 | }; |
8 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; | 8 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; |
9 | use ra_editor::{self, find_node_at_offset, LocalEdit, Severity}; | 9 | use ra_editor::{self, find_node_at_offset, assists, LocalEdit, Severity}; |
10 | use ra_syntax::{ | 10 | use ra_syntax::{ |
11 | algo::{find_covering_node, visit::{visitor, Visitor}}, | 11 | algo::{find_covering_node, visit::{visitor, Visitor}}, |
12 | ast::{self, ArgListOwner, Expr, FnDef, NameOwner}, | 12 | ast::{self, ArgListOwner, Expr, FnDef, NameOwner}, |
@@ -165,9 +165,11 @@ impl db::RootDatabase { | |||
165 | }; | 165 | }; |
166 | } | 166 | } |
167 | // If that fails try the index based approach. | 167 | // If that fails try the index based approach. |
168 | for (file_id, symbol) in self.index_resolve(name_ref)? { | 168 | rr.resolves_to.extend( |
169 | rr.add_resolution(file_id, symbol); | 169 | self.index_resolve(name_ref)? |
170 | } | 170 | .into_iter() |
171 | .map(NavigationTarget::from_symbol), | ||
172 | ); | ||
171 | return Ok(Some(rr)); | 173 | return Ok(Some(rr)); |
172 | } | 174 | } |
173 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { | 175 | if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { |
@@ -333,19 +335,9 @@ impl db::RootDatabase { | |||
333 | 335 | ||
334 | pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> { | 336 | pub(crate) fn assists(&self, frange: FileRange) -> Vec<SourceChange> { |
335 | let file = self.source_file(frange.file_id); | 337 | let file = self.source_file(frange.file_id); |
336 | let offset = frange.range.start(); | 338 | assists::assists(&file, frange.range) |
337 | let actions = vec![ | ||
338 | ra_editor::flip_comma(&file, offset).map(|f| f()), | ||
339 | ra_editor::add_derive(&file, offset).map(|f| f()), | ||
340 | ra_editor::add_impl(&file, offset).map(|f| f()), | ||
341 | ra_editor::make_pub_crate(&file, offset).map(|f| f()), | ||
342 | ra_editor::introduce_variable(&file, frange.range).map(|f| f()), | ||
343 | ]; | ||
344 | actions | ||
345 | .into_iter() | 339 | .into_iter() |
346 | .filter_map(|local_edit| { | 340 | .map(|local_edit| SourceChange::from_local_edit(frange.file_id, local_edit)) |
347 | Some(SourceChange::from_local_edit(frange.file_id, local_edit?)) | ||
348 | }) | ||
349 | .collect() | 341 | .collect() |
350 | } | 342 | } |
351 | 343 | ||
@@ -362,13 +354,15 @@ impl db::RootDatabase { | |||
362 | 354 | ||
363 | // Resolve the function's NameRef (NOTE: this isn't entirely accurate). | 355 | // Resolve the function's NameRef (NOTE: this isn't entirely accurate). |
364 | let file_symbols = self.index_resolve(name_ref)?; | 356 | let file_symbols = self.index_resolve(name_ref)?; |
365 | for (fn_file_id, fs) in file_symbols { | 357 | for symbol in file_symbols { |
366 | if fs.ptr.kind() == FN_DEF { | 358 | if symbol.ptr.kind() == FN_DEF { |
367 | let fn_file = self.source_file(fn_file_id); | 359 | let fn_file = self.source_file(symbol.file_id); |
368 | let fn_def = fs.ptr.resolve(&fn_file); | 360 | let fn_def = symbol.ptr.resolve(&fn_file); |
369 | let fn_def = ast::FnDef::cast(fn_def.borrowed()).unwrap(); | 361 | let fn_def = ast::FnDef::cast(fn_def.borrowed()).unwrap(); |
370 | let descr = ctry!(source_binder::function_from_source( | 362 | let descr = ctry!(source_binder::function_from_source( |
371 | self, fn_file_id, fn_def | 363 | self, |
364 | symbol.file_id, | ||
365 | fn_def | ||
372 | )?); | 366 | )?); |
373 | if let Some(descriptor) = descr.signature_info(self) { | 367 | if let Some(descriptor) = descr.signature_info(self) { |
374 | // If we have a calling expression let's find which argument we are on | 368 | // If we have a calling expression let's find which argument we are on |
@@ -440,7 +434,7 @@ impl db::RootDatabase { | |||
440 | .map(|(file_id, text_range)| SourceFileEdit { | 434 | .map(|(file_id, text_range)| SourceFileEdit { |
441 | file_id: *file_id, | 435 | file_id: *file_id, |
442 | edit: { | 436 | edit: { |
443 | let mut builder = ra_text_edit::TextEditBuilder::new(); | 437 | let mut builder = ra_text_edit::TextEditBuilder::default(); |
444 | builder.replace(*text_range, new_name.into()); | 438 | builder.replace(*text_range, new_name.into()); |
445 | builder.finish() | 439 | builder.finish() |
446 | }, | 440 | }, |
@@ -448,7 +442,7 @@ impl db::RootDatabase { | |||
448 | .collect::<Vec<_>>(); | 442 | .collect::<Vec<_>>(); |
449 | Ok(res) | 443 | Ok(res) |
450 | } | 444 | } |
451 | fn index_resolve(&self, name_ref: ast::NameRef) -> Cancelable<Vec<(FileId, FileSymbol)>> { | 445 | fn index_resolve(&self, name_ref: ast::NameRef) -> Cancelable<Vec<FileSymbol>> { |
452 | let name = name_ref.text(); | 446 | let name = name_ref.text(); |
453 | let mut query = Query::new(name.to_string()); | 447 | let mut query = Query::new(name.to_string()); |
454 | query.exact(); | 448 | query.exact(); |
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 61af676b2..1e26a2889 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -237,11 +237,11 @@ pub struct NavigationTarget { | |||
237 | } | 237 | } |
238 | 238 | ||
239 | impl NavigationTarget { | 239 | impl NavigationTarget { |
240 | fn from_symbol(file_id: FileId, symbol: FileSymbol) -> NavigationTarget { | 240 | fn from_symbol(symbol: FileSymbol) -> NavigationTarget { |
241 | NavigationTarget { | 241 | NavigationTarget { |
242 | file_id: symbol.file_id, | ||
242 | name: symbol.name.clone(), | 243 | name: symbol.name.clone(), |
243 | kind: symbol.ptr.kind(), | 244 | kind: symbol.ptr.kind(), |
244 | file_id, | ||
245 | range: symbol.ptr.range(), | 245 | range: symbol.ptr.range(), |
246 | ptr: Some(symbol.ptr.clone()), | 246 | ptr: Some(symbol.ptr.clone()), |
247 | } | 247 | } |
@@ -278,11 +278,6 @@ impl ReferenceResolution { | |||
278 | resolves_to: Vec::new(), | 278 | resolves_to: Vec::new(), |
279 | } | 279 | } |
280 | } | 280 | } |
281 | |||
282 | fn add_resolution(&mut self, file_id: FileId, symbol: FileSymbol) { | ||
283 | self.resolves_to | ||
284 | .push(NavigationTarget::from_symbol(file_id, symbol)) | ||
285 | } | ||
286 | } | 281 | } |
287 | 282 | ||
288 | /// `AnalysisHost` stores the current state of the world. | 283 | /// `AnalysisHost` stores the current state of the world. |
@@ -380,7 +375,7 @@ impl Analysis { | |||
380 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { | 375 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { |
381 | let res = symbol_index::world_symbols(&*self.db, query)? | 376 | let res = symbol_index::world_symbols(&*self.db, query)? |
382 | .into_iter() | 377 | .into_iter() |
383 | .map(|(file_id, symbol)| NavigationTarget::from_symbol(file_id, symbol)) | 378 | .map(NavigationTarget::from_symbol) |
384 | .collect(); | 379 | .collect(); |
385 | Ok(res) | 380 | Ok(res) |
386 | } | 381 | } |
@@ -399,7 +394,7 @@ impl Analysis { | |||
399 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { | 394 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { |
400 | self.db.doc_text_for(nav) | 395 | self.db.doc_text_for(nav) |
401 | } | 396 | } |
402 | /// Returns a `mod name;` declaration whihc created the current module. | 397 | /// Returns a `mod name;` declaration which created the current module. |
403 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { | 398 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { |
404 | self.db.parent_module(position) | 399 | self.db.parent_module(position) |
405 | } | 400 | } |
diff --git a/crates/ra_analysis/src/mock_analysis.rs b/crates/ra_analysis/src/mock_analysis.rs index 960529404..846c76cfe 100644 --- a/crates/ra_analysis/src/mock_analysis.rs +++ b/crates/ra_analysis/src/mock_analysis.rs | |||
@@ -4,7 +4,7 @@ use relative_path::RelativePathBuf; | |||
4 | use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; | 4 | use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; |
5 | use ra_db::mock::FileMap; | 5 | use ra_db::mock::FileMap; |
6 | 6 | ||
7 | use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, FileRange, SourceRootId}; | 7 | use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId}; |
8 | 8 | ||
9 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis | 9 | /// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis |
10 | /// from a set of in-memory files. | 10 | /// from a set of in-memory files. |
@@ -87,12 +87,17 @@ impl MockAnalysis { | |||
87 | let source_root = SourceRootId(0); | 87 | let source_root = SourceRootId(0); |
88 | let mut change = AnalysisChange::new(); | 88 | let mut change = AnalysisChange::new(); |
89 | change.add_root(source_root, true); | 89 | change.add_root(source_root, true); |
90 | let mut crate_graph = CrateGraph::default(); | ||
90 | for (path, contents) in self.files.into_iter() { | 91 | for (path, contents) in self.files.into_iter() { |
91 | assert!(path.starts_with('/')); | 92 | assert!(path.starts_with('/')); |
92 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); | 93 | let path = RelativePathBuf::from_path(&path[1..]).unwrap(); |
93 | let file_id = file_map.add(path.clone()); | 94 | let file_id = file_map.add(path.clone()); |
95 | if path == "/lib.rs" || path == "/main.rs" { | ||
96 | crate_graph.add_crate_root(file_id); | ||
97 | } | ||
94 | change.add_file(source_root, file_id, path, Arc::new(contents)); | 98 | change.add_file(source_root, file_id, path, Arc::new(contents)); |
95 | } | 99 | } |
100 | change.set_crate_graph(crate_graph); | ||
96 | // change.set_file_resolver(Arc::new(file_map)); | 101 | // change.set_file_resolver(Arc::new(file_map)); |
97 | host.apply_change(change); | 102 | host.apply_change(change); |
98 | host | 103 | host |
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs index 10d8e8059..e2b1c88fe 100644 --- a/crates/ra_analysis/src/symbol_index.rs +++ b/crates/ra_analysis/src/symbol_index.rs | |||
@@ -20,6 +20,7 @@ | |||
20 | //! file in the current workspace, and run a query aginst the union of all | 20 | //! file in the current workspace, and run a query aginst the union of all |
21 | //! thouse fsts. | 21 | //! thouse fsts. |
22 | use std::{ | 22 | use std::{ |
23 | cmp::Ordering, | ||
23 | hash::{Hash, Hasher}, | 24 | hash::{Hash, Hasher}, |
24 | sync::Arc, | 25 | sync::Arc, |
25 | }; | 26 | }; |
@@ -27,11 +28,11 @@ use std::{ | |||
27 | use fst::{self, Streamer}; | 28 | use fst::{self, Streamer}; |
28 | use ra_syntax::{ | 29 | use ra_syntax::{ |
29 | SyntaxNodeRef, SourceFileNode, SmolStr, | 30 | SyntaxNodeRef, SourceFileNode, SmolStr, |
30 | algo::visit::{visitor, Visitor}, | 31 | algo::{visit::{visitor, Visitor}, find_covering_node}, |
31 | SyntaxKind::{self, *}, | 32 | SyntaxKind::{self, *}, |
32 | ast::{self, NameOwner}, | 33 | ast::{self, NameOwner}, |
33 | }; | 34 | }; |
34 | use ra_db::{SyntaxDatabase, SourceRootId, FilesDatabase, LocalSyntaxPtr}; | 35 | use ra_db::{SourceRootId, FilesDatabase, LocalSyntaxPtr}; |
35 | use salsa::ParallelDatabase; | 36 | use salsa::ParallelDatabase; |
36 | use rayon::prelude::*; | 37 | use rayon::prelude::*; |
37 | 38 | ||
@@ -41,7 +42,7 @@ use crate::{ | |||
41 | }; | 42 | }; |
42 | 43 | ||
43 | salsa::query_group! { | 44 | salsa::query_group! { |
44 | pub(crate) trait SymbolsDatabase: SyntaxDatabase { | 45 | pub(crate) trait SymbolsDatabase: hir::db::HirDatabase { |
45 | fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { | 46 | fn file_symbols(file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { |
46 | type FileSymbolsQuery; | 47 | type FileSymbolsQuery; |
47 | } | 48 | } |
@@ -52,16 +53,26 @@ salsa::query_group! { | |||
52 | } | 53 | } |
53 | } | 54 | } |
54 | 55 | ||
55 | fn file_symbols(db: &impl SyntaxDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { | 56 | fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Cancelable<Arc<SymbolIndex>> { |
56 | db.check_canceled()?; | 57 | db.check_canceled()?; |
57 | let syntax = db.source_file(file_id); | 58 | let source_file = db.source_file(file_id); |
58 | Ok(Arc::new(SymbolIndex::for_file(file_id, syntax))) | 59 | let mut symbols = source_file |
60 | .syntax() | ||
61 | .descendants() | ||
62 | .filter_map(to_symbol) | ||
63 | .map(move |(name, ptr)| FileSymbol { name, ptr, file_id }) | ||
64 | .collect::<Vec<_>>(); | ||
65 | |||
66 | for (name, text_range) in hir::source_binder::macro_symbols(db, file_id)? { | ||
67 | let node = find_covering_node(source_file.syntax(), text_range); | ||
68 | let ptr = LocalSyntaxPtr::new(node); | ||
69 | symbols.push(FileSymbol { file_id, name, ptr }) | ||
70 | } | ||
71 | |||
72 | Ok(Arc::new(SymbolIndex::new(symbols))) | ||
59 | } | 73 | } |
60 | 74 | ||
61 | pub(crate) fn world_symbols( | 75 | pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Cancelable<Vec<FileSymbol>> { |
62 | db: &RootDatabase, | ||
63 | query: Query, | ||
64 | ) -> Cancelable<Vec<(FileId, FileSymbol)>> { | ||
65 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` | 76 | /// Need to wrap Snapshot to provide `Clone` impl for `map_with` |
66 | struct Snap(salsa::Snapshot<RootDatabase>); | 77 | struct Snap(salsa::Snapshot<RootDatabase>); |
67 | impl Clone for Snap { | 78 | impl Clone for Snap { |
@@ -95,7 +106,7 @@ pub(crate) fn world_symbols( | |||
95 | 106 | ||
96 | #[derive(Default, Debug)] | 107 | #[derive(Default, Debug)] |
97 | pub(crate) struct SymbolIndex { | 108 | pub(crate) struct SymbolIndex { |
98 | symbols: Vec<(FileId, FileSymbol)>, | 109 | symbols: Vec<FileSymbol>, |
99 | map: fst::Map, | 110 | map: fst::Map, |
100 | } | 111 | } |
101 | 112 | ||
@@ -114,6 +125,17 @@ impl Hash for SymbolIndex { | |||
114 | } | 125 | } |
115 | 126 | ||
116 | impl SymbolIndex { | 127 | impl SymbolIndex { |
128 | fn new(mut symbols: Vec<FileSymbol>) -> SymbolIndex { | ||
129 | fn cmp(s1: &FileSymbol, s2: &FileSymbol) -> Ordering { | ||
130 | unicase::Ascii::new(s1.name.as_str()).cmp(&unicase::Ascii::new(s2.name.as_str())) | ||
131 | } | ||
132 | symbols.par_sort_by(cmp); | ||
133 | symbols.dedup_by(|s1, s2| cmp(s1, s2) == Ordering::Equal); | ||
134 | let names = symbols.iter().map(|it| it.name.as_str().to_lowercase()); | ||
135 | let map = fst::Map::from_iter(names.into_iter().zip(0u64..)).unwrap(); | ||
136 | SymbolIndex { symbols, map } | ||
137 | } | ||
138 | |||
117 | pub(crate) fn len(&self) -> usize { | 139 | pub(crate) fn len(&self) -> usize { |
118 | self.symbols.len() | 140 | self.symbols.len() |
119 | } | 141 | } |
@@ -121,30 +143,21 @@ impl SymbolIndex { | |||
121 | pub(crate) fn for_files( | 143 | pub(crate) fn for_files( |
122 | files: impl ParallelIterator<Item = (FileId, SourceFileNode)>, | 144 | files: impl ParallelIterator<Item = (FileId, SourceFileNode)>, |
123 | ) -> SymbolIndex { | 145 | ) -> SymbolIndex { |
124 | let mut symbols = files | 146 | let symbols = files |
125 | .flat_map(|(file_id, file)| { | 147 | .flat_map(|(file_id, file)| { |
126 | file.syntax() | 148 | file.syntax() |
127 | .descendants() | 149 | .descendants() |
128 | .filter_map(to_symbol) | 150 | .filter_map(to_symbol) |
129 | .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol))) | 151 | .map(move |(name, ptr)| FileSymbol { name, ptr, file_id }) |
130 | .collect::<Vec<_>>() | 152 | .collect::<Vec<_>>() |
131 | }) | 153 | }) |
132 | .collect::<Vec<_>>(); | 154 | .collect::<Vec<_>>(); |
133 | symbols.par_sort_by(|s1, s2| s1.0.cmp(&s2.0)); | 155 | SymbolIndex::new(symbols) |
134 | symbols.dedup_by(|s1, s2| s1.0 == s2.0); | ||
135 | let (names, symbols): (Vec<String>, Vec<(FileId, FileSymbol)>) = | ||
136 | symbols.into_iter().unzip(); | ||
137 | let map = fst::Map::from_iter(names.into_iter().zip(0u64..)).unwrap(); | ||
138 | SymbolIndex { symbols, map } | ||
139 | } | ||
140 | |||
141 | pub(crate) fn for_file(file_id: FileId, file: SourceFileNode) -> SymbolIndex { | ||
142 | SymbolIndex::for_files(rayon::iter::once((file_id, file))) | ||
143 | } | 156 | } |
144 | } | 157 | } |
145 | 158 | ||
146 | impl Query { | 159 | impl Query { |
147 | pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<(FileId, FileSymbol)> { | 160 | pub(crate) fn search(self, indices: &[Arc<SymbolIndex>]) -> Vec<FileSymbol> { |
148 | let mut op = fst::map::OpBuilder::new(); | 161 | let mut op = fst::map::OpBuilder::new(); |
149 | for file_symbols in indices.iter() { | 162 | for file_symbols in indices.iter() { |
150 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); | 163 | let automaton = fst::automaton::Subsequence::new(&self.lowercased); |
@@ -160,14 +173,14 @@ impl Query { | |||
160 | let file_symbols = &indices[indexed_value.index]; | 173 | let file_symbols = &indices[indexed_value.index]; |
161 | let idx = indexed_value.value as usize; | 174 | let idx = indexed_value.value as usize; |
162 | 175 | ||
163 | let (file_id, symbol) = &file_symbols.symbols[idx]; | 176 | let symbol = &file_symbols.symbols[idx]; |
164 | if self.only_types && !is_type(symbol.ptr.kind()) { | 177 | if self.only_types && !is_type(symbol.ptr.kind()) { |
165 | continue; | 178 | continue; |
166 | } | 179 | } |
167 | if self.exact && symbol.name != self.query { | 180 | if self.exact && symbol.name != self.query { |
168 | continue; | 181 | continue; |
169 | } | 182 | } |
170 | res.push((*file_id, symbol.clone())); | 183 | res.push(symbol.clone()); |
171 | } | 184 | } |
172 | } | 185 | } |
173 | res | 186 | res |
@@ -185,17 +198,16 @@ fn is_type(kind: SyntaxKind) -> bool { | |||
185 | /// possible. | 198 | /// possible. |
186 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 199 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
187 | pub(crate) struct FileSymbol { | 200 | pub(crate) struct FileSymbol { |
201 | pub(crate) file_id: FileId, | ||
188 | pub(crate) name: SmolStr, | 202 | pub(crate) name: SmolStr, |
189 | pub(crate) ptr: LocalSyntaxPtr, | 203 | pub(crate) ptr: LocalSyntaxPtr, |
190 | } | 204 | } |
191 | 205 | ||
192 | fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { | 206 | fn to_symbol(node: SyntaxNodeRef) -> Option<(SmolStr, LocalSyntaxPtr)> { |
193 | fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<FileSymbol> { | 207 | fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<(SmolStr, LocalSyntaxPtr)> { |
194 | let name = node.name()?; | 208 | let name = node.name()?.text(); |
195 | Some(FileSymbol { | 209 | let ptr = LocalSyntaxPtr::new(node.syntax()); |
196 | name: name.text(), | 210 | Some((name, ptr)) |
197 | ptr: LocalSyntaxPtr::new(node.syntax()), | ||
198 | }) | ||
199 | } | 211 | } |
200 | visitor() | 212 | visitor() |
201 | .visit(decl::<ast::FnDef>) | 213 | .visit(decl::<ast::FnDef>) |
diff --git a/crates/ra_analysis/src/syntax_highlighting.rs b/crates/ra_analysis/src/syntax_highlighting.rs index ccea4aee3..35e153ca0 100644 --- a/crates/ra_analysis/src/syntax_highlighting.rs +++ b/crates/ra_analysis/src/syntax_highlighting.rs | |||
@@ -43,6 +43,7 @@ mod tests { | |||
43 | " | 43 | " |
44 | fn main() { | 44 | fn main() { |
45 | ctry!({ let x = 92; x}); | 45 | ctry!({ let x = 92; x}); |
46 | vec![{ let x = 92; x}]; | ||
46 | } | 47 | } |
47 | ", | 48 | ", |
48 | ); | 49 | ); |
@@ -53,10 +54,17 @@ mod tests { | |||
53 | HighlightedRange { range: [41; 46), tag: "macro" }, | 54 | HighlightedRange { range: [41; 46), tag: "macro" }, |
54 | HighlightedRange { range: [49; 52), tag: "keyword" }, | 55 | HighlightedRange { range: [49; 52), tag: "keyword" }, |
55 | HighlightedRange { range: [57; 59), tag: "literal" }, | 56 | HighlightedRange { range: [57; 59), tag: "literal" }, |
57 | HighlightedRange { range: [82; 86), tag: "macro" }, | ||
58 | HighlightedRange { range: [89; 92), tag: "keyword" }, | ||
59 | HighlightedRange { range: [97; 99), tag: "literal" }, | ||
56 | HighlightedRange { range: [49; 52), tag: "keyword" }, | 60 | HighlightedRange { range: [49; 52), tag: "keyword" }, |
57 | HighlightedRange { range: [53; 54), tag: "function" }, | 61 | HighlightedRange { range: [53; 54), tag: "function" }, |
58 | HighlightedRange { range: [57; 59), tag: "literal" }, | 62 | HighlightedRange { range: [57; 59), tag: "literal" }, |
59 | HighlightedRange { range: [61; 62), tag: "text" }]"#, | 63 | HighlightedRange { range: [61; 62), tag: "text" }, |
64 | HighlightedRange { range: [89; 92), tag: "keyword" }, | ||
65 | HighlightedRange { range: [93; 94), tag: "function" }, | ||
66 | HighlightedRange { range: [97; 99), tag: "literal" }, | ||
67 | HighlightedRange { range: [101; 102), tag: "text" }]"#, | ||
60 | &highlights, | 68 | &highlights, |
61 | ) | 69 | ) |
62 | } | 70 | } |