aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src/symbol_index.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src/symbol_index.rs')
-rw-r--r--crates/ra_analysis/src/symbol_index.rs123
1 files changed, 119 insertions, 4 deletions
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index e5bdf0aa1..edb2268fb 100644
--- a/crates/ra_analysis/src/symbol_index.rs
+++ b/crates/ra_analysis/src/symbol_index.rs
@@ -4,10 +4,11 @@ use std::{
4}; 4};
5 5
6use fst::{self, Streamer}; 6use fst::{self, Streamer};
7use ra_editor::{self, FileSymbol};
8use ra_syntax::{ 7use ra_syntax::{
9 SourceFileNode, 8 AstNode, SyntaxNodeRef, SourceFileNode, SmolStr, TextRange,
9 algo::visit::{visitor, Visitor},
10 SyntaxKind::{self, *}, 10 SyntaxKind::{self, *},
11 ast::{self, NameOwner, DocCommentsOwner},
11}; 12};
12use ra_db::{SyntaxDatabase, SourceRootId}; 13use ra_db::{SyntaxDatabase, SourceRootId};
13use rayon::prelude::*; 14use rayon::prelude::*;
@@ -65,8 +66,9 @@ impl SymbolIndex {
65 ) -> SymbolIndex { 66 ) -> SymbolIndex {
66 let mut symbols = files 67 let mut symbols = files
67 .flat_map(|(file_id, file)| { 68 .flat_map(|(file_id, file)| {
68 ra_editor::file_symbols(&file) 69 file.syntax()
69 .into_iter() 70 .descendants()
71 .filter_map(to_symbol)
70 .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol))) 72 .map(move |symbol| (symbol.name.as_str().to_lowercase(), (file_id, symbol)))
71 .collect::<Vec<_>>() 73 .collect::<Vec<_>>()
72 }) 74 })
@@ -121,3 +123,116 @@ fn is_type(kind: SyntaxKind) -> bool {
121 _ => false, 123 _ => false,
122 } 124 }
123} 125}
126
127#[derive(Debug, Clone, PartialEq, Eq, Hash)]
128pub struct FileSymbol {
129 pub name: SmolStr,
130 pub node_range: TextRange,
131 pub kind: SyntaxKind,
132}
133
134impl FileSymbol {
135 pub fn docs(&self, file: &SourceFileNode) -> Option<String> {
136 file.syntax()
137 .descendants()
138 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
139 .filter_map(|node: SyntaxNodeRef| {
140 fn doc_comments<'a, N: DocCommentsOwner<'a>>(node: N) -> Option<String> {
141 let comments = node.doc_comment_text();
142 if comments.is_empty() {
143 None
144 } else {
145 Some(comments)
146 }
147 }
148
149 visitor()
150 .visit(doc_comments::<ast::FnDef>)
151 .visit(doc_comments::<ast::StructDef>)
152 .visit(doc_comments::<ast::EnumDef>)
153 .visit(doc_comments::<ast::TraitDef>)
154 .visit(doc_comments::<ast::Module>)
155 .visit(doc_comments::<ast::TypeDef>)
156 .visit(doc_comments::<ast::ConstDef>)
157 .visit(doc_comments::<ast::StaticDef>)
158 .accept(node)?
159 })
160 .nth(0)
161 }
162 /// Get a description of this node.
163 ///
164 /// e.g. `struct Name`, `enum Name`, `fn Name`
165 pub fn description(&self, file: &SourceFileNode) -> Option<String> {
166 // TODO: After type inference is done, add type information to improve the output
167 file.syntax()
168 .descendants()
169 .filter(|node| node.kind() == self.kind && node.range() == self.node_range)
170 .filter_map(|node: SyntaxNodeRef| {
171 // TODO: Refactor to be have less repetition
172 visitor()
173 .visit(|node: ast::FnDef| {
174 let mut string = "fn ".to_string();
175 node.name()?.syntax().text().push_to(&mut string);
176 Some(string)
177 })
178 .visit(|node: ast::StructDef| {
179 let mut string = "struct ".to_string();
180 node.name()?.syntax().text().push_to(&mut string);
181 Some(string)
182 })
183 .visit(|node: ast::EnumDef| {
184 let mut string = "enum ".to_string();
185 node.name()?.syntax().text().push_to(&mut string);
186 Some(string)
187 })
188 .visit(|node: ast::TraitDef| {
189 let mut string = "trait ".to_string();
190 node.name()?.syntax().text().push_to(&mut string);
191 Some(string)
192 })
193 .visit(|node: ast::Module| {
194 let mut string = "mod ".to_string();
195 node.name()?.syntax().text().push_to(&mut string);
196 Some(string)
197 })
198 .visit(|node: ast::TypeDef| {
199 let mut string = "type ".to_string();
200 node.name()?.syntax().text().push_to(&mut string);
201 Some(string)
202 })
203 .visit(|node: ast::ConstDef| {
204 let mut string = "const ".to_string();
205 node.name()?.syntax().text().push_to(&mut string);
206 Some(string)
207 })
208 .visit(|node: ast::StaticDef| {
209 let mut string = "static ".to_string();
210 node.name()?.syntax().text().push_to(&mut string);
211 Some(string)
212 })
213 .accept(node)?
214 })
215 .nth(0)
216 }
217}
218
219fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
220 fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<FileSymbol> {
221 let name = node.name()?;
222 Some(FileSymbol {
223 name: name.text(),
224 node_range: node.syntax().range(),
225 kind: node.syntax().kind(),
226 })
227 }
228 visitor()
229 .visit(decl::<ast::FnDef>)
230 .visit(decl::<ast::StructDef>)
231 .visit(decl::<ast::EnumDef>)
232 .visit(decl::<ast::TraitDef>)
233 .visit(decl::<ast::Module>)
234 .visit(decl::<ast::TypeDef>)
235 .visit(decl::<ast::ConstDef>)
236 .visit(decl::<ast::StaticDef>)
237 .accept(node)?
238}