diff options
Diffstat (limited to 'crates/ra_analysis/src/lib.rs')
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 153 |
1 files changed, 92 insertions, 61 deletions
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 9576453ab..54eb2f4d3 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -27,11 +27,9 @@ 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 | use salsa::ParallelDatabase; | ||
30 | 31 | ||
31 | use crate::{ | 32 | use crate::symbol_index::{SymbolIndex, FileSymbol}; |
32 | imp::{AnalysisHostImpl, AnalysisImpl}, | ||
33 | symbol_index::{SymbolIndex, FileSymbol}, | ||
34 | }; | ||
35 | 33 | ||
36 | pub use crate::{ | 34 | pub use crate::{ |
37 | completion::{CompletionItem, CompletionItemKind, InsertText}, | 35 | completion::{CompletionItem, CompletionItemKind, InsertText}, |
@@ -44,7 +42,7 @@ pub use hir::FnSignatureInfo; | |||
44 | 42 | ||
45 | pub use ra_db::{ | 43 | pub use ra_db::{ |
46 | Canceled, Cancelable, FilePosition, FileRange, | 44 | Canceled, Cancelable, FilePosition, FileRange, |
47 | CrateGraph, CrateId, SourceRootId, FileId | 45 | CrateGraph, CrateId, SourceRootId, FileId, SyntaxDatabase, FilesDatabase |
48 | }; | 46 | }; |
49 | 47 | ||
50 | #[derive(Default)] | 48 | #[derive(Default)] |
@@ -150,27 +148,6 @@ impl AnalysisChange { | |||
150 | } | 148 | } |
151 | } | 149 | } |
152 | 150 | ||
153 | /// `AnalysisHost` stores the current state of the world. | ||
154 | #[derive(Debug, Default)] | ||
155 | pub struct AnalysisHost { | ||
156 | imp: AnalysisHostImpl, | ||
157 | } | ||
158 | |||
159 | impl AnalysisHost { | ||
160 | /// Returns a snapshot of the current state, which you can query for | ||
161 | /// semantic information. | ||
162 | pub fn analysis(&self) -> Analysis { | ||
163 | Analysis { | ||
164 | imp: self.imp.analysis(), | ||
165 | } | ||
166 | } | ||
167 | /// Applies changes to the current state of the world. If there are | ||
168 | /// outstanding snapshots, they will be canceled. | ||
169 | pub fn apply_change(&mut self, change: AnalysisChange) { | ||
170 | self.imp.apply_change(change) | ||
171 | } | ||
172 | } | ||
173 | |||
174 | #[derive(Debug)] | 151 | #[derive(Debug)] |
175 | pub struct SourceChange { | 152 | pub struct SourceChange { |
176 | pub label: String, | 153 | pub label: String, |
@@ -287,124 +264,178 @@ impl ReferenceResolution { | |||
287 | } | 264 | } |
288 | } | 265 | } |
289 | 266 | ||
267 | /// `AnalysisHost` stores the current state of the world. | ||
268 | #[derive(Debug, Default)] | ||
269 | pub struct AnalysisHost { | ||
270 | db: db::RootDatabase, | ||
271 | } | ||
272 | |||
273 | impl AnalysisHost { | ||
274 | /// Returns a snapshot of the current state, which you can query for | ||
275 | /// semantic information. | ||
276 | pub fn analysis(&self) -> Analysis { | ||
277 | Analysis { | ||
278 | db: self.db.snapshot(), | ||
279 | } | ||
280 | } | ||
281 | /// Applies changes to the current state of the world. If there are | ||
282 | /// outstanding snapshots, they will be canceled. | ||
283 | pub fn apply_change(&mut self, change: AnalysisChange) { | ||
284 | self.db.apply_change(change) | ||
285 | } | ||
286 | } | ||
287 | |||
290 | /// Analysis is a snapshot of a world state at a moment in time. It is the main | 288 | /// Analysis is a snapshot of a world state at a moment in time. It is the main |
291 | /// entry point for asking semantic information about the world. When the world | 289 | /// entry point for asking semantic information about the world. When the world |
292 | /// state is advanced using `AnalysisHost::apply_change` method, all existing | 290 | /// state is advanced using `AnalysisHost::apply_change` method, all existing |
293 | /// `Analysis` are canceled (most method return `Err(Canceled)`). | 291 | /// `Analysis` are canceled (most method return `Err(Canceled)`). |
294 | #[derive(Debug)] | 292 | #[derive(Debug)] |
295 | pub struct Analysis { | 293 | pub struct Analysis { |
296 | pub(crate) imp: AnalysisImpl, | 294 | db: salsa::Snapshot<db::RootDatabase>, |
297 | } | 295 | } |
298 | 296 | ||
299 | impl Analysis { | 297 | impl Analysis { |
298 | /// Gets the text of the source file. | ||
300 | pub fn file_text(&self, file_id: FileId) -> Arc<String> { | 299 | pub fn file_text(&self, file_id: FileId) -> Arc<String> { |
301 | self.imp.file_text(file_id) | 300 | self.db.file_text(file_id) |
302 | } | 301 | } |
302 | /// Gets the syntax tree of the file. | ||
303 | pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { | 303 | pub fn file_syntax(&self, file_id: FileId) -> SourceFileNode { |
304 | self.imp.file_syntax(file_id).clone() | 304 | self.db.source_file(file_id).clone() |
305 | } | 305 | } |
306 | /// Gets the file's `LineIndex`: data structure to convert between absolute | ||
307 | /// offsets and line/column representation. | ||
306 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { | 308 | pub fn file_line_index(&self, file_id: FileId) -> Arc<LineIndex> { |
307 | self.imp.file_line_index(file_id) | 309 | self.db.file_lines(file_id) |
308 | } | 310 | } |
311 | /// Selects the next syntactic nodes encopasing the range. | ||
309 | pub fn extend_selection(&self, frange: FileRange) -> TextRange { | 312 | pub fn extend_selection(&self, frange: FileRange) -> TextRange { |
310 | extend_selection::extend_selection(&self.imp.db, frange) | 313 | extend_selection::extend_selection(&self.db, frange) |
311 | } | 314 | } |
315 | /// Returns position of the mathcing brace (all types of braces are | ||
316 | /// supported). | ||
312 | pub fn matching_brace(&self, file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> { | 317 | pub fn matching_brace(&self, file: &SourceFileNode, offset: TextUnit) -> Option<TextUnit> { |
313 | ra_editor::matching_brace(file, offset) | 318 | ra_editor::matching_brace(file, offset) |
314 | } | 319 | } |
320 | /// Returns a syntax tree represented as `String`, for debug purposes. | ||
321 | // FIXME: use a better name here. | ||
315 | pub fn syntax_tree(&self, file_id: FileId) -> String { | 322 | pub fn syntax_tree(&self, file_id: FileId) -> String { |
316 | let file = self.imp.file_syntax(file_id); | 323 | let file = self.db.source_file(file_id); |
317 | ra_editor::syntax_tree(&file) | 324 | ra_editor::syntax_tree(&file) |
318 | } | 325 | } |
326 | /// Returns an edit to remove all newlines in the range, cleaning up minor | ||
327 | /// stuff like trailing commas. | ||
319 | pub fn join_lines(&self, frange: FileRange) -> SourceChange { | 328 | pub fn join_lines(&self, frange: FileRange) -> SourceChange { |
320 | let file = self.imp.file_syntax(frange.file_id); | 329 | let file = self.db.source_file(frange.file_id); |
321 | SourceChange::from_local_edit(frange.file_id, ra_editor::join_lines(&file, frange.range)) | 330 | SourceChange::from_local_edit(frange.file_id, ra_editor::join_lines(&file, frange.range)) |
322 | } | 331 | } |
332 | /// Returns an edit which should be applied when opening a new line, fixing | ||
333 | /// up minor stuff like continuing the comment. | ||
323 | pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { | 334 | pub fn on_enter(&self, position: FilePosition) -> Option<SourceChange> { |
324 | let file = self.imp.file_syntax(position.file_id); | 335 | let file = self.db.source_file(position.file_id); |
325 | let edit = ra_editor::on_enter(&file, position.offset)?; | 336 | let edit = ra_editor::on_enter(&file, position.offset)?; |
326 | let res = SourceChange::from_local_edit(position.file_id, edit); | 337 | Some(SourceChange::from_local_edit(position.file_id, edit)) |
327 | Some(res) | ||
328 | } | 338 | } |
339 | /// Returns an edit which should be applied after `=` was typed. Primaraly, | ||
340 | /// this works when adding `let =`. | ||
341 | // FIXME: use a snippet completion instead of this hack here. | ||
329 | pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { | 342 | pub fn on_eq_typed(&self, position: FilePosition) -> Option<SourceChange> { |
330 | let file = self.imp.file_syntax(position.file_id); | 343 | let file = self.db.source_file(position.file_id); |
331 | Some(SourceChange::from_local_edit( | 344 | let edit = ra_editor::on_eq_typed(&file, position.offset)?; |
332 | position.file_id, | 345 | Some(SourceChange::from_local_edit(position.file_id, edit)) |
333 | ra_editor::on_eq_typed(&file, position.offset)?, | ||
334 | )) | ||
335 | } | 346 | } |
347 | /// Returns a tree representation of symbols in the file. Useful to draw a | ||
348 | /// file outline. | ||
336 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { | 349 | pub fn file_structure(&self, file_id: FileId) -> Vec<StructureNode> { |
337 | let file = self.imp.file_syntax(file_id); | 350 | let file = self.db.source_file(file_id); |
338 | ra_editor::file_structure(&file) | 351 | ra_editor::file_structure(&file) |
339 | } | 352 | } |
353 | /// Returns the set of folding ranges. | ||
340 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { | 354 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { |
341 | let file = self.imp.file_syntax(file_id); | 355 | let file = self.db.source_file(file_id); |
342 | ra_editor::folding_ranges(&file) | 356 | ra_editor::folding_ranges(&file) |
343 | } | 357 | } |
358 | /// Fuzzy searches for a symbol. | ||
344 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { | 359 | pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> { |
345 | let res = self | 360 | let res = symbol_index::world_symbols(&*self.db, query)? |
346 | .imp | ||
347 | .world_symbols(query)? | ||
348 | .into_iter() | 361 | .into_iter() |
349 | .map(|(file_id, symbol)| NavigationTarget { file_id, symbol }) | 362 | .map(|(file_id, symbol)| NavigationTarget { file_id, symbol }) |
350 | .collect(); | 363 | .collect(); |
351 | Ok(res) | 364 | Ok(res) |
352 | } | 365 | } |
366 | /// Resolves reference to definition, but does not gurantee correctness. | ||
353 | pub fn approximately_resolve_symbol( | 367 | pub fn approximately_resolve_symbol( |
354 | &self, | 368 | &self, |
355 | position: FilePosition, | 369 | position: FilePosition, |
356 | ) -> Cancelable<Option<ReferenceResolution>> { | 370 | ) -> Cancelable<Option<ReferenceResolution>> { |
357 | self.imp.approximately_resolve_symbol(position) | 371 | self.db.approximately_resolve_symbol(position) |
358 | } | 372 | } |
373 | /// Finds all usages of the reference at point. | ||
359 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { | 374 | pub fn find_all_refs(&self, position: FilePosition) -> Cancelable<Vec<(FileId, TextRange)>> { |
360 | self.imp.find_all_refs(position) | 375 | self.db.find_all_refs(position) |
361 | } | 376 | } |
377 | /// Returns documentation string for a given target. | ||
362 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { | 378 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { |
363 | self.imp.doc_text_for(nav) | 379 | self.db.doc_text_for(nav) |
364 | } | 380 | } |
381 | /// Returns a `mod name;` declaration whihc created the current module. | ||
365 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { | 382 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { |
366 | self.imp.parent_module(position) | 383 | self.db.parent_module(position) |
367 | } | 384 | } |
385 | /// Returns `::` separated path to the current module from the crate root. | ||
368 | pub fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> { | 386 | pub fn module_path(&self, position: FilePosition) -> Cancelable<Option<String>> { |
369 | self.imp.module_path(position) | 387 | self.db.module_path(position) |
370 | } | 388 | } |
389 | /// Returns crates this file belongs too. | ||
371 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { | 390 | pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> { |
372 | self.imp.crate_for(file_id) | 391 | self.db.crate_for(file_id) |
373 | } | 392 | } |
393 | /// Returns the root file of the given crate. | ||
374 | pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { | 394 | pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { |
375 | Ok(self.imp.crate_root(crate_id)) | 395 | Ok(self.db.crate_root(crate_id)) |
376 | } | 396 | } |
397 | /// Returns the set of possible targets to run for the current file. | ||
377 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { | 398 | pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> { |
378 | let file = self.imp.file_syntax(file_id); | 399 | let file = self.db.source_file(file_id); |
379 | Ok(runnables::runnables(self, &file, file_id)) | 400 | Ok(runnables::runnables(self, &file, file_id)) |
380 | } | 401 | } |
402 | /// Computes syntax highlighting for the given file. | ||
381 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { | 403 | pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> { |
382 | syntax_highlighting::highlight(&*self.imp.db, file_id) | 404 | syntax_highlighting::highlight(&*self.db, file_id) |
383 | } | 405 | } |
406 | /// Computes completions at the given position. | ||
384 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { | 407 | pub fn completions(&self, position: FilePosition) -> Cancelable<Option<Vec<CompletionItem>>> { |
385 | self.imp.completions(position) | 408 | let completions = completion::completions(&self.db, position)?; |
409 | Ok(completions.map(|it| it.into())) | ||
386 | } | 410 | } |
411 | /// Computes assists (aks code actons aka intentions) for the given | ||
412 | /// position. | ||
387 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<SourceChange>> { | 413 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<SourceChange>> { |
388 | Ok(self.imp.assists(frange)) | 414 | Ok(self.db.assists(frange)) |
389 | } | 415 | } |
416 | /// Computes the set of diagnostics for the given file. | ||
390 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 417 | pub fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
391 | self.imp.diagnostics(file_id) | 418 | self.db.diagnostics(file_id) |
392 | } | 419 | } |
420 | /// Computes parameter information for the given call expression. | ||
393 | pub fn resolve_callable( | 421 | pub fn resolve_callable( |
394 | &self, | 422 | &self, |
395 | position: FilePosition, | 423 | position: FilePosition, |
396 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { | 424 | ) -> Cancelable<Option<(FnSignatureInfo, Option<usize>)>> { |
397 | self.imp.resolve_callable(position) | 425 | self.db.resolve_callable(position) |
398 | } | 426 | } |
427 | /// Computes the type of the expression at the given position. | ||
399 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { | 428 | pub fn type_of(&self, frange: FileRange) -> Cancelable<Option<String>> { |
400 | self.imp.type_of(frange) | 429 | self.db.type_of(frange) |
401 | } | 430 | } |
431 | /// Returns the edit required to rename reference at the position to the new | ||
432 | /// name. | ||
402 | pub fn rename( | 433 | pub fn rename( |
403 | &self, | 434 | &self, |
404 | position: FilePosition, | 435 | position: FilePosition, |
405 | new_name: &str, | 436 | new_name: &str, |
406 | ) -> Cancelable<Vec<SourceFileEdit>> { | 437 | ) -> Cancelable<Vec<SourceFileEdit>> { |
407 | self.imp.rename(position, new_name) | 438 | self.db.rename(position, new_name) |
408 | } | 439 | } |
409 | } | 440 | } |
410 | 441 | ||