Skip to content

Commit 2e3d4f4

Browse files
fix
1 parent 947a3ee commit 2e3d4f4

2 files changed

Lines changed: 63 additions & 1 deletion

File tree

pyrefly/lib/lsp/wasm/hover.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use std::collections::HashMap;
1111

12+
use dupe::Dupe;
1213
use lsp_types::Hover;
1314
use lsp_types::HoverContents;
1415
use lsp_types::MarkupContent;
@@ -315,6 +316,39 @@ fn identifier_text_at(
315316
.map(|id| id.identifier.id.to_string())
316317
}
317318

319+
fn docstring_for_class_object_type(
320+
transaction: &Transaction<'_>,
321+
handle: &Handle,
322+
type_: &Type,
323+
) -> Option<Docstring> {
324+
let qname = match type_ {
325+
Type::ClassDef(cls) => cls.qname(),
326+
Type::Type(inner) => match inner.as_ref() {
327+
Type::ClassType(cls) => cls.qname(),
328+
_ => return None,
329+
},
330+
_ => return None,
331+
};
332+
let definition_handle = Handle::new(
333+
qname.module_name(),
334+
qname.module_path().dupe(),
335+
handle.sys_info().dupe(),
336+
);
337+
let definition = transaction
338+
.find_definition(
339+
&definition_handle,
340+
qname.range().start(),
341+
FindPreference {
342+
resolve_call_dunders: false,
343+
..Default::default()
344+
},
345+
)
346+
.ok()?
347+
.into_iter()
348+
.find(|item| item.definition_range == qname.range())?;
349+
Some(Docstring(definition.docstring_range?, definition.module))
350+
}
351+
318352
fn collect_typed_dict_fields_for_hover<'a>(
319353
solver: &AnswersSolver<TransactionHandle<'a>>,
320354
ty: &Type,
@@ -636,7 +670,7 @@ pub fn get_hover(
636670
let docstring = if let (Some(docstring), Some(module)) = (docstring_range, module) {
637671
Some(Docstring(docstring, module))
638672
} else {
639-
None
673+
docstring_for_class_object_type(transaction, handle, &type_)
640674
};
641675

642676
let mut parameter_doc = keyword_argument_documentation(transaction, handle, position)

pyrefly/lib/test/lsp/hover.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,34 @@ Widget docstring"#
10291029
);
10301030
}
10311031

1032+
#[test]
1033+
fn hover_on_property_returning_class_shows_class_docstring() {
1034+
let lib = r#"
1035+
from typing import Type
1036+
1037+
class current_timestamp:
1038+
"""The CURRENT_TIMESTAMP() SQL function."""
1039+
def __init__(self, *args: object, **kwargs: object) -> None: ...
1040+
1041+
class Func:
1042+
@property
1043+
def current_timestamp(self) -> Type[current_timestamp]: ...
1044+
"#;
1045+
let code = r#"
1046+
from lib import Func
1047+
1048+
f = Func()
1049+
f.current_timestamp
1050+
# ^
1051+
"#;
1052+
let report =
1053+
get_batched_lsp_operations_report(&[("main", code), ("lib", lib)], get_test_report);
1054+
assert!(
1055+
report.contains("The CURRENT_TIMESTAMP() SQL function."),
1056+
"Expected hover to show the class docstring, got: {report}"
1057+
);
1058+
}
1059+
10321060
#[test]
10331061
fn hover_on_first_component_of_multi_part_import() {
10341062
let mymod_init = r#"# mymod/__init__.py

0 commit comments

Comments
 (0)