Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #21393 from benodiwal/fix/generic-param-inlay-hint-location-links
feat: Add location links for generic parameter type hints
| -rw-r--r-- | crates/hir-ty/src/display.rs | 18 | ||||
| -rw-r--r-- | crates/hir/src/lib.rs | 8 | ||||
| -rw-r--r-- | crates/ide/src/inlay_hints.rs | 19 | ||||
| -rw-r--r-- | crates/ide/src/inlay_hints/bind_pat.rs | 129 |
4 files changed, 165 insertions, 9 deletions
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 44bbd84003..43b428c3fa 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -10,7 +10,8 @@ use std::{ use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - FindPathConfig, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId, + FindPathConfig, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, ModuleDefId, + ModuleId, TraitId, db::DefDatabase, expr_store::{ExpressionStore, path::Path}, find_path::{self, PrefixKind}, @@ -66,6 +67,7 @@ pub type Result<T = (), E = HirDisplayError> = std::result::Result<T, E>; pub trait HirWrite: fmt::Write { fn start_location_link(&mut self, _location: ModuleDefId) {} + fn start_location_link_generic(&mut self, _location: GenericParamId) {} fn end_location_link(&mut self) {} } @@ -147,6 +149,10 @@ impl<'db> HirFormatter<'_, 'db> { self.fmt.start_location_link(location); } + pub fn start_location_link_generic(&mut self, location: GenericParamId) { + self.fmt.start_location_link_generic(location); + } + pub fn end_location_link(&mut self) { self.fmt.end_location_link(); } @@ -686,7 +692,9 @@ impl<'db> HirDisplay<'db> for Const<'db> { ConstKind::Param(param) => { let generics = generics(f.db, param.id.parent()); let param_data = &generics[param.id.local_id()]; + f.start_location_link_generic(param.id.into()); write!(f, "{}", param_data.name().unwrap().display(f.db, f.edition()))?; + f.end_location_link(); Ok(()) } ConstKind::Value(const_bytes) => render_const_scalar( @@ -1489,6 +1497,7 @@ impl<'db> HirDisplay<'db> for Ty<'db> { match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { + f.start_location_link_generic(param.id.into()); write!( f, "{}", @@ -1496,7 +1505,8 @@ impl<'db> HirDisplay<'db> for Ty<'db> { .clone() .unwrap_or_else(Name::missing) .display(f.db, f.edition()) - )? + )?; + f.end_location_link(); } TypeParamProvenance::ArgumentImplTrait => { let bounds = GenericPredicates::query_all(f.db, param.id.parent()) @@ -1519,7 +1529,9 @@ impl<'db> HirDisplay<'db> for Ty<'db> { } }, TypeOrConstParamData::ConstParamData(p) => { + f.start_location_link_generic(param.id.into()); write!(f, "{}", p.name.display(f.db, f.edition()))?; + f.end_location_link(); } } } @@ -2031,7 +2043,9 @@ impl<'db> HirDisplay<'db> for Region<'db> { RegionKind::ReEarlyParam(param) => { let generics = generics(f.db, param.id.parent); let param_data = &generics[param.id.local_id]; + f.start_location_link_generic(param.id.into()); write!(f, "{}", param_data.name.display(f.db, f.edition()))?; + f.end_location_link(); Ok(()) } RegionKind::ReBound(BoundVarIndexKind::Bound(db), idx) => { diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 1ab57c4489..65de6c0a55 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -50,9 +50,9 @@ use either::Either; use hir_def::{ AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, - GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, - MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, - TypeOrConstParamId, TypeParamId, UnionId, + HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander, + MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId, + TypeParamId, UnionId, attrs::AttrFlags, builtin_derive::BuiltinDeriveImplMethod, expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap}, @@ -150,7 +150,7 @@ pub use { visibility::Visibility, // FIXME: This is here since some queries take it as input that are used // outside of hir. - {ModuleDefId, TraitId}, + {GenericParamId, ModuleDefId, TraitId}, }, hir_expand::{ EditionedFileId, ExpandResult, HirFileId, MacroCallId, MacroKind, diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 06ae0b1d73..a58dc6f030 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -5,8 +5,8 @@ use std::{ use either::Either; use hir::{ - ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError, - HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, + ClosureStyle, DisplayTarget, EditionedFileId, GenericParam, GenericParamId, HasVisibility, + HirDisplay, HirDisplayError, HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, }; use ide_db::{ FileRange, MiniCore, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder, @@ -709,6 +709,21 @@ impl HirWrite for InlayHintLabelBuilder<'_> { }); } + fn start_location_link_generic(&mut self, def: GenericParamId) { + never!(self.location.is_some(), "location link is already started"); + self.make_new_part(); + + self.location = Some(if self.resolve { + LazyProperty::Lazy + } else { + LazyProperty::Computed({ + let Some(location) = GenericParam::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() } + }) + }); + } + fn end_location_link(&mut self) { self.make_new_part(); } diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs index 547004687c..c74e3104c1 100644 --- a/crates/ide/src/inlay_hints/bind_pat.rs +++ b/crates/ide/src/inlay_hints/bind_pat.rs @@ -183,7 +183,8 @@ mod tests { use crate::{ClosureReturnTypeHints, fixture, inlay_hints::InlayHintsConfig}; use crate::inlay_hints::tests::{ - DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_no_edit, check_with_config, + DISABLED_CONFIG, TEST_CONFIG, check, check_edit, check_expect, check_no_edit, + check_with_config, }; #[track_caller] @@ -1255,4 +1256,130 @@ where "#, ); } + + #[test] + fn type_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +fn identity<T>(t: T) -> T { + let x = t; + x +} +"#, + expect![[r#" + [ + ( + 36..37, + [ + InlayHintLabelPart { + text: "T", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 12..13, + }, + ), + ), + tooltip: "", + }, + ], + ), + ] + "#]], + ); + } + + #[test] + fn const_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +fn f<const N: usize>() { + let x = [0; N]; +} +"#, + expect![[r#" + [ + ( + 33..34, + [ + "[i32; ", + InlayHintLabelPart { + text: "N", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 11..12, + }, + ), + ), + tooltip: "", + }, + "]", + ], + ), + ] + "#]], + ); + } + + #[test] + fn lifetime_param_inlay_hint_has_location_link() { + check_expect( + InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, + r#" +struct S<'lt>(*mut &'lt ()); + +fn f<'a>() { + let x = S::<'a>(loop {}); +} +"#, + expect![[r#" + [ + ( + 51..52, + [ + InlayHintLabelPart { + text: "S", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 7..8, + }, + ), + ), + tooltip: "", + }, + "<", + InlayHintLabelPart { + text: "'a", + linked_location: Some( + Computed( + FileRangeWrapper { + file_id: FileId( + 0, + ), + range: 35..37, + }, + ), + ), + tooltip: "", + }, + ">", + ], + ), + ] + "#]], + ); + } } |