aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r--crates/ra_analysis/src/imp.rs18
-rw-r--r--crates/ra_analysis/src/lib.rs49
-rw-r--r--crates/ra_analysis/src/symbol_index.rs123
3 files changed, 166 insertions, 24 deletions
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs
index ec7da437a..8071554a7 100644
--- a/crates/ra_analysis/src/imp.rs
+++ b/crates/ra_analysis/src/imp.rs
@@ -10,7 +10,7 @@ use hir::{
10 self, FnSignatureInfo, Problem, source_binder, 10 self, FnSignatureInfo, Problem, source_binder,
11}; 11};
12use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; 12use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase};
13use ra_editor::{self, FileSymbol, find_node_at_offset, LineIndex, LocalEdit, Severity}; 13use ra_editor::{self, find_node_at_offset, LineIndex, LocalEdit, Severity};
14use ra_syntax::{ 14use ra_syntax::{
15 algo::find_covering_node, 15 algo::find_covering_node,
16 ast::{self, ArgListOwner, Expr, FnDef, NameOwner}, 16 ast::{self, ArgListOwner, Expr, FnDef, NameOwner},
@@ -21,11 +21,11 @@ use ra_syntax::{
21 21
22use crate::{ 22use crate::{
23 AnalysisChange, 23 AnalysisChange,
24 Cancelable, 24 Cancelable, NavigationTarget,
25 completion::{CompletionItem, completions}, 25 completion::{CompletionItem, completions},
26 CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit, 26 CrateId, db, Diagnostic, FileId, FilePosition, FileRange, FileSystemEdit,
27 Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit, 27 Query, ReferenceResolution, RootChange, SourceChange, SourceFileEdit,
28 symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase}, 28 symbol_index::{LibrarySymbolsQuery, SymbolIndex, SymbolsDatabase, FileSymbol},
29}; 29};
30 30
31#[derive(Debug, Default)] 31#[derive(Debug, Default)]
@@ -205,7 +205,7 @@ impl AnalysisImpl {
205 205
206 /// This returns `Vec` because a module may be included from several places. We 206 /// This returns `Vec` because a module may be included from several places. We
207 /// don't handle this case yet though, so the Vec has length at most one. 207 /// don't handle this case yet though, so the Vec has length at most one.
208 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 208 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> {
209 let descr = match source_binder::module_from_position(&*self.db, position)? { 209 let descr = match source_binder::module_from_position(&*self.db, position)? {
210 None => return Ok(Vec::new()), 210 None => return Ok(Vec::new()),
211 Some(it) => it, 211 Some(it) => it,
@@ -216,12 +216,12 @@ impl AnalysisImpl {
216 }; 216 };
217 let decl = decl.borrowed(); 217 let decl = decl.borrowed();
218 let decl_name = decl.name().unwrap(); 218 let decl_name = decl.name().unwrap();
219 let sym = FileSymbol { 219 let symbol = FileSymbol {
220 name: decl_name.text(), 220 name: decl_name.text(),
221 node_range: decl_name.syntax().range(), 221 node_range: decl_name.syntax().range(),
222 kind: MODULE, 222 kind: MODULE,
223 }; 223 };
224 Ok(vec![(file_id, sym)]) 224 Ok(vec![NavigationTarget { file_id, symbol }])
225 } 225 }
226 /// Returns `Vec` for the same reason as `parent_module` 226 /// Returns `Vec` for the same reason as `parent_module`
227 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { 227 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
@@ -355,9 +355,9 @@ impl AnalysisImpl {
355 Ok(Some((binding, descr))) 355 Ok(Some((binding, descr)))
356 } 356 }
357 } 357 }
358 pub fn doc_text_for(&self, file_id: FileId, symbol: FileSymbol) -> Cancelable<Option<String>> { 358 pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> {
359 let file = self.db.source_file(file_id); 359 let file = self.db.source_file(nav.file_id);
360 let result = match (symbol.description(&file), symbol.docs(&file)) { 360 let result = match (nav.symbol.description(&file), nav.symbol.docs(&file)) {
361 (Some(desc), Some(docs)) => { 361 (Some(desc), Some(docs)) => {
362 Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs) 362 Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs)
363 } 363 }
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs
index 08ecb125a..9576453ab 100644
--- a/crates/ra_analysis/src/lib.rs
+++ b/crates/ra_analysis/src/lib.rs
@@ -23,22 +23,22 @@ mod syntax_highlighting;
23use std::{fmt, sync::Arc}; 23use std::{fmt, sync::Arc};
24 24
25use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
26use ra_syntax::{SourceFileNode, TextRange, TextUnit}; 26use ra_syntax::{SourceFileNode, TextRange, TextUnit, SmolStr, SyntaxKind};
27use ra_text_edit::TextEdit; 27use ra_text_edit::TextEdit;
28use rayon::prelude::*; 28use rayon::prelude::*;
29use relative_path::RelativePathBuf; 29use relative_path::RelativePathBuf;
30 30
31use crate::{ 31use crate::{
32 imp::{AnalysisHostImpl, AnalysisImpl}, 32 imp::{AnalysisHostImpl, AnalysisImpl},
33 symbol_index::SymbolIndex, 33 symbol_index::{SymbolIndex, FileSymbol},
34}; 34};
35 35
36pub use crate::{ 36pub use crate::{
37 completion::{CompletionItem, CompletionItemKind, InsertText}, 37 completion::{CompletionItem, CompletionItemKind, InsertText},
38 runnables::{Runnable, RunnableKind} 38 runnables::{Runnable, RunnableKind},
39}; 39};
40pub use ra_editor::{ 40pub use ra_editor::{
41 FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, StructureNode, Severity 41 Fold, FoldKind, HighlightedRange, LineIndex, StructureNode, Severity
42}; 42};
43pub use hir::FnSignatureInfo; 43pub use hir::FnSignatureInfo;
44 44
@@ -242,6 +242,27 @@ impl Query {
242 } 242 }
243} 243}
244 244
245#[derive(Debug)]
246pub struct NavigationTarget {
247 file_id: FileId,
248 symbol: FileSymbol,
249}
250
251impl NavigationTarget {
252 pub fn name(&self) -> SmolStr {
253 self.symbol.name.clone()
254 }
255 pub fn kind(&self) -> SyntaxKind {
256 self.symbol.kind
257 }
258 pub fn file_id(&self) -> FileId {
259 self.file_id
260 }
261 pub fn range(&self) -> TextRange {
262 self.symbol.node_range
263 }
264}
265
245/// Result of "goto def" query. 266/// Result of "goto def" query.
246#[derive(Debug)] 267#[derive(Debug)]
247pub struct ReferenceResolution { 268pub struct ReferenceResolution {
@@ -250,7 +271,7 @@ pub struct ReferenceResolution {
250 /// client where the reference was. 271 /// client where the reference was.
251 pub reference_range: TextRange, 272 pub reference_range: TextRange,
252 /// What this reference resolves to. 273 /// What this reference resolves to.
253 pub resolves_to: Vec<(FileId, FileSymbol)>, 274 pub resolves_to: Vec<NavigationTarget>,
254} 275}
255 276
256impl ReferenceResolution { 277impl ReferenceResolution {
@@ -262,7 +283,7 @@ impl ReferenceResolution {
262 } 283 }
263 284
264 fn add_resolution(&mut self, file_id: FileId, symbol: FileSymbol) { 285 fn add_resolution(&mut self, file_id: FileId, symbol: FileSymbol) {
265 self.resolves_to.push((file_id, symbol)) 286 self.resolves_to.push(NavigationTarget { file_id, symbol })
266 } 287 }
267} 288}
268 289
@@ -320,8 +341,14 @@ impl Analysis {
320 let file = self.imp.file_syntax(file_id); 341 let file = self.imp.file_syntax(file_id);
321 ra_editor::folding_ranges(&file) 342 ra_editor::folding_ranges(&file)
322 } 343 }
323 pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<(FileId, FileSymbol)>> { 344 pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> {
324 self.imp.world_symbols(query) 345 let res = self
346 .imp
347 .world_symbols(query)?
348 .into_iter()
349 .map(|(file_id, symbol)| NavigationTarget { file_id, symbol })
350 .collect();
351 Ok(res)
325 } 352 }
326 pub fn approximately_resolve_symbol( 353 pub fn approximately_resolve_symbol(
327 &self, 354 &self,
@@ -332,10 +359,10 @@ impl Analysis {
332 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { 359 pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> {
333 self.imp.find_all_refs(position) 360 self.imp.find_all_refs(position)
334 } 361 }
335 pub fn doc_text_for(&self, file_id: FileId, symbol: FileSymbol) -> Cancelable<Option<String>> { 362 pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> {
336 self.imp.doc_text_for(file_id, symbol) 363 self.imp.doc_text_for(nav)
337 } 364 }
338 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<(FileId, FileSymbol)>> { 365 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> {
339 self.imp.parent_module(position) 366 self.imp.parent_module(position)
340 } 367 }
341 pub fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> { 368 pub fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> {
diff --git a/crates/ra_analysis/src/symbol_index.rs b/crates/ra_analysis/src/symbol_index.rs
index e5bdf0aa1..56a84a850 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(crate) struct FileSymbol {
129 pub(crate) name: SmolStr,
130 pub(crate) node_range: TextRange,
131 pub(crate) kind: SyntaxKind,
132}
133
134impl FileSymbol {
135 pub(crate) 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(crate) 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}