aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src')
-rw-r--r--crates/ra_ide_api/src/completion.rs5
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs20
-rw-r--r--crates/ra_ide_api/src/completion/complete_fn_param.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs21
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap54
-rw-r--r--crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap26
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs8
-rw-r--r--crates/ra_ide_api/src/hover.rs4
-rw-r--r--crates/ra_ide_api/src/impls.rs4
-rw-r--r--crates/ra_ide_api/src/lib.rs13
-rw-r--r--crates/ra_ide_api/src/mock_analysis.rs8
-rw-r--r--crates/ra_ide_api/src/navigation_target.rs11
-rw-r--r--crates/ra_ide_api/src/references.rs6
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs64
14 files changed, 202 insertions, 44 deletions
diff --git a/crates/ra_ide_api/src/completion.rs b/crates/ra_ide_api/src/completion.rs
index 83c243944..4a38d62bb 100644
--- a/crates/ra_ide_api/src/completion.rs
+++ b/crates/ra_ide_api/src/completion.rs
@@ -30,7 +30,7 @@ pub use crate::completion::completion_item::{CompletionItem, CompletionItemKind,
30/// incomplete and can look really weird. 30/// incomplete and can look really weird.
31/// 31///
32/// Once the context is collected, we run a series of completion routines which 32/// Once the context is collected, we run a series of completion routines which
33/// look at the context and produce completion items. One subtelty about this 33/// look at the context and produce completion items. One subtlety about this
34/// phase is that completion engine should not filter by the substring which is 34/// phase is that completion engine should not filter by the substring which is
35/// already present, it should give all possible variants for the identifier at 35/// already present, it should give all possible variants for the identifier at
36/// the caret. In other words, for 36/// the caret. In other words, for
@@ -71,6 +71,7 @@ pub fn function_label(node: &ast::FnDef) -> Option<String> {
71 .children() 71 .children()
72 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body 72 .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
73 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments 73 .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
74 .filter(|child| ast::Attr::cast(child).is_none()) // Filter out attributes
74 .map(|node| node.text().to_string()) 75 .map(|node| node.text().to_string())
75 .collect(); 76 .collect();
76 label 77 label
@@ -86,6 +87,7 @@ pub fn const_label(node: &ast::ConstDef) -> String {
86 .syntax() 87 .syntax()
87 .children() 88 .children()
88 .filter(|child| ast::Comment::cast(child).is_none()) 89 .filter(|child| ast::Comment::cast(child).is_none())
90 .filter(|child| ast::Attr::cast(child).is_none())
89 .map(|node| node.text().to_string()) 91 .map(|node| node.text().to_string())
90 .collect(); 92 .collect();
91 93
@@ -97,6 +99,7 @@ pub fn type_label(node: &ast::TypeDef) -> String {
97 .syntax() 99 .syntax()
98 .children() 100 .children()
99 .filter(|child| ast::Comment::cast(child).is_none()) 101 .filter(|child| ast::Comment::cast(child).is_none())
102 .filter(|child| ast::Attr::cast(child).is_none())
100 .map(|node| node.text().to_string()) 103 .map(|node| node.text().to_string())
101 .collect(); 104 .collect();
102 105
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index a673dbdcf..be839345f 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -180,6 +180,26 @@ mod tests {
180 } 180 }
181 181
182 #[test] 182 #[test]
183 fn test_method_attr_filtering() {
184 check_ref_completion(
185 "method_attr_filtering",
186 r"
187 struct A {}
188 impl A {
189 #[inline]
190 fn the_method(&self) {
191 let x = 1;
192 let y = 2;
193 }
194 }
195 fn foo(a: A) {
196 a.<|>
197 }
198 ",
199 );
200 }
201
202 #[test]
183 fn test_tuple_field_completion() { 203 fn test_tuple_field_completion() {
184 check_ref_completion( 204 check_ref_completion(
185 "tuple_field_completion", 205 "tuple_field_completion",
diff --git a/crates/ra_ide_api/src/completion/complete_fn_param.rs b/crates/ra_ide_api/src/completion/complete_fn_param.rs
index 43532226f..4d6416284 100644
--- a/crates/ra_ide_api/src/completion/complete_fn_param.rs
+++ b/crates/ra_ide_api/src/completion/complete_fn_param.rs
@@ -7,7 +7,7 @@ use rustc_hash::FxHashMap;
7 7
8use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem}; 8use crate::completion::{CompletionContext, Completions, CompletionKind, CompletionItem};
9 9
10/// Complete repeated parametes, both name and type. For example, if all 10/// Complete repeated parameters, both name and type. For example, if all
11/// functions in a file have a `spam: &mut Spam` parameter, a completion with 11/// functions in a file have a `spam: &mut Spam` parameter, a completion with
12/// `spam: &mut Spam` insert text/label and `spam` lookup string will be 12/// `spam: &mut Spam` insert text/label and `spam` lookup string will be
13/// suggested. 13/// suggested.
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 445788407..eeaf26d93 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -4,7 +4,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
4 if !ctx.is_trivial_path { 4 if !ctx.is_trivial_path {
5 return; 5 return;
6 } 6 }
7 let names = ctx.resolver.all_names(); 7 let names = ctx.resolver.all_names(ctx.db);
8 8
9 names.into_iter().for_each(|(name, res)| { 9 names.into_iter().for_each(|(name, res)| {
10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 10 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
@@ -165,4 +165,23 @@ mod tests {
165 fn completes_self_in_methods() { 165 fn completes_self_in_methods() {
166 check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }") 166 check_reference_completion("self_in_methods", r"impl S { fn foo(&self) { <|> } }")
167 } 167 }
168
169 #[test]
170 fn completes_prelude() {
171 check_reference_completion(
172 "completes_prelude",
173 "
174 //- /main.rs
175 fn foo() { let x: <|> }
176
177 //- /std/lib.rs
178 #[prelude_import]
179 use prelude::*;
180
181 mod prelude {
182 struct Option;
183 }
184 ",
185 );
186 }
168} 187}
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap
new file mode 100644
index 000000000..2b5a1a8ea
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__completes_prelude.snap
@@ -0,0 +1,54 @@
1---
2created: "2019-02-13T19:52:43.734834624Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions
6---
7[
8 CompletionItem {
9 completion_kind: Reference,
10 label: "Option",
11 kind: Some(
12 Struct
13 ),
14 detail: None,
15 documentation: None,
16 lookup: None,
17 insert_text: None,
18 insert_text_format: PlainText,
19 source_range: [18; 18),
20 text_edit: None
21 },
22 CompletionItem {
23 completion_kind: Reference,
24 label: "foo",
25 kind: Some(
26 Function
27 ),
28 detail: Some(
29 "fn foo()"
30 ),
31 documentation: None,
32 lookup: None,
33 insert_text: Some(
34 "foo()$0"
35 ),
36 insert_text_format: Snippet,
37 source_range: [18; 18),
38 text_edit: None
39 },
40 CompletionItem {
41 completion_kind: Reference,
42 label: "std",
43 kind: Some(
44 Module
45 ),
46 detail: None,
47 documentation: None,
48 lookup: None,
49 insert_text: None,
50 insert_text_format: PlainText,
51 source_range: [18; 18),
52 text_edit: None
53 }
54]
diff --git a/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap b/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap
new file mode 100644
index 000000000..46f9fa971
--- /dev/null
+++ b/crates/ra_ide_api/src/completion/snapshots/completion_item__method_attr_filtering.snap
@@ -0,0 +1,26 @@
1---
2created: "2019-02-12T18:32:09.428929418Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/completion/completion_item.rs
5expression: kind_completions
6---
7[
8 CompletionItem {
9 completion_kind: Reference,
10 label: "the_method",
11 kind: Some(
12 Method
13 ),
14 detail: Some(
15 "fn the_method(&self)"
16 ),
17 documentation: None,
18 lookup: None,
19 insert_text: Some(
20 "the_method()$0"
21 ),
22 insert_text_format: Snippet,
23 source_range: [249; 249),
24 text_edit: None
25 }
26]
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 413720960..96ed8c8e9 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -93,10 +93,10 @@ pub(crate) fn reference_definition(
93 return Exact(nav); 93 return Exact(nav);
94 } 94 }
95 Some(Resolution::GenericParam(..)) => { 95 Some(Resolution::GenericParam(..)) => {
96 // TODO go to the generic param def 96 // TODO: go to the generic param def
97 } 97 }
98 Some(Resolution::SelfType(_impl_block)) => { 98 Some(Resolution::SelfType(_impl_block)) => {
99 // TODO go to the implemented type 99 // TODO: go to the implemented type
100 } 100 }
101 None => {} 101 None => {}
102 } 102 }
@@ -133,8 +133,8 @@ mod tests {
133 133
134 use crate::mock_analysis::analysis_and_position; 134 use crate::mock_analysis::analysis_and_position;
135 135
136 fn check_goto(fixuture: &str, expected: &str) { 136 fn check_goto(fixture: &str, expected: &str) {
137 let (analysis, pos) = analysis_and_position(fixuture); 137 let (analysis, pos) = analysis_and_position(fixture);
138 138
139 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 139 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
140 assert_eq!(navs.len(), 1); 140 assert_eq!(navs.len(), 1);
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 60b81567c..0888ab6de 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -71,8 +71,8 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
71 } 71 }
72} 72}
73 73
74// FIXME: this should not really use navigation target. Rather, approximatelly 74// FIXME: this should not really use navigation target. Rather, approximately
75// resovled symbol should return a `DefId`. 75// resolved symbol should return a `DefId`.
76fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> { 76fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
77 match (nav.description(db), nav.docs(db)) { 77 match (nav.description(db), nav.docs(db)) {
78 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs), 78 (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs),
diff --git a/crates/ra_ide_api/src/impls.rs b/crates/ra_ide_api/src/impls.rs
index 444c4aeb2..681bd808d 100644
--- a/crates/ra_ide_api/src/impls.rs
+++ b/crates/ra_ide_api/src/impls.rs
@@ -78,8 +78,8 @@ fn impls_for_trait(
78mod tests { 78mod tests {
79 use crate::mock_analysis::analysis_and_position; 79 use crate::mock_analysis::analysis_and_position;
80 80
81 fn check_goto(fixuture: &str, expected: &[&str]) { 81 fn check_goto(fixture: &str, expected: &[&str]) {
82 let (analysis, pos) = analysis_and_position(fixuture); 82 let (analysis, pos) = analysis_and_position(fixture);
83 83
84 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info; 84 let navs = analysis.goto_implementation(pos).unwrap().unwrap().info;
85 assert_eq!(navs.len(), expected.len()); 85 assert_eq!(navs.len(), expected.len());
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 2d090d9b4..d77a56ce8 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -7,7 +7,7 @@
7//! However, IDE specific bits of the analysis (most notably completion) happen 7//! However, IDE specific bits of the analysis (most notably completion) happen
8//! in this crate. 8//! in this crate.
9//! 9//!
10//! The sibling `ra_ide_api_light` handles thouse bits of IDE functionality 10//! The sibling `ra_ide_api_light` handles those bits of IDE functionality
11//! which are restricted to a single file and need only syntax. 11//! which are restricted to a single file and need only syntax.
12 12
13// For proving that RootDatabase is RefUnwindSafe. 13// For proving that RootDatabase is RefUnwindSafe.
@@ -62,12 +62,13 @@ pub use ra_ide_api_light::{
62 LineIndex, LineCol, translate_offset_with_edit, 62 LineIndex, LineCol, translate_offset_with_edit,
63}; 63};
64pub use ra_db::{ 64pub use ra_db::{
65 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId 65 Canceled, CrateGraph, CrateId, FileId, FilePosition, FileRange, SourceRootId,
66 Edition
66}; 67};
67pub use hir::Documentation; 68pub use hir::Documentation;
68 69
69// We use jemalloc mainly to get heap usage statistics, actual performance 70// We use jemalloc mainly to get heap usage statistics, actual performance
70// differnece is not measures. 71// difference is not measures.
71#[cfg(feature = "jemalloc")] 72#[cfg(feature = "jemalloc")]
72#[global_allocator] 73#[global_allocator]
73static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 74static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
@@ -221,12 +222,12 @@ impl Analysis {
221 self.db.line_index(file_id) 222 self.db.line_index(file_id)
222 } 223 }
223 224
224 /// Selects the next syntactic nodes encopasing the range. 225 /// Selects the next syntactic nodes encompassing the range.
225 pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> { 226 pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> {
226 self.with_db(|db| extend_selection::extend_selection(db, frange)) 227 self.with_db(|db| extend_selection::extend_selection(db, frange))
227 } 228 }
228 229
229 /// Returns position of the mathcing brace (all types of braces are 230 /// Returns position of the matching brace (all types of braces are
230 /// supported). 231 /// supported).
231 pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> { 232 pub fn matching_brace(&self, position: FilePosition) -> Option<TextUnit> {
232 let file = self.db.parse(position.file_id); 233 let file = self.db.parse(position.file_id);
@@ -316,7 +317,7 @@ impl Analysis {
316 self.with_db(|db| references::find_all_refs(db, position)) 317 self.with_db(|db| references::find_all_refs(db, position))
317 } 318 }
318 319
319 /// Returns a short text descrbing element at position. 320 /// Returns a short text describing element at position.
320 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { 321 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> {
321 self.with_db(|db| hover::hover(db, position)) 322 self.with_db(|db| hover::hover(db, position))
322 } 323 }
diff --git a/crates/ra_ide_api/src/mock_analysis.rs b/crates/ra_ide_api/src/mock_analysis.rs
index 8d8603062..550d69641 100644
--- a/crates/ra_ide_api/src/mock_analysis.rs
+++ b/crates/ra_ide_api/src/mock_analysis.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3use relative_path::RelativePathBuf; 3use relative_path::RelativePathBuf;
4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; 4use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
5 5
6use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId}; 6use crate::{Analysis, AnalysisChange, AnalysisHost, CrateGraph, FileId, FilePosition, FileRange, SourceRootId, Edition::Edition2018};
7 7
8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis 8/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
9/// from a set of in-memory files. 9/// from a set of in-memory files.
@@ -18,7 +18,7 @@ impl MockAnalysis {
18 } 18 }
19 /// Creates `MockAnalysis` using a fixture data in the following format: 19 /// Creates `MockAnalysis` using a fixture data in the following format:
20 /// 20 ///
21 /// ```notrust 21 /// ```rust,ignore
22 /// //- /main.rs 22 /// //- /main.rs
23 /// mod foo; 23 /// mod foo;
24 /// fn main() {} 24 /// fn main() {}
@@ -89,9 +89,9 @@ impl MockAnalysis {
89 let path = RelativePathBuf::from_path(&path[1..]).unwrap(); 89 let path = RelativePathBuf::from_path(&path[1..]).unwrap();
90 let file_id = FileId(i as u32 + 1); 90 let file_id = FileId(i as u32 + 1);
91 if path == "/lib.rs" || path == "/main.rs" { 91 if path == "/lib.rs" || path == "/main.rs" {
92 root_crate = Some(crate_graph.add_crate_root(file_id)); 92 root_crate = Some(crate_graph.add_crate_root(file_id, Edition2018));
93 } else if path.ends_with("/lib.rs") { 93 } else if path.ends_with("/lib.rs") {
94 let other_crate = crate_graph.add_crate_root(file_id); 94 let other_crate = crate_graph.add_crate_root(file_id, Edition2018);
95 let crate_name = path.parent().unwrap().file_name().unwrap(); 95 let crate_name = path.parent().unwrap().file_name().unwrap();
96 if let Some(root_crate) = root_crate { 96 if let Some(root_crate) = root_crate {
97 crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap(); 97 crate_graph.add_dep(root_crate, crate_name.into(), other_crate).unwrap();
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs
index a2e4b6506..c559dca11 100644
--- a/crates/ra_ide_api/src/navigation_target.rs
+++ b/crates/ra_ide_api/src/navigation_target.rs
@@ -19,6 +19,7 @@ pub struct NavigationTarget {
19 kind: SyntaxKind, 19 kind: SyntaxKind,
20 full_range: TextRange, 20 full_range: TextRange,
21 focus_range: Option<TextRange>, 21 focus_range: Option<TextRange>,
22 container_name: Option<SmolStr>,
22} 23}
23 24
24impl NavigationTarget { 25impl NavigationTarget {
@@ -26,6 +27,10 @@ impl NavigationTarget {
26 &self.name 27 &self.name
27 } 28 }
28 29
30 pub fn container_name(&self) -> Option<&SmolStr> {
31 self.container_name.as_ref()
32 }
33
29 pub fn kind(&self) -> SyntaxKind { 34 pub fn kind(&self) -> SyntaxKind {
30 self.kind 35 self.kind
31 } 36 }
@@ -53,6 +58,7 @@ impl NavigationTarget {
53 kind: symbol.ptr.kind(), 58 kind: symbol.ptr.kind(),
54 full_range: symbol.ptr.range(), 59 full_range: symbol.ptr.range(),
55 focus_range: None, 60 focus_range: None,
61 container_name: symbol.container_name.clone(),
56 } 62 }
57 } 63 }
58 64
@@ -67,6 +73,7 @@ impl NavigationTarget {
67 full_range: ptr.range(), 73 full_range: ptr.range(),
68 focus_range: None, 74 focus_range: None,
69 kind: NAME, 75 kind: NAME,
76 container_name: None,
70 } 77 }
71 } 78 }
72 79
@@ -170,6 +177,9 @@ impl NavigationTarget {
170 if let Some(focus_range) = self.focus_range() { 177 if let Some(focus_range) = self.focus_range() {
171 buf.push_str(&format!(" {:?}", focus_range)) 178 buf.push_str(&format!(" {:?}", focus_range))
172 } 179 }
180 if let Some(container_name) = self.container_name() {
181 buf.push_str(&format!(" {:?}", container_name))
182 }
173 buf 183 buf
174 } 184 }
175 185
@@ -192,6 +202,7 @@ impl NavigationTarget {
192 full_range: node.range(), 202 full_range: node.range(),
193 focus_range, 203 focus_range,
194 // ptr: Some(LocalSyntaxPtr::new(node)), 204 // ptr: Some(LocalSyntaxPtr::new(node)),
205 container_name: None,
195 } 206 }
196 } 207 }
197} 208}
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 2cb1cc9be..ca145f3e4 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -295,17 +295,17 @@ mod tests {
295 fn test_rename(text: &str, new_name: &str, expected: &str) { 295 fn test_rename(text: &str, new_name: &str, expected: &str) {
296 let (analysis, position) = single_file_with_position(text); 296 let (analysis, position) = single_file_with_position(text);
297 let source_change = analysis.rename(position, new_name).unwrap(); 297 let source_change = analysis.rename(position, new_name).unwrap();
298 let mut text_edit_bulder = ra_text_edit::TextEditBuilder::default(); 298 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
299 let mut file_id: Option<FileId> = None; 299 let mut file_id: Option<FileId> = None;
300 if let Some(change) = source_change { 300 if let Some(change) = source_change {
301 for edit in change.source_file_edits { 301 for edit in change.source_file_edits {
302 file_id = Some(edit.file_id); 302 file_id = Some(edit.file_id);
303 for atom in edit.edit.as_atoms() { 303 for atom in edit.edit.as_atoms() {
304 text_edit_bulder.replace(atom.delete, atom.insert.clone()); 304 text_edit_builder.replace(atom.delete, atom.insert.clone());
305 } 305 }
306 } 306 }
307 } 307 }
308 let result = text_edit_bulder.finish().apply(&*analysis.file_text(file_id.unwrap())); 308 let result = text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()));
309 assert_eq_text!(expected, &*result); 309 assert_eq_text!(expected, &*result);
310 } 310 }
311} 311}
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index de0f46134..afb10fa92 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -5,20 +5,20 @@
5//! symbols. The backbone of the index is the **awesome** `fst` crate by 5//! symbols. The backbone of the index is the **awesome** `fst` crate by
6//! @BurntSushi. 6//! @BurntSushi.
7//! 7//!
8//! In a nutshell, you give a set of strings to the `fst`, and it builds a 8//! In a nutshell, you give a set of strings to `fst`, and it builds a
9//! finite state machine describing this set of strings. The strings which 9//! finite state machine describing this set of strings. The strings which
10//! could fuzzy-match a pattern can also be described by a finite state machine. 10//! could fuzzy-match a pattern can also be described by a finite state machine.
11//! What is freakingly cool is that you can now traverse both state machines in 11//! What is freaking cool is that you can now traverse both state machines in
12//! lock-step to enumerate the strings which are both in the input set and 12//! lock-step to enumerate the strings which are both in the input set and
13//! fuzz-match the query. Or, more formally, given two languages described by 13//! fuzz-match the query. Or, more formally, given two languages described by
14//! fsts, one can build an product fst which describes the intersection of the 14//! FSTs, one can build a product FST which describes the intersection of the
15//! languages. 15//! languages.
16//! 16//!
17//! `fst` does not support cheap updating of the index, but it supports unioning 17//! `fst` does not support cheap updating of the index, but it supports unioning
18//! of state machines. So, to account for changing source code, we build an fst 18//! of state machines. So, to account for changing source code, we build an FST
19//! for each library (which is assumed to never change) and an fst for each rust 19//! for each library (which is assumed to never change) and an FST for each Rust
20//! file in the current workspace, and run a query against the union of all 20//! file in the current workspace, and run a query against the union of all
21//! those fsts. 21//! those FSTs.
22use std::{ 22use std::{
23 cmp::Ordering, 23 cmp::Ordering,
24 hash::{Hash, Hasher}, 24 hash::{Hash, Hasher},
@@ -32,6 +32,7 @@ use ra_syntax::{
32 algo::{visit::{visitor, Visitor}, find_covering_node}, 32 algo::{visit::{visitor, Visitor}, find_covering_node},
33 SyntaxKind::{self, *}, 33 SyntaxKind::{self, *},
34 ast::{self, NameOwner}, 34 ast::{self, NameOwner},
35 WalkEvent,
35}; 36};
36use ra_db::{ 37use ra_db::{
37 SourceRootId, SourceDatabase, 38 SourceRootId, SourceDatabase,
@@ -62,17 +63,14 @@ pub(crate) trait SymbolsDatabase: hir::db::HirDatabase {
62fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> { 63fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
63 db.check_canceled(); 64 db.check_canceled();
64 let source_file = db.parse(file_id); 65 let source_file = db.parse(file_id);
65 let mut symbols = source_file 66
66 .syntax() 67 let mut symbols = source_file_to_file_symbols(&source_file, file_id);
67 .descendants()
68 .filter_map(to_symbol)
69 .map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
70 .collect::<Vec<_>>();
71 68
72 for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) { 69 for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) {
73 let node = find_covering_node(source_file.syntax(), text_range); 70 let node = find_covering_node(source_file.syntax(), text_range);
74 let ptr = SyntaxNodePtr::new(node); 71 let ptr = SyntaxNodePtr::new(node);
75 symbols.push(FileSymbol { file_id, name, ptr }) 72 // TODO: Should we get container name for macro symbols?
73 symbols.push(FileSymbol { file_id, name, ptr, container_name: None })
76 } 74 }
77 75
78 Arc::new(SymbolIndex::new(symbols)) 76 Arc::new(SymbolIndex::new(symbols))
@@ -158,13 +156,7 @@ impl SymbolIndex {
158 files: impl ParallelIterator<Item = (FileId, TreeArc<SourceFile>)>, 156 files: impl ParallelIterator<Item = (FileId, TreeArc<SourceFile>)>,
159 ) -> SymbolIndex { 157 ) -> SymbolIndex {
160 let symbols = files 158 let symbols = files
161 .flat_map(|(file_id, file)| { 159 .flat_map(|(file_id, file)| source_file_to_file_symbols(&file, file_id))
162 file.syntax()
163 .descendants()
164 .filter_map(to_symbol)
165 .map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
166 .collect::<Vec<_>>()
167 })
168 .collect::<Vec<_>>(); 160 .collect::<Vec<_>>();
169 SymbolIndex::new(symbols) 161 SymbolIndex::new(symbols)
170 } 162 }
@@ -215,12 +207,40 @@ pub(crate) struct FileSymbol {
215 pub(crate) file_id: FileId, 207 pub(crate) file_id: FileId,
216 pub(crate) name: SmolStr, 208 pub(crate) name: SmolStr,
217 pub(crate) ptr: SyntaxNodePtr, 209 pub(crate) ptr: SyntaxNodePtr,
210 pub(crate) container_name: Option<SmolStr>,
211}
212
213fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec<FileSymbol> {
214 let mut symbols = Vec::new();
215 let mut stack = Vec::new();
216
217 for event in source_file.syntax().preorder() {
218 match event {
219 WalkEvent::Enter(node) => {
220 if let Some(mut symbol) = to_file_symbol(node, file_id) {
221 symbol.container_name = stack.last().cloned();
222
223 stack.push(symbol.name.clone());
224 symbols.push(symbol);
225 }
226 }
227
228 WalkEvent::Leave(node) => {
229 if to_symbol(node).is_some() {
230 stack.pop();
231 }
232 }
233 }
234 }
235
236 symbols
218} 237}
219 238
220fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> { 239fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
221 fn decl<N: NameOwner>(node: &N) -> Option<(SmolStr, SyntaxNodePtr)> { 240 fn decl<N: NameOwner>(node: &N) -> Option<(SmolStr, SyntaxNodePtr)> {
222 let name = node.name()?.text().clone(); 241 let name = node.name()?.text().clone();
223 let ptr = SyntaxNodePtr::new(node.syntax()); 242 let ptr = SyntaxNodePtr::new(node.syntax());
243
224 Some((name, ptr)) 244 Some((name, ptr))
225 } 245 }
226 visitor() 246 visitor()
@@ -234,3 +254,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
234 .visit(decl::<ast::StaticDef>) 254 .visit(decl::<ast::StaticDef>)
235 .accept(node)? 255 .accept(node)?
236} 256}
257
258fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
259 to_symbol(node).map(move |(name, ptr)| FileSymbol { name, ptr, file_id, container_name: None })
260}