Skip to content

Commit 65266c6

Browse files
bors[bot]vipentti
andcommitted
Merge #813
813: Add support for container_name in workspace/symbol query r=matklad a=vipentti Currently this does not fill in the container_info if a type is defined on the top level in a file. e.g. `foo.rs` ```rust enum Foo { } ``` `Foo` will have None as the container_name, however ```rust mod foo_mod { enum Foo { } } ``` `Foo` has `foo_mod` as the container_name. This closes #559 Co-authored-by: Ville Penttinen <[email protected]>
2 parents 74d03d5 + 3973974 commit 65266c6

File tree

4 files changed

+100
-17
lines changed

4 files changed

+100
-17
lines changed

crates/ra_ide_api/src/navigation_target.rs

+11
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.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

+38-14
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
}
@@ -215,12 +207,40 @@ pub(crate) struct FileSymbol {
215207
pub(crate) file_id: FileId,
216208
pub(crate) name: SmolStr,
217209
pub(crate) ptr: SyntaxNodePtr,
210+
pub(crate) container_name: Option<SmolStr>,
211+
}
212+
213+
fn 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
218237
}
219238

220239
fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
221240
fn decl<N: NameOwner>(node: &N) -> Option<(SmolStr, SyntaxNodePtr)> {
222241
let name = node.name()?.text().clone();
223242
let ptr = SyntaxNodePtr::new(node.syntax());
243+
224244
Some((name, ptr))
225245
}
226246
visitor()
@@ -234,3 +254,7 @@ fn to_symbol(node: &SyntaxNode) -> Option<(SmolStr, SyntaxNodePtr)> {
234254
.visit(decl::<ast::StaticDef>)
235255
.accept(node)?
236256
}
257+
258+
fn 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+
}

crates/ra_ide_api/tests/test/main.rs

+50-2
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,49 @@ 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+
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]
113+
fn test_world_symbols_include_container_name() {
114+
let code = r#"
115+
fn 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#"
128+
mod 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+
93141
#[test]
94142
#[ignore]
95143
fn world_symbols_include_stuff_from_macros() {

crates/ra_lsp_server/src/main_loop/handlers.rs

+1-1
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)