aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/hover.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/hover.rs')
-rw-r--r--crates/ide/src/hover.rs187
1 files changed, 172 insertions, 15 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index c43089476..9de653739 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,6 +1,6 @@
1use either::Either; 1use either::Either;
2use hir::{ 2use hir::{
3 AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, Module, 3 AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module,
4 ModuleDef, Semantics, 4 ModuleDef, Semantics,
5}; 5};
6use ide_db::{ 6use ide_db::{
@@ -16,8 +16,8 @@ use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, Toke
16use crate::{ 16use crate::{
17 display::{macro_label, TryToNav}, 17 display::{macro_label, TryToNav},
18 doc_links::{ 18 doc_links::{
19 doc_owner_to_def, extract_positioned_link_from_comment, remove_links, 19 doc_attributes, extract_definitions_from_markdown, remove_links, resolve_doc_path_for_def,
20 resolve_doc_path_for_def, rewrite_links, 20 rewrite_links,
21 }, 21 },
22 markdown_remove::remove_markdown, 22 markdown_remove::remove_markdown,
23 markup::Markup, 23 markup::Markup,
@@ -82,6 +82,8 @@ pub struct HoverResult {
82// 82//
83// Shows additional information, like type of an expression or documentation for definition when "focusing" code. 83// Shows additional information, like type of an expression or documentation for definition when "focusing" code.
84// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. 84// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
85//
86// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
85pub(crate) fn hover( 87pub(crate) fn hover(
86 db: &RootDatabase, 88 db: &RootDatabase,
87 position: FilePosition, 89 position: FilePosition,
@@ -114,11 +116,19 @@ pub(crate) fn hover(
114 ), 116 ),
115 117
116 _ => ast::Comment::cast(token.clone()) 118 _ => ast::Comment::cast(token.clone())
117 .and_then(|comment| { 119 .and_then(|_| {
120 let (attributes, def) = doc_attributes(&sema, &node)?;
121 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
118 let (idl_range, link, ns) = 122 let (idl_range, link, ns) =
119 extract_positioned_link_from_comment(position.offset, &comment)?; 123 extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| {
124 let InFile { file_id, value: range } = doc_mapping.map(range.clone())?;
125 if file_id == position.file_id.into() && range.contains(position.offset) {
126 Some((range, link, ns))
127 } else {
128 None
129 }
130 })?;
120 range = Some(idl_range); 131 range = Some(idl_range);
121 let def = doc_owner_to_def(&sema, &node)?;
122 resolve_doc_path_for_def(db, def, &link, ns) 132 resolve_doc_path_for_def(db, def, &link, ns)
123 }) 133 })
124 .map(Definition::ModuleDef), 134 .map(Definition::ModuleDef),
@@ -195,7 +205,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
195 let adt = match def { 205 let adt = match def {
196 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), 206 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action),
197 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), 207 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it),
198 Definition::SelfType(it) => it.target_ty(db).as_adt(), 208 Definition::SelfType(it) => it.self_ty(db).as_adt(),
199 _ => None, 209 _ => None,
200 }?; 210 }?;
201 adt.try_to_nav(db).map(to_action) 211 adt.try_to_nav(db).map(to_action)
@@ -318,7 +328,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
318 Definition::ModuleDef(md) => match md { 328 Definition::ModuleDef(md) => match md {
319 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { 329 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
320 AssocItemContainer::Trait(t) => Some(t.name(db)), 330 AssocItemContainer::Trait(t) => Some(t.name(db)),
321 AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), 331 AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
322 }, 332 },
323 ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), 333 ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)),
324 _ => None, 334 _ => None,
@@ -376,7 +386,7 @@ fn hover_for_definition(
376 }, 386 },
377 Definition::Local(it) => hover_for_local(it, db), 387 Definition::Local(it) => hover_for_local(it, db),
378 Definition::SelfType(impl_def) => { 388 Definition::SelfType(impl_def) => {
379 impl_def.target_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) 389 impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path))
380 } 390 }
381 Definition::GenericParam(it) => from_hir_fmt(db, it, None), 391 Definition::GenericParam(it) => from_hir_fmt(db, it, None),
382 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 392 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
@@ -470,6 +480,7 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module>
470 480
471fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 481fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
472 return tokens.max_by_key(priority); 482 return tokens.max_by_key(priority);
483
473 fn priority(n: &SyntaxToken) -> usize { 484 fn priority(n: &SyntaxToken) -> usize {
474 match n.kind() { 485 match n.kind() {
475 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, 486 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
@@ -1235,6 +1246,37 @@ fn f() { fo$0o!(); }
1235 } 1246 }
1236 1247
1237 #[test] 1248 #[test]
1249 fn test_hover_macro2_invocation() {
1250 check(
1251 r#"
1252/// foo bar
1253///
1254/// foo bar baz
1255macro foo() {}
1256
1257fn f() { fo$0o!(); }
1258"#,
1259 expect![[r#"
1260 *foo*
1261
1262 ```rust
1263 test
1264 ```
1265
1266 ```rust
1267 macro foo
1268 ```
1269
1270 ---
1271
1272 foo bar
1273
1274 foo bar baz
1275 "#]],
1276 )
1277 }
1278
1279 #[test]
1238 fn test_hover_tuple_field() { 1280 fn test_hover_tuple_field() {
1239 check( 1281 check(
1240 r#"struct TS(String, i32$0);"#, 1282 r#"struct TS(String, i32$0);"#,
@@ -3780,24 +3822,139 @@ fn main() {
3780 fn hover_intra_doc_links() { 3822 fn hover_intra_doc_links() {
3781 check( 3823 check(
3782 r#" 3824 r#"
3783/// This is the [`foo`](foo$0) function. 3825
3784fn foo() {} 3826pub mod theitem {
3827 /// This is the item. Cool!
3828 pub struct TheItem;
3829}
3830
3831/// Gives you a [`TheItem$0`].
3832///
3833/// [`TheItem`]: theitem::TheItem
3834pub fn gimme() -> theitem::TheItem {
3835 theitem::TheItem
3836}
3785"#, 3837"#,
3786 expect![[r#" 3838 expect![[r#"
3787 *[`foo`](foo)* 3839 *[`TheItem`]*
3788 3840
3789 ```rust 3841 ```rust
3790 test 3842 test::theitem
3791 ``` 3843 ```
3792 3844
3793 ```rust 3845 ```rust
3794 fn foo() 3846 pub struct TheItem
3795 ``` 3847 ```
3796 3848
3797 --- 3849 ---
3798 3850
3799 This is the [`foo`](https://docs.rs/test/*/test/fn.foo.html) function. 3851 This is the item. Cool!
3852 "#]],
3853 );
3854 }
3855
3856 #[test]
3857 fn hover_generic_assoc() {
3858 check(
3859 r#"
3860fn foo<T: A>() where T::Assoc$0: {}
3861
3862trait A {
3863 type Assoc;
3864}"#,
3865 expect![[r#"
3866 *Assoc*
3867
3868 ```rust
3869 test
3870 ```
3871
3872 ```rust
3873 type Assoc
3874 ```
3875 "#]],
3876 );
3877 check(
3878 r#"
3879fn foo<T: A>() {
3880 let _: <T>::Assoc$0;
3881}
3882
3883trait A {
3884 type Assoc;
3885}"#,
3886 expect![[r#"
3887 *Assoc*
3888
3889 ```rust
3890 test
3891 ```
3892
3893 ```rust
3894 type Assoc
3895 ```
3896 "#]],
3897 );
3898 check(
3899 r#"
3900trait A where
3901 Self::Assoc$0: ,
3902{
3903 type Assoc;
3904}"#,
3905 expect![[r#"
3906 *Assoc*
3907
3908 ```rust
3909 test
3910 ```
3911
3912 ```rust
3913 type Assoc
3914 ```
3800 "#]], 3915 "#]],
3801 ); 3916 );
3802 } 3917 }
3918
3919 #[test]
3920 fn string_shadowed_with_inner_items() {
3921 check(
3922 r#"
3923//- /main.rs crate:main deps:alloc
3924
3925/// Custom `String` type.
3926struct String;
3927
3928fn f() {
3929 let _: String$0;
3930
3931 fn inner() {}
3932}
3933
3934//- /alloc.rs crate:alloc
3935#[prelude_import]
3936pub use string::*;
3937
3938mod string {
3939 /// This is `alloc::String`.
3940 pub struct String;
3941}
3942 "#,
3943 expect![[r#"
3944 *String*
3945
3946 ```rust
3947 main
3948 ```
3949
3950 ```rust
3951 struct String
3952 ```
3953
3954 ---
3955
3956 Custom `String` type.
3957 "#]],
3958 )
3959 }
3803} 3960}