Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/inlay_hints.rs')
| -rw-r--r-- | crates/ide/src/inlay_hints.rs | 77 |
1 files changed, 51 insertions, 26 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 6d83a747d7..1f723c85df 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -209,7 +209,7 @@ fn hints( ) { closing_brace::hints(hints, sema, config, file_id, node.clone()); if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) { - generic_param::hints(hints, sema, config, any_has_generic_args); + generic_param::hints(hints, famous_defs, config, any_has_generic_args); } match_ast! { @@ -300,22 +300,23 @@ pub struct InlayHintsConfig { pub closing_brace_hints_min_lines: Option<usize>, pub fields_to_resolve: InlayFieldsToResolve, } + impl InlayHintsConfig { - fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> Lazy<TextEdit> { + fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> { if self.fields_to_resolve.resolve_text_edits { - Lazy::Lazy + LazyProperty::Lazy } else { let edit = finish(); never!(edit.is_empty(), "inlay hint produced an empty text edit"); - Lazy::Computed(edit) + LazyProperty::Computed(edit) } } - fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> Lazy<InlayTooltip> { + fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> LazyProperty<InlayTooltip> { if self.fields_to_resolve.resolve_hint_tooltip && self.fields_to_resolve.resolve_label_tooltip { - Lazy::Lazy + LazyProperty::Lazy } else { let tooltip = finish(); never!( @@ -326,7 +327,20 @@ impl InlayHintsConfig { .is_empty(), "inlay hint produced an empty tooltip" ); - Lazy::Computed(tooltip) + LazyProperty::Computed(tooltip) + } + } + + /// This always reports a resolvable location, so only use this when it is very likely for a + /// location link to actually resolve but where computing `finish` would be costly. + fn lazy_location_opt( + &self, + finish: impl FnOnce() -> Option<FileRange>, + ) -> Option<LazyProperty<FileRange>> { + if self.fields_to_resolve.resolve_label_location { + Some(LazyProperty::Lazy) + } else { + finish().map(LazyProperty::Computed) } } } @@ -441,7 +455,7 @@ pub struct InlayHint { /// The actual label to show in the inlay hint. pub label: InlayHintLabel, /// Text edit to apply when "accepting" this inlay hint. - pub text_edit: Option<Lazy<TextEdit>>, + pub text_edit: Option<LazyProperty<TextEdit>>, /// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the /// hint does not support resolving. pub resolve_parent: Option<TextRange>, @@ -449,15 +463,15 @@ pub struct InlayHint { /// A type signaling that a value is either computed, or is available for computation. #[derive(Clone, Debug)] -pub enum Lazy<T> { +pub enum LazyProperty<T> { Computed(T), Lazy, } -impl<T> Lazy<T> { +impl<T> LazyProperty<T> { pub fn computed(self) -> Option<T> { match self { - Lazy::Computed(it) => Some(it), + LazyProperty::Computed(it) => Some(it), _ => None, } } @@ -508,8 +522,8 @@ pub struct InlayHintLabel { impl InlayHintLabel { pub fn simple( s: impl Into<String>, - tooltip: Option<Lazy<InlayTooltip>>, - linked_location: Option<FileRange>, + tooltip: Option<LazyProperty<InlayTooltip>>, + linked_location: Option<LazyProperty<FileRange>>, ) -> InlayHintLabel { InlayHintLabel { parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location, tooltip }], @@ -593,16 +607,16 @@ pub struct InlayHintLabelPart { /// refers to (not necessarily the location itself). /// When setting this, no tooltip must be set on the containing hint, or VS Code will display /// them both. - pub linked_location: Option<FileRange>, + pub linked_location: Option<LazyProperty<FileRange>>, /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like /// hover requests to show. - pub tooltip: Option<Lazy<InlayTooltip>>, + pub tooltip: Option<LazyProperty<InlayTooltip>>, } impl std::hash::Hash for InlayHintLabelPart { fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.text.hash(state); - self.linked_location.hash(state); + self.linked_location.is_some().hash(state); self.tooltip.is_some().hash(state); } } @@ -610,7 +624,9 @@ impl std::hash::Hash for InlayHintLabelPart { impl fmt::Debug for InlayHintLabelPart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self { text, linked_location: None, tooltip: None | Some(Lazy::Lazy) } => text.fmt(f), + Self { text, linked_location: None, tooltip: None | Some(LazyProperty::Lazy) } => { + text.fmt(f) + } Self { text, linked_location, tooltip } => f .debug_struct("InlayHintLabelPart") .field("text", text) @@ -618,8 +634,10 @@ impl fmt::Debug for InlayHintLabelPart { .field( "tooltip", &tooltip.as_ref().map_or("", |it| match it { - Lazy::Computed(InlayTooltip::String(it) | InlayTooltip::Markdown(it)) => it, - Lazy::Lazy => "", + LazyProperty::Computed( + InlayTooltip::String(it) | InlayTooltip::Markdown(it), + ) => it, + LazyProperty::Lazy => "", }), ) .finish(), @@ -632,7 +650,8 @@ struct InlayHintLabelBuilder<'a> { db: &'a RootDatabase, result: InlayHintLabel, last_part: String, - location: Option<FileRange>, + resolve: bool, + location: Option<LazyProperty<FileRange>>, } impl fmt::Write for InlayHintLabelBuilder<'_> { @@ -645,11 +664,16 @@ impl HirWrite for InlayHintLabelBuilder<'_> { fn start_location_link(&mut self, def: ModuleDefId) { never!(self.location.is_some(), "location link is already started"); self.make_new_part(); - let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return }; - let location = location.call_site(); - let location = - FileRange { file_id: location.file_id, range: location.focus_or_full_range() }; - self.location = Some(location); + + self.location = Some(if self.resolve { + LazyProperty::Lazy + } else { + LazyProperty::Computed({ + let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return }; + let location = location.call_site(); + FileRange { file_id: location.file_id, range: location.focus_or_full_range() } + }) + }); } fn end_location_link(&mut self) { @@ -735,6 +759,7 @@ fn label_of_ty( last_part: String::new(), location: None, result: InlayHintLabel::default(), + resolve: config.fields_to_resolve.resolve_label_location, }; let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, edition); let r = label_builder.finish(); @@ -783,7 +808,7 @@ fn ty_to_text_edit( ty: &hir::Type, offset_to_insert: TextSize, prefix: impl Into<String>, -) -> Option<Lazy<TextEdit>> { +) -> Option<LazyProperty<TextEdit>> { // FIXME: Limit the length and bail out on excess somehow? let rendered = sema .scope(node_for_hint) |