diff options
Diffstat (limited to 'crates/ra_analysis/src')
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 18 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 49 | ||||
-rw-r--r-- | crates/ra_analysis/src/symbol_index.rs | 123 |
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 | }; |
12 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; | 12 | use ra_db::{FilesDatabase, SourceRoot, SourceRootId, SyntaxDatabase}; |
13 | use ra_editor::{self, FileSymbol, find_node_at_offset, LineIndex, LocalEdit, Severity}; | 13 | use ra_editor::{self, find_node_at_offset, LineIndex, LocalEdit, Severity}; |
14 | use ra_syntax::{ | 14 | use 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 | ||
22 | use crate::{ | 22 | use 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; | |||
23 | use std::{fmt, sync::Arc}; | 23 | use std::{fmt, sync::Arc}; |
24 | 24 | ||
25 | use rustc_hash::FxHashMap; | 25 | use rustc_hash::FxHashMap; |
26 | use ra_syntax::{SourceFileNode, TextRange, TextUnit}; | 26 | use ra_syntax::{SourceFileNode, TextRange, TextUnit, SmolStr, SyntaxKind}; |
27 | use ra_text_edit::TextEdit; | 27 | use ra_text_edit::TextEdit; |
28 | use rayon::prelude::*; | 28 | use rayon::prelude::*; |
29 | use relative_path::RelativePathBuf; | 29 | use relative_path::RelativePathBuf; |
30 | 30 | ||
31 | use crate::{ | 31 | use crate::{ |
32 | imp::{AnalysisHostImpl, AnalysisImpl}, | 32 | imp::{AnalysisHostImpl, AnalysisImpl}, |
33 | symbol_index::SymbolIndex, | 33 | symbol_index::{SymbolIndex, FileSymbol}, |
34 | }; | 34 | }; |
35 | 35 | ||
36 | pub use crate::{ | 36 | pub use crate::{ |
37 | completion::{CompletionItem, CompletionItemKind, InsertText}, | 37 | completion::{CompletionItem, CompletionItemKind, InsertText}, |
38 | runnables::{Runnable, RunnableKind} | 38 | runnables::{Runnable, RunnableKind}, |
39 | }; | 39 | }; |
40 | pub use ra_editor::{ | 40 | pub use ra_editor::{ |
41 | FileSymbol, Fold, FoldKind, HighlightedRange, LineIndex, StructureNode, Severity | 41 | Fold, FoldKind, HighlightedRange, LineIndex, StructureNode, Severity |
42 | }; | 42 | }; |
43 | pub use hir::FnSignatureInfo; | 43 | pub use hir::FnSignatureInfo; |
44 | 44 | ||
@@ -242,6 +242,27 @@ impl Query { | |||
242 | } | 242 | } |
243 | } | 243 | } |
244 | 244 | ||
245 | #[derive(Debug)] | ||
246 | pub struct NavigationTarget { | ||
247 | file_id: FileId, | ||
248 | symbol: FileSymbol, | ||
249 | } | ||
250 | |||
251 | impl 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)] |
247 | pub struct ReferenceResolution { | 268 | pub 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 | ||
256 | impl ReferenceResolution { | 277 | impl 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 | ||
6 | use fst::{self, Streamer}; | 6 | use fst::{self, Streamer}; |
7 | use ra_editor::{self, FileSymbol}; | ||
8 | use ra_syntax::{ | 7 | use 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 | }; |
12 | use ra_db::{SyntaxDatabase, SourceRootId}; | 13 | use ra_db::{SyntaxDatabase, SourceRootId}; |
13 | use rayon::prelude::*; | 14 | use 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)] | ||
128 | pub(crate) struct FileSymbol { | ||
129 | pub(crate) name: SmolStr, | ||
130 | pub(crate) node_range: TextRange, | ||
131 | pub(crate) kind: SyntaxKind, | ||
132 | } | ||
133 | |||
134 | impl 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 | |||
219 | fn 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 | } | ||