aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide_api/src/navigation_target.rs11
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs52
-rw-r--r--crates/ra_ide_api/tests/test/main.rs52
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs2
4 files changed, 100 insertions, 17 deletions
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/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index 15348124b..afb10fa92 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -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}
diff --git a/crates/ra_ide_api/tests/test/main.rs b/crates/ra_ide_api/tests/test/main.rs
index 7d1695cfd..4cf842452 100644
--- a/crates/ra_ide_api/tests/test/main.rs
+++ b/crates/ra_ide_api/tests/test/main.rs
@@ -1,9 +1,9 @@
1use insta::assert_debug_snapshot_matches; 1use insta::assert_debug_snapshot_matches;
2use ra_ide_api::{ 2use ra_ide_api::{
3 mock_analysis::{single_file, single_file_with_position, MockAnalysis}, 3 mock_analysis::{single_file, single_file_with_position, MockAnalysis},
4 AnalysisChange, CrateGraph, FileId, Query, 4 AnalysisChange, CrateGraph, FileId, Query, NavigationTarget,
5}; 5};
6use ra_syntax::TextRange; 6use ra_syntax::{TextRange, SmolStr};
7 7
8#[test] 8#[test]
9fn test_unresolved_module_diagnostic() { 9fn test_unresolved_module_diagnostic() {
@@ -49,6 +49,11 @@ fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
49 analysis.find_all_refs(position).unwrap() 49 analysis.find_all_refs(position).unwrap()
50} 50}
51 51
52fn get_symbols_matching(text: &str, query: &str) -> Vec<NavigationTarget> {
53 let (analysis, _) = single_file(text);
54 analysis.symbol_search(Query::new(query.into())).unwrap()
55}
56
52#[test] 57#[test]
53fn test_find_all_refs_for_local() { 58fn test_find_all_refs_for_local() {
54 let code = r#" 59 let code = r#"
@@ -91,6 +96,49 @@ fn test_find_all_refs_for_fn_param() {
91} 96}
92 97
93#[test] 98#[test]
99fn test_world_symbols_with_no_container() {
100 let code = r#"
101 enum FooInner { }
102 "#;
103
104 let mut symbols = get_symbols_matching(code, "FooInner");
105
106 let s = symbols.pop().unwrap();
107
108 assert_eq!(s.name(), "FooInner");
109 assert!(s.container_name().is_none());
110}
111
112#[test]
113fn test_world_symbols_include_container_name() {
114 let code = r#"
115fn foo() {
116 enum FooInner { }
117}
118 "#;
119
120 let mut symbols = get_symbols_matching(code, "FooInner");
121
122 let s = symbols.pop().unwrap();
123
124 assert_eq!(s.name(), "FooInner");
125 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
126
127 let code = r#"
128mod foo {
129 struct FooInner;
130}
131 "#;
132
133 let mut symbols = get_symbols_matching(code, "FooInner");
134
135 let s = symbols.pop().unwrap();
136
137 assert_eq!(s.name(), "FooInner");
138 assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
139}
140
141#[test]
94#[ignore] 142#[ignore]
95fn world_symbols_include_stuff_from_macros() { 143fn world_symbols_include_stuff_from_macros() {
96 let (analysis, _) = single_file( 144 let (analysis, _) = single_file(
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 0cdb39c32..09d896c40 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -190,7 +190,7 @@ pub fn handle_workspace_symbol(
190 name: nav.name().to_string(), 190 name: nav.name().to_string(),
191 kind: nav.kind().conv(), 191 kind: nav.kind().conv(),
192 location: nav.try_conv_with(world)?, 192 location: nav.try_conv_with(world)?,
193 container_name: None, 193 container_name: nav.container_name().map(|v| v.to_string()),
194 deprecated: None, 194 deprecated: None,
195 }; 195 };
196 res.push(info); 196 res.push(info);