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
Lukas Wirth 4 months ago
parent e19dfc8 · parent 0082ec1 · commit 8f5634a
-rw-r--r--crates/hir-ty/src/display.rs18
-rw-r--r--crates/hir/src/lib.rs8
-rw-r--r--crates/ide/src/inlay_hints.rs19
-rw-r--r--crates/ide/src/inlay_hints/bind_pat.rs129
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: "",
+ },
+ ">",
+ ],
+ ),
+ ]
+ "#]],
+ );
+ }
}