|
9 | 9 |
|
10 | 10 | use std::collections::HashMap; |
11 | 11 |
|
| 12 | +use dupe::Dupe; |
12 | 13 | use lsp_types::Hover; |
13 | 14 | use lsp_types::HoverContents; |
14 | 15 | use lsp_types::MarkupContent; |
@@ -310,6 +311,22 @@ fn identifier_text_at( |
310 | 311 | .map(|id| id.identifier.id.to_string()) |
311 | 312 | } |
312 | 313 |
|
| 314 | +/// Hover should still work when the use site has no type trace, as in |
| 315 | +/// `Annotated[..., imported_symbol]` metadata. In that case, recover the type |
| 316 | +/// from the resolved definition instead of returning no hover at all. |
| 317 | +fn hover_type_from_definition( |
| 318 | + transaction: &Transaction<'_>, |
| 319 | + current_handle: &Handle, |
| 320 | + definition: &FindDefinitionItemWithDocstring, |
| 321 | +) -> Option<Type> { |
| 322 | + let definition_handle = Handle::new( |
| 323 | + definition.module.name(), |
| 324 | + definition.module.path().dupe(), |
| 325 | + current_handle.sys_info().dupe(), |
| 326 | + ); |
| 327 | + transaction.get_type_at(&definition_handle, definition.definition_range.start()) |
| 328 | +} |
| 329 | + |
313 | 330 | fn collect_typed_dict_fields_for_hover<'a>( |
314 | 331 | solver: &AnswersSolver<TransactionHandle<'a>>, |
315 | 332 | ty: &Type, |
@@ -513,8 +530,28 @@ pub fn get_hover( |
513 | 530 | }); |
514 | 531 | } |
515 | 532 |
|
516 | | - // Otherwise, fall through to the existing type hover logic |
517 | | - let mut type_ = transaction.get_type_at(handle, position)?; |
| 533 | + let definition = transaction |
| 534 | + .find_definition( |
| 535 | + handle, |
| 536 | + position, |
| 537 | + FindPreference { |
| 538 | + prefer_pyi: false, |
| 539 | + ..Default::default() |
| 540 | + }, |
| 541 | + ) |
| 542 | + .map(Vec1::into_vec) |
| 543 | + .unwrap_or_default() |
| 544 | + .into_iter() |
| 545 | + .next(); |
| 546 | + |
| 547 | + // Otherwise, fall through to the existing type hover logic. Some |
| 548 | + // annotation metadata names do not get a type trace at the use site, so |
| 549 | + // recover their hover type from the resolved definition. |
| 550 | + let mut type_ = transaction.get_type_at(handle, position).or_else(|| { |
| 551 | + definition |
| 552 | + .as_ref() |
| 553 | + .and_then(|definition| hover_type_from_definition(transaction, handle, definition)) |
| 554 | + })?; |
518 | 555 |
|
519 | 556 | // Helper function to check if we're hovering over a callee and get its range |
520 | 557 | let find_callee_range_at_position = || -> Option<TextRange> { |
@@ -555,20 +592,7 @@ pub fn get_hover( |
555 | 592 | module, |
556 | 593 | docstring_range, |
557 | 594 | display_name, |
558 | | - }) = transaction |
559 | | - .find_definition( |
560 | | - handle, |
561 | | - position, |
562 | | - FindPreference { |
563 | | - prefer_pyi: false, |
564 | | - ..Default::default() |
565 | | - }, |
566 | | - ) |
567 | | - .map(Vec1::into_vec) |
568 | | - .unwrap_or_default() |
569 | | - // TODO: handle more than 1 definition |
570 | | - .into_iter() |
571 | | - .next() |
| 595 | + }) = definition |
572 | 596 | { |
573 | 597 | let kind = metadata.symbol_kind(); |
574 | 598 | let name = { |
|
0 commit comments