diff options
Diffstat (limited to 'crates/ide/src/hover.rs')
-rw-r--r-- | crates/ide/src/hover.rs | 74 |
1 files changed, 55 insertions, 19 deletions
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 73245fbe7..2737c900f 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -13,7 +13,7 @@ use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, | |||
13 | use test_utils::mark; | 13 | use test_utils::mark; |
14 | 14 | ||
15 | use crate::{ | 15 | use crate::{ |
16 | display::{macro_label, ShortLabel, ToNav, TryToNav}, | 16 | display::{macro_label, ShortLabel, TryToNav}, |
17 | doc_links::{remove_links, rewrite_links}, | 17 | doc_links::{remove_links, rewrite_links}, |
18 | markdown_remove::remove_markdown, | 18 | markdown_remove::remove_markdown, |
19 | markup::Markup, | 19 | markup::Markup, |
@@ -109,6 +109,8 @@ pub(crate) fn hover( | |||
109 | match node { | 109 | match node { |
110 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), | 110 | ast::Name(name) => NameClass::classify(&sema, &name).and_then(|d| d.defined(sema.db)), |
111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), | 111 | ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), |
112 | ast::Lifetime(lifetime) => NameClass::classify_lifetime(&sema, &lifetime) | ||
113 | .map_or_else(|| NameRefClass::classify_lifetime(&sema, &lifetime).map(|d| d.referenced(sema.db)), |d| d.defined(sema.db)), | ||
112 | _ => None, | 114 | _ => None, |
113 | } | 115 | } |
114 | }; | 116 | }; |
@@ -181,10 +183,10 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov | |||
181 | 183 | ||
182 | match def { | 184 | match def { |
183 | Definition::ModuleDef(it) => match it { | 185 | Definition::ModuleDef(it) => match it { |
184 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.to_nav(db))), | 186 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)), |
185 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.to_nav(db))), | 187 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)), |
186 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.to_nav(db))), | 188 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)), |
187 | ModuleDef::Trait(it) => Some(to_action(it.to_nav(db))), | 189 | ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)), |
188 | _ => None, | 190 | _ => None, |
189 | }, | 191 | }, |
190 | _ => None, | 192 | _ => None, |
@@ -204,7 +206,8 @@ fn runnable_action( | |||
204 | _ => None, | 206 | _ => None, |
205 | }, | 207 | }, |
206 | ModuleDef::Function(it) => { | 208 | ModuleDef::Function(it) => { |
207 | let src = it.source(sema.db); | 209 | #[allow(deprecated)] |
210 | let src = it.source(sema.db)?; | ||
208 | if src.file_id != file_id.into() { | 211 | if src.file_id != file_id.into() { |
209 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); | 212 | mark::hit!(hover_macro_generated_struct_fn_doc_comment); |
210 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); | 213 | mark::hit!(hover_macro_generated_struct_fn_doc_attr); |
@@ -324,17 +327,12 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
324 | let mod_path = definition_mod_path(db, &def); | 327 | let mod_path = definition_mod_path(db, &def); |
325 | return match def { | 328 | return match def { |
326 | Definition::Macro(it) => { | 329 | Definition::Macro(it) => { |
327 | // FIXME: Currently proc-macro do not have ast-node, | 330 | let label = macro_label(&it.source(db)?.value); |
328 | // such that it does not have source | ||
329 | // more discussion: https://github.com/rust-analyzer/rust-analyzer/issues/6913 | ||
330 | if it.is_proc_macro() { | ||
331 | return None; | ||
332 | } | ||
333 | let label = macro_label(&it.source(db).value); | ||
334 | from_def_source_labeled(db, it, Some(label), mod_path) | 331 | from_def_source_labeled(db, it, Some(label), mod_path) |
335 | } | 332 | } |
336 | Definition::Field(def) => { | 333 | Definition::Field(def) => { |
337 | let src = def.source(db).value; | 334 | #[allow(deprecated)] |
335 | let src = def.source(db)?.value; | ||
338 | if let FieldSource::Named(it) = src { | 336 | if let FieldSource::Named(it) = src { |
339 | from_def_source_labeled(db, def, it.short_label(), mod_path) | 337 | from_def_source_labeled(db, def, it.short_label(), mod_path) |
340 | } else { | 338 | } else { |
@@ -360,9 +358,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
360 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), | 358 | ModuleDef::Static(it) => from_def_source(db, it, mod_path), |
361 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), | 359 | ModuleDef::Trait(it) => from_def_source(db, it, mod_path), |
362 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), | 360 | ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path), |
363 | ModuleDef::BuiltinType(it) => return Some(it.to_string().into()), | 361 | ModuleDef::BuiltinType(it) => Some(Markup::fenced_block(&it)), |
364 | }, | 362 | }, |
365 | Definition::Local(it) => return Some(Markup::fenced_block(&it.ty(db).display(db))), | 363 | Definition::Local(it) => Some(Markup::fenced_block(&it.ty(db).display(db))), |
366 | Definition::SelfType(impl_def) => { | 364 | Definition::SelfType(impl_def) => { |
367 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { | 365 | impl_def.target_ty(db).as_adt().and_then(|adt| match adt { |
368 | Adt::Struct(it) => from_def_source(db, it, mod_path), | 366 | Adt::Struct(it) => from_def_source(db, it, mod_path), |
@@ -370,7 +368,9 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
370 | Adt::Enum(it) => from_def_source(db, it, mod_path), | 368 | Adt::Enum(it) => from_def_source(db, it, mod_path), |
371 | }) | 369 | }) |
372 | } | 370 | } |
373 | Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => { | 371 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
372 | Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), | ||
373 | Definition::TypeParam(_) | Definition::ConstParam(_) => { | ||
374 | // FIXME: Hover for generic param | 374 | // FIXME: Hover for generic param |
375 | None | 375 | None |
376 | } | 376 | } |
@@ -381,7 +381,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
381 | D: HasSource<Ast = A> + HasAttrs + Copy, | 381 | D: HasSource<Ast = A> + HasAttrs + Copy, |
382 | A: ShortLabel, | 382 | A: ShortLabel, |
383 | { | 383 | { |
384 | let short_label = def.source(db).value.short_label(); | 384 | #[allow(deprecated)] |
385 | let short_label = def.source(db)?.value.short_label(); | ||
385 | from_def_source_labeled(db, def, short_label, mod_path) | 386 | from_def_source_labeled(db, def, short_label, mod_path) |
386 | } | 387 | } |
387 | 388 | ||
@@ -403,7 +404,7 @@ fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { | |||
403 | return tokens.max_by_key(priority); | 404 | return tokens.max_by_key(priority); |
404 | fn priority(n: &SyntaxToken) -> usize { | 405 | fn priority(n: &SyntaxToken) -> usize { |
405 | match n.kind() { | 406 | match n.kind() { |
406 | IDENT | INT_NUMBER => 3, | 407 | IDENT | INT_NUMBER | LIFETIME_IDENT => 3, |
407 | T!['('] | T![')'] => 2, | 408 | T!['('] | T![')'] => 2, |
408 | kind if kind.is_trivia() => 0, | 409 | kind if kind.is_trivia() => 0, |
409 | _ => 1, | 410 | _ => 1, |
@@ -1169,7 +1170,10 @@ fn f() { fo<|>o!(); } | |||
1169 | r#"struct TS(String, i32<|>);"#, | 1170 | r#"struct TS(String, i32<|>);"#, |
1170 | expect![[r#" | 1171 | expect![[r#" |
1171 | *i32* | 1172 | *i32* |
1173 | |||
1174 | ```rust | ||
1172 | i32 | 1175 | i32 |
1176 | ``` | ||
1173 | "#]], | 1177 | "#]], |
1174 | ) | 1178 | ) |
1175 | } | 1179 | } |
@@ -3221,4 +3225,36 @@ fn no_hover() { | |||
3221 | "#, | 3225 | "#, |
3222 | ); | 3226 | ); |
3223 | } | 3227 | } |
3228 | |||
3229 | #[test] | ||
3230 | fn hover_label() { | ||
3231 | check( | ||
3232 | r#" | ||
3233 | fn foo() { | ||
3234 | 'label<|>: loop {} | ||
3235 | } | ||
3236 | "#, | ||
3237 | expect![[r#" | ||
3238 | *'label* | ||
3239 | |||
3240 | ```rust | ||
3241 | 'label | ||
3242 | ``` | ||
3243 | "#]], | ||
3244 | ); | ||
3245 | } | ||
3246 | |||
3247 | #[test] | ||
3248 | fn hover_lifetime() { | ||
3249 | check( | ||
3250 | r#"fn foo<'lifetime>(_: &'lifetime<|> ()) {}"#, | ||
3251 | expect![[r#" | ||
3252 | *'lifetime* | ||
3253 | |||
3254 | ```rust | ||
3255 | 'lifetime | ||
3256 | ``` | ||
3257 | "#]], | ||
3258 | ); | ||
3259 | } | ||
3224 | } | 3260 | } |