Skip to content

Commit cf8852a

Browse files
fix
1 parent b1e5a2f commit cf8852a

File tree

2 files changed

+63
-1
lines changed

2 files changed

+63
-1
lines changed

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;
@@ -310,6 +311,39 @@ fn identifier_text_at(
310311
.map(|id| id.identifier.id.to_string())
311312
}
312313

314+
fn docstring_for_class_object_type(
315+
transaction: &Transaction<'_>,
316+
handle: &Handle,
317+
type_: &Type,
318+
) -> Option<Docstring> {
319+
let qname = match type_ {
320+
Type::ClassDef(cls) => cls.qname(),
321+
Type::Type(inner) => match inner.as_ref() {
322+
Type::ClassType(cls) => cls.qname(),
323+
_ => return None,
324+
},
325+
_ => return None,
326+
};
327+
let definition_handle = Handle::new(
328+
qname.module_name(),
329+
qname.module_path().dupe(),
330+
handle.sys_info().dupe(),
331+
);
332+
let definition = transaction
333+
.find_definition(
334+
&definition_handle,
335+
qname.range().start(),
336+
FindPreference {
337+
resolve_call_dunders: false,
338+
..Default::default()
339+
},
340+
)
341+
.ok()?
342+
.into_iter()
343+
.find(|item| item.definition_range == qname.range())?;
344+
Some(Docstring(definition.docstring_range?, definition.module))
345+
}
346+
313347
fn collect_typed_dict_fields_for_hover<'a>(
314348
solver: &AnswersSolver<TransactionHandle<'a>>,
315349
ty: &Type,
@@ -631,7 +665,7 @@ pub fn get_hover(
631665
let docstring = if let (Some(docstring), Some(module)) = (docstring_range, module) {
632666
Some(Docstring(docstring, module))
633667
} else {
634-
None
668+
docstring_for_class_object_type(transaction, handle, &type_)
635669
};
636670

637671
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
@@ -1008,6 +1008,34 @@ Widget docstring"#
10081008
);
10091009
}
10101010

1011+
#[test]
1012+
fn hover_on_property_returning_class_shows_class_docstring() {
1013+
let lib = r#"
1014+
from typing import Type
1015+
1016+
class current_timestamp:
1017+
"""The CURRENT_TIMESTAMP() SQL function."""
1018+
def __init__(self, *args: object, **kwargs: object) -> None: ...
1019+
1020+
class Func:
1021+
@property
1022+
def current_timestamp(self) -> Type[current_timestamp]: ...
1023+
"#;
1024+
let code = r#"
1025+
from lib import Func
1026+
1027+
f = Func()
1028+
f.current_timestamp
1029+
# ^
1030+
"#;
1031+
let report =
1032+
get_batched_lsp_operations_report(&[("main", code), ("lib", lib)], get_test_report);
1033+
assert!(
1034+
report.contains("The CURRENT_TIMESTAMP() SQL function."),
1035+
"Expected hover to show the class docstring, got: {report}"
1036+
);
1037+
}
1038+
10111039
#[test]
10121040
fn hover_on_first_component_of_multi_part_import() {
10131041
let mymod_init = r#"# mymod/__init__.py

0 commit comments

Comments
 (0)