aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide/src/lib.rs')
-rw-r--r--crates/ra_ide/src/lib.rs535
1 files changed, 0 insertions, 535 deletions
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
deleted file mode 100644
index e615e993a..000000000
--- a/crates/ra_ide/src/lib.rs
+++ /dev/null
@@ -1,535 +0,0 @@
1//! ra_ide crate provides "ide-centric" APIs for the rust-analyzer. That is,
2//! it generally operates with files and text ranges, and returns results as
3//! Strings, suitable for displaying to the human.
4//!
5//! What powers this API are the `RootDatabase` struct, which defines a `salsa`
6//! database, and the `ra_hir` crate, where majority of the analysis happens.
7//! However, IDE specific bits of the analysis (most notably completion) happen
8//! in this crate.
9
10// For proving that RootDatabase is RefUnwindSafe.
11#![recursion_limit = "128"]
12
13#[allow(unused)]
14macro_rules! eprintln {
15 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
16}
17
18pub mod mock_analysis;
19
20mod markup;
21mod prime_caches;
22mod display;
23
24mod call_hierarchy;
25mod call_info;
26mod completion;
27mod diagnostics;
28mod expand_macro;
29mod extend_selection;
30mod file_structure;
31mod folding_ranges;
32mod goto_definition;
33mod goto_implementation;
34mod goto_type_definition;
35mod hover;
36mod inlay_hints;
37mod join_lines;
38mod matching_brace;
39mod parent_module;
40mod references;
41mod runnables;
42mod ssr;
43mod status;
44mod syntax_highlighting;
45mod syntax_tree;
46mod typing;
47mod link_rewrite;
48
49use std::sync::Arc;
50
51use ra_cfg::CfgOptions;
52use ra_db::{
53 salsa::{self, ParallelDatabase},
54 CheckCanceled, Env, FileLoader, FileSet, SourceDatabase, VfsPath,
55};
56use ra_ide_db::{
57 symbol_index::{self, FileSymbol},
58 LineIndexDatabase,
59};
60use ra_syntax::{SourceFile, TextRange, TextSize};
61
62use crate::display::ToNav;
63
64pub use crate::{
65 call_hierarchy::CallItem,
66 call_info::CallInfo,
67 completion::{
68 CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat,
69 },
70 diagnostics::Severity,
71 display::NavigationTarget,
72 expand_macro::ExpandedMacro,
73 file_structure::StructureNode,
74 folding_ranges::{Fold, FoldKind},
75 hover::{HoverAction, HoverConfig, HoverGotoTypeData, HoverResult},
76 inlay_hints::{InlayHint, InlayHintsConfig, InlayKind},
77 markup::Markup,
78 references::{Declaration, Reference, ReferenceAccess, ReferenceKind, ReferenceSearchResult},
79 runnables::{Runnable, RunnableKind, TestId},
80 syntax_highlighting::{
81 Highlight, HighlightModifier, HighlightModifiers, HighlightTag, HighlightedRange,
82 },
83};
84
85pub use hir::{Documentation, Semantics};
86pub use ra_assists::{Assist, AssistConfig, AssistId, AssistKind, ResolvedAssist};
87pub use ra_db::{
88 Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRoot,
89 SourceRootId,
90};
91pub use ra_ide_db::{
92 change::AnalysisChange,
93 line_index::{LineCol, LineIndex},
94 search::SearchScope,
95 source_change::{FileSystemEdit, SourceChange, SourceFileEdit},
96 symbol_index::Query,
97 RootDatabase,
98};
99pub use ra_ssr::SsrError;
100pub use ra_text_edit::{Indel, TextEdit};
101
102pub type Cancelable<T> = Result<T, Canceled>;
103
104#[derive(Debug)]
105pub struct Diagnostic {
106 pub message: String,
107 pub range: TextRange,
108 pub severity: Severity,
109 pub fix: Option<Fix>,
110}
111
112#[derive(Debug)]
113pub struct Fix {
114 pub label: String,
115 pub source_change: SourceChange,
116}
117
118impl Fix {
119 pub fn new(label: impl Into<String>, source_change: SourceChange) -> Self {
120 let label = label.into();
121 assert!(label.starts_with(char::is_uppercase) && !label.ends_with('.'));
122 Self { label, source_change }
123 }
124}
125
126/// Info associated with a text range.
127#[derive(Debug)]
128pub struct RangeInfo<T> {
129 pub range: TextRange,
130 pub info: T,
131}
132
133impl<T> RangeInfo<T> {
134 pub fn new(range: TextRange, info: T) -> RangeInfo<T> {
135 RangeInfo { range, info }
136 }
137}
138
139/// `AnalysisHost` stores the current state of the world.
140#[derive(Debug)]
141pub struct AnalysisHost {
142 db: RootDatabase,
143}
144
145impl AnalysisHost {
146 pub fn new(lru_capacity: Option<usize>) -> AnalysisHost {
147 AnalysisHost { db: RootDatabase::new(lru_capacity) }
148 }
149
150 pub fn update_lru_capacity(&mut self, lru_capacity: Option<usize>) {
151 self.db.update_lru_capacity(lru_capacity);
152 }
153
154 /// Returns a snapshot of the current state, which you can query for
155 /// semantic information.
156 pub fn analysis(&self) -> Analysis {
157 Analysis { db: self.db.snapshot() }
158 }
159
160 /// Applies changes to the current state of the world. If there are
161 /// outstanding snapshots, they will be canceled.
162 pub fn apply_change(&mut self, change: AnalysisChange) {
163 self.db.apply_change(change)
164 }
165
166 pub fn maybe_collect_garbage(&mut self) {
167 self.db.maybe_collect_garbage();
168 }
169
170 pub fn collect_garbage(&mut self) {
171 self.db.collect_garbage();
172 }
173 /// NB: this clears the database
174 pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> {
175 self.db.per_query_memory_usage()
176 }
177 pub fn request_cancellation(&mut self) {
178 self.db.request_cancellation();
179 }
180 pub fn raw_database(&self) -> &RootDatabase {
181 &self.db
182 }
183 pub fn raw_database_mut(&mut self) -> &mut RootDatabase {
184 &mut self.db
185 }
186}
187
188impl Default for AnalysisHost {
189 fn default() -> AnalysisHost {
190 AnalysisHost::new(None)
191 }
192}
193
194/// Analysis is a snapshot of a world state at a moment in time. It is the main
195/// entry point for asking semantic information about the world. When the world
196/// state is advanced using `AnalysisHost::apply_change` method, all existing
197/// `Analysis` are canceled (most method return `Err(Canceled)`).
198#[derive(Debug)]
199pub struct Analysis {
200 db: salsa::Snapshot<RootDatabase>,
201}
202
203// As a general design guideline, `Analysis` API are intended to be independent
204// from the language server protocol. That is, when exposing some functionality
205// we should think in terms of "what API makes most sense" and not in terms of
206// "what types LSP uses". Although currently LSP is the only consumer of the
207// API, the API should in theory be usable as a library, or via a different
208// protocol.
209impl Analysis {
210 // Creates an analysis instance for a single file, without any extenal
211 // dependencies, stdlib support or ability to apply changes. See
212 // `AnalysisHost` for creating a fully-featured analysis.
213 pub fn from_single_file(text: String) -> (Analysis, FileId) {
214 let mut host = AnalysisHost::default();
215 let file_id = FileId(0);
216 let mut file_set = FileSet::default();
217 file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string()));
218 let source_root = SourceRoot::new_local(file_set);
219
220 let mut change = AnalysisChange::new();
221 change.set_roots(vec![source_root]);
222 let mut crate_graph = CrateGraph::default();
223 // FIXME: cfg options
224 // Default to enable test for single file.
225 let mut cfg_options = CfgOptions::default();
226 cfg_options.insert_atom("test".into());
227 crate_graph.add_crate_root(
228 file_id,
229 Edition::Edition2018,
230 None,
231 cfg_options,
232 Env::default(),
233 Default::default(),
234 );
235 change.change_file(file_id, Some(Arc::new(text)));
236 change.set_crate_graph(crate_graph);
237 host.apply_change(change);
238 (host.analysis(), file_id)
239 }
240
241 /// Debug info about the current state of the analysis.
242 pub fn status(&self) -> Cancelable<String> {
243 self.with_db(|db| status::status(&*db))
244 }
245
246 pub fn prime_caches(&self, files: Vec<FileId>) -> Cancelable<()> {
247 self.with_db(|db| prime_caches::prime_caches(db, files))
248 }
249
250 /// Gets the text of the source file.
251 pub fn file_text(&self, file_id: FileId) -> Cancelable<Arc<String>> {
252 self.with_db(|db| db.file_text(file_id))
253 }
254
255 /// Gets the syntax tree of the file.
256 pub fn parse(&self, file_id: FileId) -> Cancelable<SourceFile> {
257 self.with_db(|db| db.parse(file_id).tree())
258 }
259
260 /// Gets the file's `LineIndex`: data structure to convert between absolute
261 /// offsets and line/column representation.
262 pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> {
263 self.with_db(|db| db.line_index(file_id))
264 }
265
266 /// Selects the next syntactic nodes encompassing the range.
267 pub fn extend_selection(&self, frange: FileRange) -> Cancelable<TextRange> {
268 self.with_db(|db| extend_selection::extend_selection(db, frange))
269 }
270
271 /// Returns position of the matching brace (all types of braces are
272 /// supported).
273 pub fn matching_brace(&self, position: FilePosition) -> Cancelable<Option<TextSize>> {
274 self.with_db(|db| {
275 let parse = db.parse(position.file_id);
276 let file = parse.tree();
277 matching_brace::matching_brace(&file, position.offset)
278 })
279 }
280
281 /// Returns a syntax tree represented as `String`, for debug purposes.
282 // FIXME: use a better name here.
283 pub fn syntax_tree(
284 &self,
285 file_id: FileId,
286 text_range: Option<TextRange>,
287 ) -> Cancelable<String> {
288 self.with_db(|db| syntax_tree::syntax_tree(&db, file_id, text_range))
289 }
290
291 pub fn expand_macro(&self, position: FilePosition) -> Cancelable<Option<ExpandedMacro>> {
292 self.with_db(|db| expand_macro::expand_macro(db, position))
293 }
294
295 /// Returns an edit to remove all newlines in the range, cleaning up minor
296 /// stuff like trailing commas.
297 pub fn join_lines(&self, frange: FileRange) -> Cancelable<TextEdit> {
298 self.with_db(|db| {
299 let parse = db.parse(frange.file_id);
300 join_lines::join_lines(&parse.tree(), frange.range)
301 })
302 }
303
304 /// Returns an edit which should be applied when opening a new line, fixing
305 /// up minor stuff like continuing the comment.
306 /// The edit will be a snippet (with `$0`).
307 pub fn on_enter(&self, position: FilePosition) -> Cancelable<Option<TextEdit>> {
308 self.with_db(|db| typing::on_enter(&db, position))
309 }
310
311 /// Returns an edit which should be applied after a character was typed.
312 ///
313 /// This is useful for some on-the-fly fixups, like adding `;` to `let =`
314 /// automatically.
315 pub fn on_char_typed(
316 &self,
317 position: FilePosition,
318 char_typed: char,
319 ) -> Cancelable<Option<SourceChange>> {
320 // Fast path to not even parse the file.
321 if !typing::TRIGGER_CHARS.contains(char_typed) {
322 return Ok(None);
323 }
324 self.with_db(|db| typing::on_char_typed(&db, position, char_typed))
325 }
326
327 /// Returns a tree representation of symbols in the file. Useful to draw a
328 /// file outline.
329 pub fn file_structure(&self, file_id: FileId) -> Cancelable<Vec<StructureNode>> {
330 self.with_db(|db| file_structure::file_structure(&db.parse(file_id).tree()))
331 }
332
333 /// Returns a list of the places in the file where type hints can be displayed.
334 pub fn inlay_hints(
335 &self,
336 file_id: FileId,
337 config: &InlayHintsConfig,
338 ) -> Cancelable<Vec<InlayHint>> {
339 self.with_db(|db| inlay_hints::inlay_hints(db, file_id, config))
340 }
341
342 /// Returns the set of folding ranges.
343 pub fn folding_ranges(&self, file_id: FileId) -> Cancelable<Vec<Fold>> {
344 self.with_db(|db| folding_ranges::folding_ranges(&db.parse(file_id).tree()))
345 }
346
347 /// Fuzzy searches for a symbol.
348 pub fn symbol_search(&self, query: Query) -> Cancelable<Vec<NavigationTarget>> {
349 self.with_db(|db| {
350 symbol_index::world_symbols(db, query)
351 .into_iter()
352 .map(|s| s.to_nav(db))
353 .collect::<Vec<_>>()
354 })
355 }
356
357 /// Returns the definitions from the symbol at `position`.
358 pub fn goto_definition(
359 &self,
360 position: FilePosition,
361 ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
362 self.with_db(|db| goto_definition::goto_definition(db, position))
363 }
364
365 /// Returns the impls from the symbol at `position`.
366 pub fn goto_implementation(
367 &self,
368 position: FilePosition,
369 ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
370 self.with_db(|db| goto_implementation::goto_implementation(db, position))
371 }
372
373 /// Returns the type definitions for the symbol at `position`.
374 pub fn goto_type_definition(
375 &self,
376 position: FilePosition,
377 ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
378 self.with_db(|db| goto_type_definition::goto_type_definition(db, position))
379 }
380
381 /// Finds all usages of the reference at point.
382 pub fn find_all_refs(
383 &self,
384 position: FilePosition,
385 search_scope: Option<SearchScope>,
386 ) -> Cancelable<Option<ReferenceSearchResult>> {
387 self.with_db(|db| {
388 references::find_all_refs(&Semantics::new(db), position, search_scope).map(|it| it.info)
389 })
390 }
391
392 /// Returns a short text describing element at position.
393 pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<HoverResult>>> {
394 self.with_db(|db| hover::hover(db, position))
395 }
396
397 /// Computes parameter information for the given call expression.
398 pub fn call_info(&self, position: FilePosition) -> Cancelable<Option<CallInfo>> {
399 self.with_db(|db| call_info::call_info(db, position))
400 }
401
402 /// Computes call hierarchy candidates for the given file position.
403 pub fn call_hierarchy(
404 &self,
405 position: FilePosition,
406 ) -> Cancelable<Option<RangeInfo<Vec<NavigationTarget>>>> {
407 self.with_db(|db| call_hierarchy::call_hierarchy(db, position))
408 }
409
410 /// Computes incoming calls for the given file position.
411 pub fn incoming_calls(&self, position: FilePosition) -> Cancelable<Option<Vec<CallItem>>> {
412 self.with_db(|db| call_hierarchy::incoming_calls(db, position))
413 }
414
415 /// Computes incoming calls for the given file position.
416 pub fn outgoing_calls(&self, position: FilePosition) -> Cancelable<Option<Vec<CallItem>>> {
417 self.with_db(|db| call_hierarchy::outgoing_calls(db, position))
418 }
419
420 /// Returns a `mod name;` declaration which created the current module.
421 pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> {
422 self.with_db(|db| parent_module::parent_module(db, position))
423 }
424
425 /// Returns crates this file belongs too.
426 pub fn crate_for(&self, file_id: FileId) -> Cancelable<Vec<CrateId>> {
427 self.with_db(|db| parent_module::crate_for(db, file_id))
428 }
429
430 /// Returns the edition of the given crate.
431 pub fn crate_edition(&self, crate_id: CrateId) -> Cancelable<Edition> {
432 self.with_db(|db| db.crate_graph()[crate_id].edition)
433 }
434
435 /// Returns the root file of the given crate.
436 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
437 self.with_db(|db| db.crate_graph()[crate_id].root_file_id)
438 }
439
440 /// Returns the set of possible targets to run for the current file.
441 pub fn runnables(&self, file_id: FileId) -> Cancelable<Vec<Runnable>> {
442 self.with_db(|db| runnables::runnables(db, file_id))
443 }
444
445 /// Computes syntax highlighting for the given file
446 pub fn highlight(&self, file_id: FileId) -> Cancelable<Vec<HighlightedRange>> {
447 self.with_db(|db| syntax_highlighting::highlight(db, file_id, None, false))
448 }
449
450 /// Computes syntax highlighting for the given file range.
451 pub fn highlight_range(&self, frange: FileRange) -> Cancelable<Vec<HighlightedRange>> {
452 self.with_db(|db| {
453 syntax_highlighting::highlight(db, frange.file_id, Some(frange.range), false)
454 })
455 }
456
457 /// Computes syntax highlighting for the given file.
458 pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancelable<String> {
459 self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow))
460 }
461
462 /// Computes completions at the given position.
463 pub fn completions(
464 &self,
465 config: &CompletionConfig,
466 position: FilePosition,
467 ) -> Cancelable<Option<Vec<CompletionItem>>> {
468 self.with_db(|db| completion::completions(db, config, position).map(Into::into))
469 }
470
471 /// Computes resolved assists with source changes for the given position.
472 pub fn resolved_assists(
473 &self,
474 config: &AssistConfig,
475 frange: FileRange,
476 ) -> Cancelable<Vec<ResolvedAssist>> {
477 self.with_db(|db| ra_assists::Assist::resolved(db, config, frange))
478 }
479
480 /// Computes unresolved assists (aka code actions aka intentions) for the given
481 /// position.
482 pub fn unresolved_assists(
483 &self,
484 config: &AssistConfig,
485 frange: FileRange,
486 ) -> Cancelable<Vec<Assist>> {
487 self.with_db(|db| Assist::unresolved(db, config, frange))
488 }
489
490 /// Computes the set of diagnostics for the given file.
491 pub fn diagnostics(
492 &self,
493 file_id: FileId,
494 enable_experimental: bool,
495 ) -> Cancelable<Vec<Diagnostic>> {
496 self.with_db(|db| diagnostics::diagnostics(db, file_id, enable_experimental))
497 }
498
499 /// Returns the edit required to rename reference at the position to the new
500 /// name.
501 pub fn rename(
502 &self,
503 position: FilePosition,
504 new_name: &str,
505 ) -> Cancelable<Option<RangeInfo<SourceChange>>> {
506 self.with_db(|db| references::rename(db, position, new_name))
507 }
508
509 pub fn structural_search_replace(
510 &self,
511 query: &str,
512 parse_only: bool,
513 position: FilePosition,
514 selections: Vec<FileRange>,
515 ) -> Cancelable<Result<SourceChange, SsrError>> {
516 self.with_db(|db| {
517 let edits = ssr::parse_search_replace(query, parse_only, db, position, selections)?;
518 Ok(SourceChange::from(edits))
519 })
520 }
521
522 /// Performs an operation on that may be Canceled.
523 fn with_db<F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, T>(
524 &self,
525 f: F,
526 ) -> Cancelable<T> {
527 self.db.catch_canceled(f)
528 }
529}
530
531#[test]
532fn analysis_is_send() {
533 fn is_send<T: Send>() {}
534 is_send::<Analysis>();
535}