1#![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
13#![recursion_limit = "128"]
14
15#[cfg(test)]
16mod fixture;
17
18mod markup;
19mod navigation_target;
20
21mod annotations;
22mod call_hierarchy;
23mod child_modules;
24mod doc_links;
25mod expand_macro;
26mod extend_selection;
27mod fetch_crates;
28mod file_structure;
29mod folding_ranges;
30mod goto_declaration;
31mod goto_definition;
32mod goto_implementation;
33mod goto_type_definition;
34mod highlight_related;
35mod hover;
36mod inlay_hints;
37mod interpret;
38mod join_lines;
39mod markdown_remove;
40mod matching_brace;
41mod moniker;
42mod move_item;
43mod parent_module;
44mod predicate_eval;
45mod references;
46mod rename;
47mod runnables;
48mod signature_help;
49mod ssr;
50mod static_index;
51mod status;
52mod syntax_highlighting;
53mod test_explorer;
54mod typing;
55mod view_crate_graph;
56mod view_hir;
57mod view_item_tree;
58mod view_memory_layout;
59mod view_mir;
60mod view_syntax_tree;
61
62use std::panic::{AssertUnwindSafe, UnwindSafe};
63use std::time::Duration;
64
65use cfg::CfgOptions;
66use fetch_crates::CrateInfo;
67use hir::{ChangeWithProcMacros, EditionedFileId, crate_def_map, sym};
68use ide_db::base_db::relevant_crates;
69use ide_db::base_db::salsa::Durability;
70use ide_db::line_index;
71use ide_db::ra_fixture::RaFixtureAnalysis;
72use ide_db::{
73 FxHashMap, FxIndexSet,
74 base_db::{
75 AbsPathBuf, CrateOrigin, CrateWorkspaceData, Env, FileSet, SourceDatabase, VfsPath,
76 salsa::{Cancelled, Database},
77 },
78 prime_caches, symbol_index,
79};
80use macros::UpmapFromRaFixture;
81use syntax::{AstNode, SourceFile, ast};
82use triomphe::Arc;
83use view_memory_layout::{RecursiveMemoryLayout, view_memory_layout};
84
85use crate::navigation_target::ToNav;
86
87pub use crate::{
88 annotations::{Annotation, AnnotationConfig, AnnotationKind, AnnotationLocation},
89 call_hierarchy::{CallHierarchyConfig, CallItem},
90 expand_macro::ExpandedMacro,
91 file_structure::{FileStructureConfig, StructureNode, StructureNodeKind},
92 folding_ranges::{Fold, FoldKind},
93 goto_definition::GotoDefinitionConfig,
94 goto_implementation::GotoImplementationConfig,
95 highlight_related::{HighlightRelatedConfig, HighlightedRange},
96 hover::{
97 HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult,
98 MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, SubstTyLen,
99 },
100 inlay_hints::{
101 AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
102 GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart,
103 InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LazyProperty,
104 LifetimeElisionHints, TypeHintsPlacement,
105 },
106 join_lines::JoinLinesConfig,
107 markup::Markup,
108 moniker::{
109 Moniker, MonikerDescriptorKind, MonikerIdentifier, MonikerKind, MonikerResult,
110 PackageInformation, SymbolInformationKind,
111 },
112 move_item::Direction,
113 navigation_target::{NavigationTarget, TryToNav, UpmappingResult},
114 references::{FindAllRefsConfig, ReferenceSearchResult},
115 rename::{RenameConfig, RenameError},
116 runnables::{Runnable, RunnableKind, TestId, UpdateTest},
117 signature_help::SignatureHelp,
118 static_index::{
119 StaticIndex, StaticIndexedFile, TokenId, TokenStaticData, VendoredLibrariesConfig,
120 },
121 syntax_highlighting::{
122 HighlightConfig, HlRange,
123 tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
124 },
125 test_explorer::{TestItem, TestItemKind},
126};
127pub use hir::{PredicateEvaluationResult, PredicateEvaluationStatus, Semantics};
128pub use ide_assists::{
129 Assist, AssistConfig, AssistId, AssistKind, AssistResolveStrategy, SingleResolve,
130};
131pub use ide_completion::{
132 CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem,
133 CompletionItemImport, CompletionItemKind, CompletionItemRefMode, CompletionRelevance, Snippet,
134 SnippetScope,
135};
136pub use ide_db::{
137 FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind,
138 assists::ExprFillDefaultMode,
139 base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId},
140 documentation::Documentation,
141 label::Label,
142 line_index::{LineCol, LineIndex},
143 prime_caches::ParallelPrimeCachesProgress,
144 ra_fixture::RaFixtureConfig,
145 search::{ReferenceCategory, SearchScope},
146 source_change::{FileSystemEdit, SnippetEdit, SourceChange},
147 symbol_index::Query,
148 text_edit::{Indel, TextEdit},
149};
150pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig};
151pub use ide_ssr::SsrError;
152pub use span::Edition;
153pub use syntax::{TextRange, TextSize};
154
155pub type Cancellable<T> = Result<T, Cancelled>;
156
157#[derive(Debug, UpmapFromRaFixture)]
159pub struct RangeInfo<T> {
160 pub range: TextRange,
161 pub info: T,
162}
163
164impl<T> RangeInfo<T> {
165 pub fn new(range: TextRange, info: T) -> RangeInfo<T> {
166 RangeInfo { range, info }
167 }
168}
169
170#[derive(Debug)]
172pub struct AnalysisHost {
173 db: RootDatabase,
174}
175
176impl AnalysisHost {
177 pub fn new(lru_capacity: Option<u16>) -> AnalysisHost {
178 AnalysisHost { db: RootDatabase::new(lru_capacity) }
179 }
180
181 pub fn with_database(db: RootDatabase) -> AnalysisHost {
182 AnalysisHost { db }
183 }
184
185 pub fn update_lru_capacity(&mut self, lru_capacity: Option<u16>) {
186 self.db.update_base_query_lru_capacities(lru_capacity);
187 }
188
189 pub fn update_lru_capacities(&mut self, lru_capacities: &FxHashMap<Box<str>, u16>) {
190 self.db.update_lru_capacities(lru_capacities);
191 }
192
193 pub fn analysis(&self) -> Analysis {
196 Analysis { db: self.db.clone() }
197 }
198
199 pub fn apply_change(&mut self, change: ChangeWithProcMacros) -> Duration {
202 self.db.apply_change(change)
203 }
204
205 pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes, usize)> {
207 self.db.per_query_memory_usage()
208 }
209 pub fn trigger_cancellation(&mut self) {
210 self.db.synthetic_write(Durability::LOW);
215 }
216 pub fn trigger_garbage_collection(&mut self) {
217 self.db.synthetic_write(Durability::LOW);
222 unsafe { hir::collect_ty_garbage() };
224 }
225 pub fn raw_database(&self) -> &RootDatabase {
226 &self.db
227 }
228 pub fn raw_database_mut(&mut self) -> &mut RootDatabase {
229 &mut self.db
230 }
231}
232
233impl Default for AnalysisHost {
234 fn default() -> AnalysisHost {
235 AnalysisHost::new(None)
236 }
237}
238
239#[derive(Debug)]
244pub struct Analysis {
245 db: RootDatabase,
246}
247
248impl Analysis {
255 pub fn from_single_file(text: String, proc_macro_cwd: Arc<AbsPathBuf>) -> (Analysis, FileId) {
259 let mut host = AnalysisHost::default();
260 let file_id = FileId::from_raw(0);
261 let mut file_set = FileSet::default();
262 file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_owned()));
263 let source_root = SourceRoot::new_local(file_set);
264
265 let mut change = ChangeWithProcMacros::default();
266 change.set_roots(vec![source_root]);
267 let mut crate_graph = CrateGraphBuilder::default();
268 let mut cfg_options = CfgOptions::default();
271
272 let crate_attrs = Vec::new();
273 cfg_options.insert_atom(sym::test);
274 crate_graph.add_crate_root(
275 file_id,
276 Edition::CURRENT,
277 None,
278 None,
279 cfg_options,
280 None,
281 Env::default(),
282 CrateOrigin::Local { repo: None, name: None },
283 crate_attrs,
284 false,
285 proc_macro_cwd,
286 Arc::new(CrateWorkspaceData {
287 target: Err("fixture has no layout".into()),
288 toolchain: None,
289 }),
290 );
291 change.change_file(file_id, Some(text));
292 change.set_crate_graph(crate_graph);
293
294 host.apply_change(change);
295 (host.analysis(), file_id)
296 }
297
298 pub(crate) fn from_ra_fixture(
299 sema: &Semantics<'_, RootDatabase>,
300 literal: ast::String,
301 expanded: &ast::String,
302 config: &RaFixtureConfig<'_>,
303 ) -> Option<(Analysis, RaFixtureAnalysis)> {
304 Self::from_ra_fixture_with_on_cursor(sema, literal, expanded, config, &mut |_| {})
305 }
306
307 pub(crate) fn from_ra_fixture_with_on_cursor(
309 sema: &Semantics<'_, RootDatabase>,
310 literal: ast::String,
311 expanded: &ast::String,
312 config: &RaFixtureConfig<'_>,
313 on_cursor: &mut dyn FnMut(TextRange),
314 ) -> Option<(Analysis, RaFixtureAnalysis)> {
315 let analysis =
316 RaFixtureAnalysis::analyze_ra_fixture(sema, literal, expanded, config, on_cursor)?;
317 Some((Analysis { db: analysis.db.clone() }, analysis))
318 }
319
320 pub fn status(&self, file_id: Option<FileId>) -> Cancellable<String> {
322 self.with_db(|db| status::status(db, file_id))
323 }
324
325 pub fn source_root_id(&self, file_id: FileId) -> Cancellable<SourceRootId> {
326 self.with_db(|db| db.file_source_root(file_id).source_root_id(db))
327 }
328
329 pub fn is_local_source_root(&self, source_root_id: SourceRootId) -> Cancellable<bool> {
330 self.with_db(|db| {
331 let sr = db.source_root(source_root_id).source_root(db);
332 !sr.is_library
333 })
334 }
335
336 pub fn parallel_prime_caches<F>(&self, num_worker_threads: usize, cb: F) -> Cancellable<()>
337 where
338 F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe,
339 {
340 self.with_db(move |db| prime_caches::parallel_prime_caches(db, num_worker_threads, &cb))
341 }
342
343 pub fn file_text(&self, file_id: FileId) -> Cancellable<Arc<str>> {
345 self.with_db(|db| SourceDatabase::file_text(db, file_id).text(db).clone())
346 }
347
348 pub fn parse(&self, file_id: FileId) -> Cancellable<SourceFile> {
350 self.with_db(|db| {
352 let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
353
354 editioned_file_id_wrapper.parse(db).tree()
355 })
356 }
357
358 pub fn is_library_file(&self, file_id: FileId) -> Cancellable<bool> {
360 self.with_db(|db| {
361 let source_root = db.file_source_root(file_id).source_root_id(db);
362 db.source_root(source_root).source_root(db).is_library
363 })
364 }
365
366 pub fn file_line_index(&self, file_id: FileId) -> Cancellable<Arc<LineIndex>> {
369 self.with_db(|db| line_index(db, file_id).clone())
370 }
371
372 pub fn extend_selection(&self, frange: FileRange) -> Cancellable<TextRange> {
374 self.with_db(|db| extend_selection::extend_selection(db, frange))
375 }
376
377 pub fn matching_brace(&self, position: FilePosition) -> Cancellable<Option<TextSize>> {
380 self.with_db(|db| {
381 let file_id = EditionedFileId::current_edition(&self.db, position.file_id);
382 let parse = file_id.parse(db);
383 let file = parse.tree();
384 matching_brace::matching_brace(&file, position.offset)
385 })
386 }
387
388 pub fn view_syntax_tree(&self, file_id: FileId) -> Cancellable<String> {
389 self.with_db(|db| view_syntax_tree::view_syntax_tree(db, file_id))
390 }
391
392 pub fn view_hir(&self, position: FilePosition) -> Cancellable<String> {
393 self.with_db(|db| view_hir::view_hir(db, position))
394 }
395
396 pub fn evaluate_predicate(
397 &self,
398 text: String,
399 position: FilePosition,
400 ) -> Cancellable<PredicateEvaluationResult> {
401 self.with_db(|db| predicate_eval::evaluate_predicate(db, text, position))
402 }
403
404 pub fn view_mir(&self, position: FilePosition) -> Cancellable<String> {
405 self.with_db(|db| view_mir::view_mir(db, position))
406 }
407
408 pub fn interpret_function(&self, position: FilePosition) -> Cancellable<String> {
409 self.with_db(|db| interpret::interpret(db, position))
410 }
411
412 pub fn view_item_tree(&self, file_id: FileId) -> Cancellable<String> {
413 self.with_db(|db| view_item_tree::view_item_tree(db, file_id))
414 }
415
416 pub fn discover_test_roots(&self) -> Cancellable<Vec<TestItem>> {
417 self.with_db(test_explorer::discover_test_roots)
418 }
419
420 pub fn discover_tests_in_crate_by_test_id(&self, crate_id: &str) -> Cancellable<Vec<TestItem>> {
421 self.with_db(|db| test_explorer::discover_tests_in_crate_by_test_id(db, crate_id))
422 }
423
424 pub fn discover_tests_in_crate(&self, crate_id: Crate) -> Cancellable<Vec<TestItem>> {
425 self.with_db(|db| test_explorer::discover_tests_in_crate(db, crate_id))
426 }
427
428 pub fn discover_tests_in_file(&self, file_id: FileId) -> Cancellable<Vec<TestItem>> {
429 self.with_db(|db| test_explorer::discover_tests_in_file(db, file_id))
430 }
431
432 pub fn view_crate_graph(&self, full: bool) -> Cancellable<String> {
434 self.with_db(|db| view_crate_graph::view_crate_graph(db, full))
435 }
436
437 pub fn fetch_crates(&self) -> Cancellable<FxIndexSet<CrateInfo>> {
438 self.with_db(fetch_crates::fetch_crates)
439 }
440
441 pub fn expand_macro(&self, position: FilePosition) -> Cancellable<Option<ExpandedMacro>> {
442 self.with_db(|db| expand_macro::expand_macro(db, position))
443 }
444
445 pub fn join_lines(&self, config: &JoinLinesConfig, frange: FileRange) -> Cancellable<TextEdit> {
448 self.with_db(|db| {
449 let editioned_file_id_wrapper =
450 EditionedFileId::current_edition(&self.db, frange.file_id);
451 let parse = editioned_file_id_wrapper.parse(db);
452 join_lines::join_lines(config, &parse.tree(), frange.range)
453 })
454 }
455
456 pub fn on_enter(&self, position: FilePosition) -> Cancellable<Option<TextEdit>> {
460 self.with_db(|db| typing::on_enter(db, position))
461 }
462
463 pub const SUPPORTED_TRIGGER_CHARS: &[char] = typing::TRIGGER_CHARS;
464
465 pub fn on_char_typed(
470 &self,
471 position: FilePosition,
472 char_typed: char,
473 ) -> Cancellable<Option<SourceChange>> {
474 if !typing::TRIGGER_CHARS.contains(&char_typed) {
476 return Ok(None);
477 }
478
479 self.with_db(|db| typing::on_char_typed(db, position, char_typed))
480 }
481
482 pub fn file_structure(
485 &self,
486 config: &FileStructureConfig,
487 file_id: FileId,
488 ) -> Cancellable<Vec<StructureNode>> {
489 self.with_db(|db| {
491 let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
492 let source_file = editioned_file_id_wrapper.parse(db).tree();
493 file_structure::file_structure(&source_file, config)
494 })
495 }
496
497 pub fn inlay_hints(
499 &self,
500 config: &InlayHintsConfig<'_>,
501 file_id: FileId,
502 range: Option<TextRange>,
503 ) -> Cancellable<Vec<InlayHint>> {
504 self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
505 }
506 pub fn inlay_hints_resolve(
507 &self,
508 config: &InlayHintsConfig<'_>,
509 file_id: FileId,
510 resolve_range: TextRange,
511 hash: u64,
512 hasher: impl Fn(&InlayHint) -> u64 + Send + UnwindSafe,
513 ) -> Cancellable<Option<InlayHint>> {
514 self.with_db(|db| {
515 inlay_hints::inlay_hints_resolve(db, file_id, resolve_range, hash, config, hasher)
516 })
517 }
518
519 pub fn folding_ranges(&self, file_id: FileId, collapsed_text: bool) -> Cancellable<Vec<Fold>> {
521 self.with_db(|db| {
522 let editioned_file_id_wrapper = EditionedFileId::current_edition(&self.db, file_id);
523
524 folding_ranges::folding_ranges(
525 &editioned_file_id_wrapper.parse(db).tree(),
526 collapsed_text,
527 )
528 })
529 }
530
531 pub fn symbol_search(&self, query: Query, limit: usize) -> Cancellable<Vec<NavigationTarget>> {
533 Cancelled::catch(|| {
536 let symbols = symbol_index::world_symbols(&self.db, query);
537 hir::attach_db(&self.db, || {
538 symbols
539 .into_iter()
540 .filter_map(|s| s.try_to_nav(&Semantics::new(&self.db)))
541 .take(limit)
542 .map(UpmappingResult::call_site)
543 .collect::<Vec<_>>()
544 })
545 })
546 }
547
548 pub fn goto_definition(
550 &self,
551 position: FilePosition,
552 config: &GotoDefinitionConfig<'_>,
553 ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
554 self.with_db(|db| goto_definition::goto_definition(db, position, config))
555 }
556
557 pub fn goto_declaration(
559 &self,
560 position: FilePosition,
561 config: &GotoDefinitionConfig<'_>,
562 ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
563 self.with_db(|db| goto_declaration::goto_declaration(db, position, config))
564 }
565
566 pub fn goto_implementation(
568 &self,
569 config: &GotoImplementationConfig,
570 position: FilePosition,
571 ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
572 self.with_db(|db| goto_implementation::goto_implementation(db, config, position))
573 }
574
575 pub fn goto_type_definition(
577 &self,
578 position: FilePosition,
579 ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
580 self.with_db(|db| goto_type_definition::goto_type_definition(db, position))
581 }
582
583 pub fn find_all_refs(
584 &self,
585 position: FilePosition,
586 config: &FindAllRefsConfig<'_>,
587 ) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
588 let config = AssertUnwindSafe(config);
589 self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, &config))
590 }
591
592 pub fn hover(
594 &self,
595 config: &HoverConfig<'_>,
596 range: FileRange,
597 ) -> Cancellable<Option<RangeInfo<HoverResult>>> {
598 self.with_db(|db| hover::hover(db, range, config))
599 }
600
601 pub fn moniker(
603 &self,
604 position: FilePosition,
605 ) -> Cancellable<Option<RangeInfo<Vec<moniker::MonikerResult>>>> {
606 self.with_db(|db| moniker::moniker(db, position))
607 }
608
609 pub fn external_docs(
614 &self,
615 position: FilePosition,
616 target_dir: Option<&str>,
617 sysroot: Option<&str>,
618 ) -> Cancellable<doc_links::DocumentationLinks> {
619 self.with_db(|db| {
620 doc_links::external_docs(db, position, target_dir, sysroot).unwrap_or_default()
621 })
622 }
623
624 pub fn signature_help(&self, position: FilePosition) -> Cancellable<Option<SignatureHelp>> {
626 self.with_db(|db| signature_help::signature_help(db, position))
627 }
628
629 pub fn call_hierarchy(
631 &self,
632 position: FilePosition,
633 config: &CallHierarchyConfig<'_>,
634 ) -> Cancellable<Option<RangeInfo<Vec<NavigationTarget>>>> {
635 self.with_db(|db| call_hierarchy::call_hierarchy(db, position, config))
636 }
637
638 pub fn incoming_calls(
640 &self,
641 config: &CallHierarchyConfig<'_>,
642 position: FilePosition,
643 ) -> Cancellable<Option<Vec<CallItem>>> {
644 self.with_db(|db| call_hierarchy::incoming_calls(db, config, position))
645 }
646
647 pub fn outgoing_calls(
649 &self,
650 config: &CallHierarchyConfig<'_>,
651 position: FilePosition,
652 ) -> Cancellable<Option<Vec<CallItem>>> {
653 self.with_db(|db| call_hierarchy::outgoing_calls(db, config, position))
654 }
655
656 pub fn parent_module(&self, position: FilePosition) -> Cancellable<Vec<NavigationTarget>> {
658 self.with_db(|db| parent_module::parent_module(db, position))
659 }
660
661 pub fn child_modules(&self, position: FilePosition) -> Cancellable<Vec<NavigationTarget>> {
663 self.with_db(|db| child_modules::child_modules(db, position))
664 }
665
666 pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> {
668 self.with_db(|db| parent_module::crates_for(db, file_id))
669 }
670
671 pub fn transitive_rev_deps(&self, crate_id: Crate) -> Cancellable<Vec<Crate>> {
673 self.with_db(|db| Vec::from_iter(crate_id.transitive_rev_deps(db)))
674 }
675
676 pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<Crate>> {
678 self.with_db(|db| relevant_crates(db, file_id).to_vec())
679 }
680
681 pub fn crate_edition(&self, crate_id: Crate) -> Cancellable<Edition> {
683 self.with_db(|db| crate_id.data(db).edition)
684 }
685
686 pub fn is_proc_macro_crate(&self, crate_id: Crate) -> Cancellable<bool> {
688 self.with_db(|db| crate_id.data(db).is_proc_macro)
689 }
690
691 pub fn is_crate_no_std(&self, crate_id: Crate) -> Cancellable<bool> {
693 self.with_db(|db| crate_def_map(db, crate_id).is_no_std())
694 }
695
696 pub fn crate_root(&self, crate_id: Crate) -> Cancellable<FileId> {
698 self.with_db(|db| crate_id.data(db).root_file_id)
699 }
700
701 pub fn runnables(&self, file_id: FileId) -> Cancellable<Vec<Runnable>> {
703 self.with_db(|db| runnables::runnables(db, file_id))
704 }
705
706 pub fn related_tests(
708 &self,
709 position: FilePosition,
710 search_scope: Option<SearchScope>,
711 ) -> Cancellable<Vec<Runnable>> {
712 let search_scope = AssertUnwindSafe(search_scope);
713 self.with_db(|db| {
714 let _ = &search_scope;
715 runnables::related_tests(db, position, search_scope.0)
716 })
717 }
718
719 pub fn highlight_related(
721 &self,
722 config: HighlightRelatedConfig,
723 position: FilePosition,
724 ) -> Cancellable<Option<Vec<HighlightedRange>>> {
725 self.with_db(|db| {
726 highlight_related::highlight_related(&Semantics::new(db), config, position)
727 })
728 }
729
730 pub fn highlight(
732 &self,
733 highlight_config: HighlightConfig<'_>,
734 file_id: FileId,
735 ) -> Cancellable<Vec<HlRange>> {
736 self.with_db(|db| syntax_highlighting::highlight(db, &highlight_config, file_id, None))
737 }
738
739 pub fn highlight_range(
741 &self,
742 highlight_config: HighlightConfig<'_>,
743 frange: FileRange,
744 ) -> Cancellable<Vec<HlRange>> {
745 self.with_db(|db| {
746 syntax_highlighting::highlight(
747 db,
748 &highlight_config,
749 frange.file_id,
750 Some(frange.range),
751 )
752 })
753 }
754
755 pub fn highlight_as_html_with_config(
757 &self,
758 config: HighlightConfig<'_>,
759 file_id: FileId,
760 rainbow: bool,
761 ) -> Cancellable<String> {
762 self.with_db(|db| {
763 syntax_highlighting::highlight_as_html_with_config(db, &config, file_id, rainbow)
764 })
765 }
766
767 pub fn highlight_as_html(&self, file_id: FileId, rainbow: bool) -> Cancellable<String> {
769 self.with_db(|db| syntax_highlighting::highlight_as_html(db, file_id, rainbow))
770 }
771
772 pub fn completions(
774 &self,
775 config: &CompletionConfig<'_>,
776 position: FilePosition,
777 trigger_character: Option<char>,
778 ) -> Cancellable<Option<Vec<CompletionItem>>> {
779 self.with_db(|db| ide_completion::completions(db, config, position, trigger_character))
780 }
781
782 pub fn resolve_completion_edits(
784 &self,
785 config: &CompletionConfig<'_>,
786 position: FilePosition,
787 imports: impl IntoIterator<Item = CompletionItemImport> + std::panic::UnwindSafe,
788 ) -> Cancellable<Vec<TextEdit>> {
789 Ok(self
790 .with_db(|db| ide_completion::resolve_completion_edits(db, config, position, imports))?
791 .unwrap_or_default())
792 }
793
794 pub fn syntax_diagnostics(
796 &self,
797 config: &DiagnosticsConfig,
798 file_id: FileId,
799 ) -> Cancellable<Vec<Diagnostic>> {
800 self.with_db(|db| ide_diagnostics::syntax_diagnostics(db, config, file_id))
801 }
802
803 pub fn semantic_diagnostics(
805 &self,
806 config: &DiagnosticsConfig,
807 resolve: AssistResolveStrategy,
808 file_id: FileId,
809 ) -> Cancellable<Vec<Diagnostic>> {
810 self.with_db(|db| ide_diagnostics::semantic_diagnostics(db, config, &resolve, file_id))
811 }
812
813 pub fn full_diagnostics(
815 &self,
816 config: &DiagnosticsConfig,
817 resolve: AssistResolveStrategy,
818 file_id: FileId,
819 ) -> Cancellable<Vec<Diagnostic>> {
820 self.with_db(|db| ide_diagnostics::full_diagnostics(db, config, &resolve, file_id))
821 }
822
823 pub fn assists_with_fixes(
825 &self,
826 assist_config: &AssistConfig,
827 diagnostics_config: &DiagnosticsConfig,
828 resolve: AssistResolveStrategy,
829 frange: FileRange,
830 ) -> Cancellable<Vec<Assist>> {
831 let include_fixes = match &assist_config.allowed {
832 Some(it) => it.contains(&AssistKind::QuickFix),
833 None => true,
834 };
835
836 self.with_db(|db| {
837 let diagnostic_assists = if diagnostics_config.enabled && include_fixes {
838 ide_diagnostics::full_diagnostics(db, diagnostics_config, &resolve, frange.file_id)
839 .into_iter()
840 .flat_map(|it| it.fixes.unwrap_or_default())
841 .filter(|it| it.target.intersect(frange.range).is_some())
842 .collect()
843 } else {
844 Vec::new()
845 };
846 let ssr_assists = ssr::ssr_assists(db, &resolve, frange);
847 let assists = ide_assists::assists(db, assist_config, resolve, frange);
848
849 let mut res = diagnostic_assists;
850 res.extend(ssr_assists);
851 res.extend(assists);
852
853 res
854 })
855 }
856
857 pub fn rename(
860 &self,
861 position: FilePosition,
862 new_name: &str,
863 config: &RenameConfig,
864 ) -> Cancellable<Result<SourceChange, RenameError>> {
865 self.with_db(|db| rename::rename(db, position, new_name, config))
866 }
867
868 pub fn prepare_rename(
869 &self,
870 position: FilePosition,
871 ) -> Cancellable<Result<RangeInfo<()>, RenameError>> {
872 self.with_db(|db| rename::prepare_rename(db, position))
873 }
874
875 pub fn will_rename_file(
876 &self,
877 file_id: FileId,
878 new_name_stem: &str,
879 config: &RenameConfig,
880 ) -> Cancellable<Option<SourceChange>> {
881 self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem, config))
882 }
883
884 pub fn structural_search_replace(
885 &self,
886 query: &str,
887 parse_only: bool,
888 resolve_context: FilePosition,
889 selections: Vec<FileRange>,
890 ) -> Cancellable<Result<SourceChange, SsrError>> {
891 self.with_db(|db| {
892 let rule: ide_ssr::SsrRule = query.parse()?;
893 let mut match_finder =
894 ide_ssr::MatchFinder::in_context(db, resolve_context, selections)?;
895 match_finder.add_rule(rule)?;
896 let edits = if parse_only { Default::default() } else { match_finder.edits() };
897 Ok(SourceChange::from_iter(edits))
898 })
899 }
900
901 pub fn annotations(
902 &self,
903 config: &AnnotationConfig<'_>,
904 file_id: FileId,
905 ) -> Cancellable<Vec<Annotation>> {
906 self.with_db(|db| annotations::annotations(db, config, file_id))
907 }
908
909 pub fn resolve_annotation(
910 &self,
911 config: &AnnotationConfig<'_>,
912 annotation: Annotation,
913 ) -> Cancellable<Annotation> {
914 self.with_db(|db| annotations::resolve_annotation(db, config, annotation))
915 }
916
917 pub fn move_item(
918 &self,
919 range: FileRange,
920 direction: Direction,
921 ) -> Cancellable<Option<TextEdit>> {
922 self.with_db(|db| move_item::move_item(db, range, direction))
923 }
924
925 pub fn get_recursive_memory_layout(
926 &self,
927 position: FilePosition,
928 ) -> Cancellable<Option<RecursiveMemoryLayout>> {
929 self.with_db(|db| view_memory_layout(db, position))
930 }
931
932 pub fn get_failed_obligations(&self, offset: TextSize, file_id: FileId) -> Cancellable<String> {
933 self.with_db(|db| {
934 let sema = Semantics::new(db);
935 let source_file = sema.parse_guess_edition(file_id);
936
937 let Some(token) = source_file.syntax().token_at_offset(offset).next() else {
938 return String::new();
939 };
940 sema.get_failed_obligations(token).unwrap_or_default()
941 })
942 }
943
944 pub fn editioned_file_id_to_vfs(&self, file_id: hir::EditionedFileId) -> FileId {
945 file_id.file_id(&self.db)
946 }
947
948 fn with_db<F, T>(&self, f: F) -> Cancellable<T>
962 where
963 F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe,
964 {
965 hir::attach_db_allow_change(&self.db, || Cancelled::catch(|| f(&self.db)))
967 }
968}
969
970#[test]
971fn analysis_is_send() {
972 fn is_send<T: Send>() {}
973 is_send::<Analysis>();
974}