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 | 196 |
1 files changed, 121 insertions, 75 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 19e5509681..21550d5e66 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -8,9 +8,12 @@ use hir::{ ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, }; -use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder}; +use ide_db::{ + FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder, +}; use ide_db::{FxHashSet, text_edit::TextEdit}; use itertools::Itertools; +use macros::UpmapFromRaFixture; use smallvec::{SmallVec, smallvec}; use stdx::never; use syntax::{ @@ -37,6 +40,7 @@ mod implicit_static; mod implied_dyn_trait; mod lifetime; mod param_name; +mod ra_fixture; mod range_exclusive; // Feature: Inlay Hints @@ -80,7 +84,7 @@ pub(crate) fn inlay_hints( db: &RootDatabase, file_id: FileId, range_limit: Option<TextRange>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, ) -> Vec<InlayHint> { let _p = tracing::info_span!("inlay_hints").entered(); let sema = Semantics::new(db); @@ -105,14 +109,16 @@ pub(crate) fn inlay_hints( } }; let mut preorder = file.preorder(); - while let Some(event) = preorder.next() { - if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none()) - { - preorder.skip_subtree(); - continue; + hir::attach_db(sema.db, || { + while let Some(event) = preorder.next() { + if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none()) + { + preorder.skip_subtree(); + continue; + } + hints(event); } - hints(event); - } + }); if let Some(range_limit) = range_limit { acc.retain(|hint| range_limit.contains_range(hint.range)); } @@ -130,7 +136,7 @@ pub(crate) fn inlay_hints_resolve( file_id: FileId, resolve_range: TextRange, hash: u64, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, hasher: impl Fn(&InlayHint) -> u64, ) -> Option<InlayHint> { let _p = tracing::info_span!("inlay_hints_resolve").entered(); @@ -206,7 +212,7 @@ fn hints( hints: &mut Vec<InlayHint>, ctx: &mut InlayHintCtx, famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, file_id: EditionedFileId, display_target: DisplayTarget, node: SyntaxNode, @@ -228,15 +234,16 @@ fn hints( chaining::hints(hints, famous_defs, config, display_target, &expr); adjustment::hints(hints, famous_defs, config, display_target, &expr); match expr { - ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, ast::Expr::from(it)), + ast::Expr::CallExpr(it) => param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)), ast::Expr::MethodCallExpr(it) => { - param_name::hints(hints, famous_defs, config, ast::Expr::from(it)) + param_name::hints(hints, famous_defs, config, file_id, ast::Expr::from(it)) } ast::Expr::ClosureExpr(it) => { closure_captures::hints(hints, famous_defs, config, it.clone()); closure_ret::hints(hints, famous_defs, config, display_target, it) }, ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it), + ast::Expr::Literal(it) => ra_fixture::hints(hints, famous_defs.0, file_id, config, it), _ => Some(()), } }, @@ -292,8 +299,8 @@ fn hints( }; } -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct InlayHintsConfig { +#[derive(Clone, Debug)] +pub struct InlayHintsConfig<'a> { pub render_colons: bool, pub type_hints: bool, pub sized_bound: bool, @@ -302,6 +309,7 @@ pub struct InlayHintsConfig { pub generic_parameter_hints: GenericParameterHints, pub chaining_hints: bool, pub adjustment_hints: AdjustmentHints, + pub adjustment_hints_disable_reborrows: bool, pub adjustment_hints_mode: AdjustmentHintsMode, pub adjustment_hints_hide_outside_unsafe: bool, pub closure_return_type_hints: ClosureReturnTypeHints, @@ -318,9 +326,10 @@ pub struct InlayHintsConfig { pub max_length: Option<usize>, pub closing_brace_hints_min_lines: Option<usize>, pub fields_to_resolve: InlayFieldsToResolve, + pub minicore: MiniCore<'a>, } -impl InlayHintsConfig { +impl InlayHintsConfig<'_> { fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> { if self.fields_to_resolve.resolve_text_edits { LazyProperty::Lazy @@ -426,7 +435,7 @@ pub enum LifetimeElisionHints { #[derive(Clone, Debug, PartialEq, Eq)] pub enum AdjustmentHints { Always, - ReborrowOnly, + BorrowsOnly, Never, } @@ -463,7 +472,7 @@ pub enum InlayHintPosition { After, } -#[derive(Debug)] +#[derive(Debug, UpmapFromRaFixture)] pub struct InlayHint { /// The text range this inlay hint applies to. pub range: TextRange, @@ -482,9 +491,10 @@ pub struct InlayHint { } /// A type signaling that a value is either computed, or is available for computation. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default, UpmapFromRaFixture)] pub enum LazyProperty<T> { Computed(T), + #[default] Lazy, } @@ -534,7 +544,7 @@ pub enum InlayTooltip { Markdown(String), } -#[derive(Default, Hash)] +#[derive(Default, Hash, UpmapFromRaFixture)] pub struct InlayHintLabel { pub parts: SmallVec<[InlayHintLabelPart; 1]>, } @@ -576,13 +586,13 @@ impl InlayHintLabel { } pub fn append_part(&mut self, part: InlayHintLabelPart) { - if part.linked_location.is_none() && part.tooltip.is_none() { - if let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) = + if part.linked_location.is_none() + && part.tooltip.is_none() + && let Some(InlayHintLabelPart { text, linked_location: None, tooltip: None }) = self.parts.last_mut() - { - text.push_str(&part.text); - return; - } + { + text.push_str(&part.text); + return; } self.parts.push(part); } @@ -620,6 +630,7 @@ impl fmt::Debug for InlayHintLabel { } } +#[derive(UpmapFromRaFixture)] pub struct InlayHintLabelPart { pub text: String, /// Source location represented by this label part. The client will use this to fetch the part's @@ -667,7 +678,7 @@ impl fmt::Debug for InlayHintLabelPart { #[derive(Debug)] struct InlayHintLabelBuilder<'a> { - db: &'a RootDatabase, + sema: &'a Semantics<'a, RootDatabase>, result: InlayHintLabel, last_part: String, resolve: bool, @@ -689,7 +700,7 @@ impl HirWrite for InlayHintLabelBuilder<'_> { LazyProperty::Lazy } else { LazyProperty::Computed({ - let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return }; + let Some(location) = ModuleDef::from(def).try_to_nav(self.sema) else { return }; let location = location.call_site(); FileRange { file_id: location.file_id, range: location.focus_or_full_range() } }) @@ -721,7 +732,7 @@ impl InlayHintLabelBuilder<'_> { fn label_of_ty( famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, ty: &hir::Type<'_>, display_target: DisplayTarget, ) -> Option<InlayHintLabel> { @@ -731,51 +742,53 @@ fn label_of_ty( mut max_length: Option<usize>, ty: &hir::Type<'_>, label_builder: &mut InlayHintLabelBuilder<'_>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, display_target: DisplayTarget, ) -> Result<(), HirDisplayError> { - let iter_item_type = hint_iterator(sema, famous_defs, ty); - match iter_item_type { - Some((iter_trait, item, ty)) => { - const LABEL_START: &str = "impl "; - const LABEL_ITERATOR: &str = "Iterator"; - const LABEL_MIDDLE: &str = "<"; - const LABEL_ITEM: &str = "Item"; - const LABEL_MIDDLE2: &str = " = "; - const LABEL_END: &str = ">"; - - max_length = max_length.map(|len| { - len.saturating_sub( - LABEL_START.len() - + LABEL_ITERATOR.len() - + LABEL_MIDDLE.len() - + LABEL_MIDDLE2.len() - + LABEL_END.len(), - ) - }); - - label_builder.write_str(LABEL_START)?; - label_builder.start_location_link(ModuleDef::from(iter_trait).into()); - label_builder.write_str(LABEL_ITERATOR)?; - label_builder.end_location_link(); - label_builder.write_str(LABEL_MIDDLE)?; - label_builder.start_location_link(ModuleDef::from(item).into()); - label_builder.write_str(LABEL_ITEM)?; - label_builder.end_location_link(); - label_builder.write_str(LABEL_MIDDLE2)?; - rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?; - label_builder.write_str(LABEL_END)?; - Ok(()) + hir::attach_db(sema.db, || { + let iter_item_type = hint_iterator(sema, famous_defs, ty); + match iter_item_type { + Some((iter_trait, item, ty)) => { + const LABEL_START: &str = "impl "; + const LABEL_ITERATOR: &str = "Iterator"; + const LABEL_MIDDLE: &str = "<"; + const LABEL_ITEM: &str = "Item"; + const LABEL_MIDDLE2: &str = " = "; + const LABEL_END: &str = ">"; + + max_length = max_length.map(|len| { + len.saturating_sub( + LABEL_START.len() + + LABEL_ITERATOR.len() + + LABEL_MIDDLE.len() + + LABEL_MIDDLE2.len() + + LABEL_END.len(), + ) + }); + + label_builder.write_str(LABEL_START)?; + label_builder.start_location_link(ModuleDef::from(iter_trait).into()); + label_builder.write_str(LABEL_ITERATOR)?; + label_builder.end_location_link(); + label_builder.write_str(LABEL_MIDDLE)?; + label_builder.start_location_link(ModuleDef::from(item).into()); + label_builder.write_str(LABEL_ITEM)?; + label_builder.end_location_link(); + label_builder.write_str(LABEL_MIDDLE2)?; + rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?; + label_builder.write_str(LABEL_END)?; + Ok(()) + } + None => ty + .display_truncated(sema.db, max_length, display_target) + .with_closure_style(config.closure_style) + .write_to(label_builder), } - None => ty - .display_truncated(sema.db, max_length, display_target) - .with_closure_style(config.closure_style) - .write_to(label_builder), - } + }) } let mut label_builder = InlayHintLabelBuilder { - db: sema.db, + sema, last_part: String::new(), location: None, result: InlayHintLabel::default(), @@ -824,7 +837,7 @@ fn hint_iterator<'db>( fn ty_to_text_edit( sema: &Semantics<'_, RootDatabase>, - config: &InlayHintsConfig, + config: &InlayHintsConfig<'_>, node_for_hint: &SyntaxNode, ty: &hir::Type<'_>, offset_to_insert_ty: TextSize, @@ -855,6 +868,7 @@ mod tests { use expect_test::Expect; use hir::ClosureStyle; + use ide_db::MiniCore; use itertools::Itertools; use test_utils::extract_annotations; @@ -864,7 +878,7 @@ mod tests { use super::{ClosureReturnTypeHints, GenericParameterHints, InlayFieldsToResolve}; - pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig { + pub(super) const DISABLED_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig { discriminant_hints: DiscriminantHints::Never, render_colons: false, type_hints: false, @@ -880,6 +894,7 @@ mod tests { closure_return_type_hints: ClosureReturnTypeHints::Never, closure_capture_hints: false, adjustment_hints: AdjustmentHints::Never, + adjustment_hints_disable_reborrows: false, adjustment_hints_mode: AdjustmentHintsMode::Prefix, adjustment_hints_hide_outside_unsafe: false, binding_mode_hints: false, @@ -893,8 +908,9 @@ mod tests { fields_to_resolve: InlayFieldsToResolve::empty(), implicit_drop_hints: false, range_exclusive_hints: false, + minicore: MiniCore::default(), }; - pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig { + pub(super) const TEST_CONFIG: InlayHintsConfig<'_> = InlayHintsConfig { type_hints: true, parameter_hints: true, chaining_hints: true, @@ -911,7 +927,7 @@ mod tests { #[track_caller] pub(super) fn check_with_config( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, ) { let (analysis, file_id) = fixture::file(ra_fixture); @@ -930,7 +946,7 @@ mod tests { #[track_caller] pub(super) fn check_expect( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { @@ -945,7 +961,7 @@ mod tests { /// expect test. #[track_caller] pub(super) fn check_edit( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { @@ -968,7 +984,7 @@ mod tests { #[track_caller] pub(super) fn check_no_edit( - config: InlayHintsConfig, + config: InlayHintsConfig<'_>, #[rust_analyzer::rust_fixture] ra_fixture: &str, ) { let (analysis, file_id) = fixture::file(ra_fixture); @@ -1065,4 +1081,34 @@ fn bar() { "#, ); } + + #[test] + fn regression_20239() { + check_with_config( + InlayHintsConfig { parameter_hints: true, type_hints: true, ..DISABLED_CONFIG }, + r#" +//- minicore: fn +trait Iterator { + type Item; + fn map<B, F: FnMut(Self::Item) -> B>(self, f: F); +} +trait ToString { + fn to_string(&self); +} + +fn check_tostr_eq<L, R>(left: L, right: R) +where + L: Iterator, + L::Item: ToString, + R: Iterator, + R::Item: ToString, +{ + left.map(|s| s.to_string()); + // ^ impl ToString + right.map(|s| s.to_string()); + // ^ impl ToString +} + "#, + ); + } } |