Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/ide/src/hover.rs55
-rw-r--r--crates/ide/src/hover/render.rs86
-rw-r--r--crates/ide/src/hover/tests.rs559
3 files changed, 378 insertions, 322 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 5ed3b2dbbc..77a06a97e2 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -393,30 +393,7 @@ pub(crate) fn hover_for_definition(
Definition::BuiltinType(it) => Some(it.ty(db)),
_ => None,
};
- let notable_traits = def_ty
- .map(|ty| {
- db.notable_traits_in_deps(ty.krate(db).into())
- .iter()
- .flat_map(|it| &**it)
- .filter_map(move |&trait_| {
- let trait_ = trait_.into();
- ty.impls_trait(db, trait_, &[]).then(|| {
- (
- trait_,
- trait_
- .items(db)
- .into_iter()
- .filter_map(hir::AssocItem::as_type_alias)
- .map(|alias| {
- (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db))
- })
- .collect::<Vec<_>>(),
- )
- })
- })
- .collect::<Vec<_>>()
- })
- .unwrap_or_default();
+ let notable_traits = def_ty.map(|ty| notable_traits(db, &ty)).unwrap_or_default();
render::definition(sema.db, def, famous_defs.as_ref(), &notable_traits, config).map(|markup| {
HoverResult {
@@ -434,6 +411,32 @@ pub(crate) fn hover_for_definition(
})
}
+fn notable_traits(
+ db: &RootDatabase,
+ ty: &hir::Type,
+) -> Vec<(hir::Trait, Vec<(Option<hir::Type>, hir::Name)>)> {
+ db.notable_traits_in_deps(ty.krate(db).into())
+ .iter()
+ .flat_map(|it| &**it)
+ .filter_map(move |&trait_| {
+ let trait_ = trait_.into();
+ ty.impls_trait(db, trait_, &[]).then(|| {
+ (
+ trait_,
+ trait_
+ .items(db)
+ .into_iter()
+ .filter_map(hir::AssocItem::as_type_alias)
+ .map(|alias| {
+ (ty.normalize_trait_assoc_type(db, &[], alias), alias.name(db))
+ })
+ .collect::<Vec<_>>(),
+ )
+ })
+ })
+ .collect::<Vec<_>>()
+}
+
fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
fn to_action(nav_target: NavigationTarget) -> HoverAction {
HoverAction::Implementation(FilePosition {
@@ -583,7 +586,9 @@ fn dedupe_or_merge_hover_actions(actions: Vec<HoverAction>) -> Vec<HoverAction>
}
if !go_to_type_targets.is_empty() {
- deduped_actions.push(HoverAction::GoToType(go_to_type_targets.into_iter().collect()));
+ deduped_actions.push(HoverAction::GoToType(
+ go_to_type_targets.into_iter().sorted_by(|a, b| a.mod_path.cmp(&b.mod_path)).collect(),
+ ));
}
deduped_actions
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 511137f67c..787b74fc62 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -3,8 +3,8 @@ use std::{mem, ops::Not};
use either::Either;
use hir::{
- Adt, AsAssocItem, CaptureKind, HasSource, HirDisplay, Layout, LayoutError, Name, Semantics,
- Trait, Type, TypeInfo,
+ Adt, AsAssocItem, CaptureKind, HasCrate, HasSource, HirDisplay, Layout, LayoutError, Name,
+ Semantics, Trait, Type, TypeInfo,
};
use ide_db::{
base_db::SourceDatabase,
@@ -25,7 +25,7 @@ use syntax::{
use crate::{
doc_links::{remove_links, rewrite_links},
- hover::walk_and_push_ty,
+ hover::{notable_traits, walk_and_push_ty},
HoverAction, HoverConfig, HoverResult, Markup, MemoryLayoutHoverConfig,
MemoryLayoutHoverRenderKind,
};
@@ -471,38 +471,8 @@ pub(super) fn definition(
_ => None,
};
- let notable_traits = {
- let mut desc = String::new();
- let mut needs_impl_header = true;
- for (trait_, assoc_types) in notable_traits {
- desc.push_str(if mem::take(&mut needs_impl_header) {
- " // notable traits implemented: "
- } else {
- ", "
- });
- format_to!(desc, "{}", trait_.name(db).display(db),);
- if !assoc_types.is_empty() {
- desc.push('<');
- format_to!(
- desc,
- "{}",
- assoc_types.into_iter().format_with(", ", |(ty, name), f| {
- f(&name.display(db))?;
- f(&" = ")?;
- match ty {
- Some(ty) => f(&ty.display(db)),
- None => f(&"?"),
- }
- })
- );
- desc.push('>');
- }
- }
- desc.is_empty().not().then(|| desc)
- };
-
let mut desc = String::new();
- if let Some(notable_traits) = notable_traits {
+ if let Some(notable_traits) = render_notable_trait_comment(db, notable_traits) {
desc.push_str(&notable_traits);
desc.push('\n');
}
@@ -519,6 +489,39 @@ pub(super) fn definition(
markup(docs.map(Into::into), desc, mod_path)
}
+fn render_notable_trait_comment(
+ db: &RootDatabase,
+ notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
+) -> Option<String> {
+ let mut desc = String::new();
+ let mut needs_impl_header = true;
+ for (trait_, assoc_types) in notable_traits {
+ desc.push_str(if mem::take(&mut needs_impl_header) {
+ " // notable traits implemented: "
+ } else {
+ ", "
+ });
+ format_to!(desc, "{}", trait_.name(db).display(db),);
+ if !assoc_types.is_empty() {
+ desc.push('<');
+ format_to!(
+ desc,
+ "{}",
+ assoc_types.into_iter().format_with(", ", |(ty, name), f| {
+ f(&name.display(db))?;
+ f(&" = ")?;
+ match ty {
+ Some(ty) => f(&ty.display(db)),
+ None => f(&"?"),
+ }
+ })
+ );
+ desc.push('>');
+ }
+ }
+ desc.is_empty().not().then(|| desc)
+}
+
fn type_info(
sema: &Semantics<'_, RootDatabase>,
config: &HoverConfig,
@@ -536,8 +539,12 @@ fn type_info(
}
};
walk_and_push_ty(sema.db, &original, &mut push_new_def);
-
- res.markup = if let Some(adjusted_ty) = adjusted {
+ let mut desc = match render_notable_trait_comment(sema.db, &notable_traits(sema.db, &original))
+ {
+ Some(desc) => desc + "\n",
+ None => String::new(),
+ };
+ desc += &if let Some(adjusted_ty) = adjusted {
walk_and_push_ty(sema.db, &adjusted_ty, &mut push_new_def);
let original = original.display(sema.db).to_string();
let adjusted = adjusted_ty.display(sema.db).to_string();
@@ -549,10 +556,10 @@ fn type_info(
apad = static_text_diff_len + adjusted.len().max(original.len()),
opad = original.len(),
)
- .into()
} else {
- Markup::fenced_block(&original.display(sema.db))
+ Markup::fenced_block(&original.display(sema.db)).into()
};
+ res.markup = desc.into();
if let Some(actions) = HoverAction::goto_type_from_targets(sema.db, targets) {
res.actions.push(actions);
}
@@ -607,6 +614,9 @@ fn closure_ty(
{
format_to!(markup, "{layout}");
}
+ if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) {
+ push_new_def(hir::Trait::from(trait_).into())
+ }
format_to!(
markup,
"\n{}\n```{adjusted}\n\n## Captures\n{}",
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 09548745f6..d8d439c0d2 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -400,6 +400,20 @@ fn main() {
description: "struct S",
},
},
+ HoverGotoTypeData {
+ mod_path: "core::ops::function::FnOnce",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 1,
+ ),
+ full_range: 631..866,
+ focus_range: 692..698,
+ name: "FnOnce",
+ kind: Trait,
+ container_name: "function",
+ description: "pub trait FnOnce<Args>\nwhere\n Args: Tuple,",
+ },
+ },
],
),
]
@@ -2387,39 +2401,39 @@ struct S<T>{ f1: T }
fn main() { let s$0t = S{ f1:Arg(0) }; }
"#,
expect![[r#"
- [
- GoToType(
- [
- HoverGotoTypeData {
- mod_path: "test::S",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 17..37,
- focus_range: 24..25,
- name: "S",
- kind: Struct,
- description: "struct S<T> {\n f1: T,\n}",
- },
+ [
+ GoToType(
+ [
+ HoverGotoTypeData {
+ mod_path: "test::Arg",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..16,
+ focus_range: 7..10,
+ name: "Arg",
+ kind: Struct,
+ description: "struct Arg(u32);",
},
- HoverGotoTypeData {
- mod_path: "test::Arg",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 0..16,
- focus_range: 7..10,
- name: "Arg",
- kind: Struct,
- description: "struct Arg(u32);",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::S",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 17..37,
+ focus_range: 24..25,
+ name: "S",
+ kind: Struct,
+ description: "struct S<T> {\n f1: T,\n}",
},
- ],
- ),
- ]
- "#]],
+ },
+ ],
+ ),
+ ]
+ "#]],
);
}
@@ -2446,39 +2460,39 @@ struct S<T>{ f1: T }
fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
"#,
expect![[r#"
- [
- GoToType(
- [
- HoverGotoTypeData {
- mod_path: "test::S",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 17..37,
- focus_range: 24..25,
- name: "S",
- kind: Struct,
- description: "struct S<T> {\n f1: T,\n}",
- },
+ [
+ GoToType(
+ [
+ HoverGotoTypeData {
+ mod_path: "test::Arg",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..16,
+ focus_range: 7..10,
+ name: "Arg",
+ kind: Struct,
+ description: "struct Arg(u32);",
},
- HoverGotoTypeData {
- mod_path: "test::Arg",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 0..16,
- focus_range: 7..10,
- name: "Arg",
- kind: Struct,
- description: "struct Arg(u32);",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::S",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 17..37,
+ focus_range: 24..25,
+ name: "S",
+ kind: Struct,
+ description: "struct S<T> {\n f1: T,\n}",
},
- ],
- ),
- ]
- "#]],
+ },
+ ],
+ ),
+ ]
+ "#]],
);
}
@@ -2636,39 +2650,39 @@ fn foo() -> impl Foo + Bar {}
fn main() { let s$0t = foo(); }
"#,
expect![[r#"
- [
- GoToType(
- [
- HoverGotoTypeData {
- mod_path: "test::Foo",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 0..12,
- focus_range: 6..9,
- name: "Foo",
- kind: Trait,
- description: "trait Foo",
- },
+ [
+ GoToType(
+ [
+ HoverGotoTypeData {
+ mod_path: "test::Bar",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 13..25,
+ focus_range: 19..22,
+ name: "Bar",
+ kind: Trait,
+ description: "trait Bar",
},
- HoverGotoTypeData {
- mod_path: "test::Bar",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 13..25,
- focus_range: 19..22,
- name: "Bar",
- kind: Trait,
- description: "trait Bar",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::Foo",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..12,
+ focus_range: 6..9,
+ name: "Foo",
+ kind: Trait,
+ description: "trait Foo",
},
- ],
- ),
- ]
- "#]],
+ },
+ ],
+ ),
+ ]
+ "#]],
);
}
@@ -2686,65 +2700,65 @@ fn foo() -> impl Foo<S1> + Bar<S2> {}
fn main() { let s$0t = foo(); }
"#,
expect![[r#"
- [
- GoToType(
- [
- HoverGotoTypeData {
- mod_path: "test::Foo",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 0..15,
- focus_range: 6..9,
- name: "Foo",
- kind: Trait,
- description: "trait Foo<T>",
- },
+ [
+ GoToType(
+ [
+ HoverGotoTypeData {
+ mod_path: "test::Bar",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 16..31,
+ focus_range: 22..25,
+ name: "Bar",
+ kind: Trait,
+ description: "trait Bar<T>",
},
- HoverGotoTypeData {
- mod_path: "test::Bar",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 16..31,
- focus_range: 22..25,
- name: "Bar",
- kind: Trait,
- description: "trait Bar<T>",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::Foo",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..15,
+ focus_range: 6..9,
+ name: "Foo",
+ kind: Trait,
+ description: "trait Foo<T>",
},
- HoverGotoTypeData {
- mod_path: "test::S1",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 32..44,
- focus_range: 39..41,
- name: "S1",
- kind: Struct,
- description: "struct S1 {}",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::S1",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 32..44,
+ focus_range: 39..41,
+ name: "S1",
+ kind: Struct,
+ description: "struct S1 {}",
},
- HoverGotoTypeData {
- mod_path: "test::S2",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 45..57,
- focus_range: 52..54,
- name: "S2",
- kind: Struct,
- description: "struct S2 {}",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::S2",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 45..57,
+ focus_range: 52..54,
+ name: "S2",
+ kind: Struct,
+ description: "struct S2 {}",
},
- ],
- ),
- ]
- "#]],
+ },
+ ],
+ ),
+ ]
+ "#]],
);
}
@@ -2790,52 +2804,52 @@ struct S{}
fn foo(ar$0g: &impl Foo + Bar<S>) {}
"#,
expect![[r#"
- [
- GoToType(
- [
- HoverGotoTypeData {
- mod_path: "test::Foo",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 0..12,
- focus_range: 6..9,
- name: "Foo",
- kind: Trait,
- description: "trait Foo",
- },
+ [
+ GoToType(
+ [
+ HoverGotoTypeData {
+ mod_path: "test::Bar",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 13..28,
+ focus_range: 19..22,
+ name: "Bar",
+ kind: Trait,
+ description: "trait Bar<T>",
},
- HoverGotoTypeData {
- mod_path: "test::Bar",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 13..28,
- focus_range: 19..22,
- name: "Bar",
- kind: Trait,
- description: "trait Bar<T>",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::Foo",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..12,
+ focus_range: 6..9,
+ name: "Foo",
+ kind: Trait,
+ description: "trait Foo",
},
- HoverGotoTypeData {
- mod_path: "test::S",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 29..39,
- focus_range: 36..37,
- name: "S",
- kind: Struct,
- description: "struct S {}",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::S",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 29..39,
+ focus_range: 36..37,
+ name: "S",
+ kind: Struct,
+ description: "struct S {}",
},
- ],
- ),
- ]
- "#]],
+ },
+ ],
+ ),
+ ]
+ "#]],
);
}
@@ -3077,65 +3091,65 @@ struct S {}
fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
"#,
expect![[r#"
- [
- GoToType(
- [
- HoverGotoTypeData {
- mod_path: "test::ImplTrait",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 0..21,
- focus_range: 6..15,
- name: "ImplTrait",
- kind: Trait,
- description: "trait ImplTrait<T>",
- },
+ [
+ GoToType(
+ [
+ HoverGotoTypeData {
+ mod_path: "test::B",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 43..57,
+ focus_range: 50..51,
+ name: "B",
+ kind: Struct,
+ description: "struct B<T> {}",
},
- HoverGotoTypeData {
- mod_path: "test::B",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 43..57,
- focus_range: 50..51,
- name: "B",
- kind: Struct,
- description: "struct B<T> {}",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::DynTrait",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 22..42,
+ focus_range: 28..36,
+ name: "DynTrait",
+ kind: Trait,
+ description: "trait DynTrait<T>",
},
- HoverGotoTypeData {
- mod_path: "test::DynTrait",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 22..42,
- focus_range: 28..36,
- name: "DynTrait",
- kind: Trait,
- description: "trait DynTrait<T>",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::ImplTrait",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 0..21,
+ focus_range: 6..15,
+ name: "ImplTrait",
+ kind: Trait,
+ description: "trait ImplTrait<T>",
},
- HoverGotoTypeData {
- mod_path: "test::S",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 58..69,
- focus_range: 65..66,
- name: "S",
- kind: Struct,
- description: "struct S {}",
- },
+ },
+ HoverGotoTypeData {
+ mod_path: "test::S",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 58..69,
+ focus_range: 65..66,
+ name: "S",
+ kind: Struct,
+ description: "struct S {}",
},
- ],
- ),
- ]
- "#]],
+ },
+ ],
+ ),
+ ]
+ "#]],
);
}
@@ -7121,6 +7135,33 @@ impl Iterator for S {
}
#[test]
+fn notable_ranged() {
+ check_hover_range(
+ r#"
+//- minicore: future, iterator
+struct S;
+#[doc(notable_trait)]
+trait Notable {}
+impl Notable for S {}
+impl core::future::Future for S {
+ type Output = u32;
+}
+impl Iterator for S {
+ type Item = S;
+}
+fn main() {
+ $0S$0;
+}
+"#,
+ expect![[r#"
+ // notable traits implemented: Notable, Future<Output = u32>, Iterator<Item = S>
+ ```rust
+ S
+ ```"#]],
+ );
+}
+
+#[test]
fn notable_actions() {
check_actions(
r#"
@@ -7150,19 +7191,6 @@ impl Iterator for S {
GoToType(
[
HoverGotoTypeData {
- mod_path: "test::Notable",
- nav: NavigationTarget {
- file_id: FileId(
- 0,
- ),
- full_range: 21..59,
- focus_range: 49..56,
- name: "Notable",
- kind: Trait,
- description: "trait Notable",
- },
- },
- HoverGotoTypeData {
mod_path: "core::future::Future",
nav: NavigationTarget {
file_id: FileId(
@@ -7191,6 +7219,19 @@ impl Iterator for S {
},
},
HoverGotoTypeData {
+ mod_path: "test::Notable",
+ nav: NavigationTarget {
+ file_id: FileId(
+ 0,
+ ),
+ full_range: 21..59,
+ focus_range: 49..56,
+ name: "Notable",
+ kind: Trait,
+ description: "trait Notable",
+ },
+ },
+ HoverGotoTypeData {
mod_path: "test::S2",
nav: NavigationTarget {
file_id: FileId(