Skip to content

Commit dd6307d

Browse files
committed
Add support for container_name in workspace/symbol query
1 parent 61324a8 commit dd6307d

File tree

4 files changed

+116
-17
lines changed

4 files changed

+116
-17
lines changed

crates/ra_ide_api/src/navigation_target.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,18 @@ pub struct NavigationTarget {
1919
kind: SyntaxKind,
2020
full_range: TextRange,
2121
focus_range: Option<TextRange>,
22+
container_name: Option<SmolStr>,
2223
}
2324

2425
impl NavigationTarget {
2526
pub fn name(&self) -> &SmolStr {
2627
&self.name
2728
}
2829

30+
pub fn container_name(&self) -> Option<&SmolStr> {
31+
self.container_name.as_ref()
32+
}
33+
2934
pub fn kind(&self) -> SyntaxKind {
3035
self.kind
3136
}
@@ -53,6 +58,7 @@ impl NavigationTarget {
5358
kind: symbol.ptr.kind(),
5459
full_range: symbol.ptr.range(),
5560
focus_range: None,
61+
container_name: symbol.container_name.map(|v| v.clone()),
5662
}
5763
}
5864

@@ -67,6 +73,7 @@ impl NavigationTarget {
6773
full_range: ptr.range(),
6874
focus_range: None,
6975
kind: NAME,
76+
container_name: None,
7077
}
7178
}
7279

@@ -170,6 +177,9 @@ impl NavigationTarget {
170177
if let Some(focus_range) = self.focus_range() {
171178
buf.push_str(&format!(" {:?}", focus_range))
172179
}
180+
if let Some(container_name) = self.container_name() {
181+
buf.push_str(&format!(" {:?}", container_name))
182+
}
173183
buf
174184
}
175185

@@ -192,6 +202,7 @@ impl NavigationTarget {
192202
full_range: node.range(),
193203
focus_range,
194204
// ptr: Some(LocalSyntaxPtr::new(node)),
205+
container_name: None,
195206
}
196207
}
197208
}

crates/ra_ide_api/src/symbol_index.rs

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use ra_syntax::{
3232
algo::{visit::{visitor, Visitor}, find_covering_node},
3333
SyntaxKind::{self, *},
3434
ast::{self, NameOwner},
35+
WalkEvent,
3536
};
3637
use ra_db::{
3738
SourceRootId, SourceDatabase,
@@ -62,17 +63,14 @@ pub(crate) trait SymbolsDatabase: hir::db::HirDatabase {
6263
fn file_symbols(db: &impl SymbolsDatabase, file_id: FileId) -> Arc<SymbolIndex> {
6364
db.check_canceled();
6465
let source_file = db.parse(file_id);
65-
let mut symbols = source_file
66-
.syntax()
67-
.descendants()
68-
.filter_map(to_symbol)
69-
.map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
70-
.collect::<Vec<_>>();
66+
67+
let mut symbols = source_file_to_file_symbols(&source_file, file_id);
7168

7269
for (name, text_range) in hir::source_binder::macro_symbols(db, file_id) {
7370
let node = find_covering_node(source_file.syntax(), text_range);
7471
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 })
7674
}
7775

7876
Arc::new(SymbolIndex::new(symbols))
@@ -158,13 +156,7 @@ impl SymbolIndex {
158156
files: impl ParallelIterator<Item = (FileId, TreeArc<SourceFile>)>,
159157
) -> SymbolIndex {
160158
let symbols = files
161-
.flat_map(|(file_id, file)| {
162-
file.syntax()
163-
.descendants()
164-
.filter_map(to_symbol)
165-
.map(move |(name, ptr)| FileSymbol { name, ptr, file_id })
166-
.collect::<Vec<_>>()
167-
})
159+
.flat_map(|(file_id, file)| source_file_to_file_symbols(&file, file_id))
168160
.collect::<Vec<_>>();
169161
SymbolIndex::new(symbols)
170162
}
@@ -208,19 +200,57 @@ fn is_type(kind: SyntaxKind) -> bool {
208200
}
209201
}
210202

203+
fn is_symbol_def(kind: SyntaxKind) -> bool {
204+
match kind {
205+
FN_DEF | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | MODULE | TYPE_DEF | CONST_DEF | STATIC_DEF => {
206+
true
207+
}
208+
209+
_ => false,
210+
}
211+
}
212+
211213
/// The actual data that is stored in the index. It should be as compact as
212214
/// possible.
213215
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
214216
pub(crate) struct FileSymbol {
215217
pub(crate) file_id: FileId,
216218
pub(crate) name: SmolStr,
217219
pub(crate) ptr: SyntaxNodePtr,
220+
pub(crate) container_name: Option<SmolStr>,
221+
}
222+
223+
fn source_file_to_file_symbols(source_file: &SourceFile, file_id: FileId) -> Vec<FileSymbol> {
224+
let mut symbols = Vec::new();
225+
let mut stack = Vec::new();
226+
227+
for event in source_file.syntax().preorder() {
228+
match event {
229+
WalkEvent::Enter(node) => {
230+
if let Some(mut symbol) = to_file_symbol(node, file_id) {
231+
symbol.container_name = stack.last().map(|v: &SmolStr| v.clone());
232+
233+
stack.push(symbol.name.clone());
234+
symbols.push(symbol);
235+
}
236+
}
237+
238+
WalkEvent::Leave(node) => {
239+
if is_symbol_def(node.kind()) {
240+
stack.pop();
241+
}
242+
}
243+
}
244+
}
245+
246+
symbols
218247
}
219248

220249
fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
221250
fn decl<N: NameOwner>(node: &N) -> Option<(SmolStr, SyntaxNodePtr)> {
222251
let name = node.name()?.text().clone();
223252
let ptr = SyntaxNodePtr::new(node.syntax());
253+
224254
Some((name, ptr))
225255
}
226256
visitor()
@@ -234,3 +264,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
234264
.visit(decl::<ast::StaticDef>)
235265
.accept(node)?
236266
}
267+
268+
fn to_file_symbol(node: &SyntaxNode, file_id: FileId) -> Option<FileSymbol> {
269+
to_symbol(node).map(move |(name, ptr)| FileSymbol { name, ptr, file_id, container_name: None })
270+
}

crates/ra_ide_api/tests/test/main.rs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use insta::assert_debug_snapshot_matches;
22
use ra_ide_api::{
33
mock_analysis::{single_file, single_file_with_position, MockAnalysis},
4-
AnalysisChange, CrateGraph, FileId, Query,
4+
AnalysisChange, CrateGraph, FileId, Query, NavigationTarget,
55
};
6-
use ra_syntax::TextRange;
6+
use ra_syntax::{TextRange, SmolStr};
77

88
#[test]
99
fn test_unresolved_module_diagnostic() {
@@ -49,6 +49,11 @@ fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
4949
analysis.find_all_refs(position).unwrap()
5050
}
5151

52+
fn 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+
5257
#[test]
5358
fn test_find_all_refs_for_local() {
5459
let code = r#"
@@ -90,6 +95,55 @@ fn test_find_all_refs_for_fn_param() {
9095
assert_eq!(refs.len(), 2);
9196
}
9297

98+
#[test]
99+
fn test_world_symbols_with_no_container() {
100+
{
101+
let code = r#"
102+
enum FooInner { }
103+
"#;
104+
105+
let mut symbols = get_symbols_matching(code, "FooInner");
106+
107+
let s = symbols.pop().unwrap();
108+
109+
assert_eq!(s.name(), "FooInner");
110+
assert!(s.container_name().is_none());
111+
}
112+
}
113+
114+
#[test]
115+
fn test_world_symbols_include_container_name() {
116+
{
117+
let code = r#"
118+
fn foo() {
119+
enum FooInner { }
120+
}
121+
"#;
122+
123+
let mut symbols = get_symbols_matching(code, "FooInner");
124+
125+
let s = symbols.pop().unwrap();
126+
127+
assert_eq!(s.name(), "FooInner");
128+
assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
129+
}
130+
131+
{
132+
let code = r#"
133+
mod foo {
134+
struct FooInner;
135+
}
136+
"#;
137+
138+
let mut symbols = get_symbols_matching(code, "FooInner");
139+
140+
let s = symbols.pop().unwrap();
141+
142+
assert_eq!(s.name(), "FooInner");
143+
assert_eq!(s.container_name(), Some(&SmolStr::new("foo")));
144+
}
145+
}
146+
93147
#[test]
94148
#[ignore]
95149
fn world_symbols_include_stuff_from_macros() {

crates/ra_lsp_server/src/main_loop/handlers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ pub fn handle_workspace_symbol(
190190
name: nav.name().to_string(),
191191
kind: nav.kind().conv(),
192192
location: nav.try_conv_with(world)?,
193-
container_name: None,
193+
container_name: nav.container_name().map(|v| v.to_string()),
194194
deprecated: None,
195195
};
196196
res.push(info);

0 commit comments

Comments
 (0)