diff --git a/fortls/langserver.py b/fortls/langserver.py index 6d2ce185..46c9d2ba 100644 --- a/fortls/langserver.py +++ b/fortls/langserver.py @@ -1082,7 +1082,12 @@ def create_hover(string: str, docs: str | None): # Construct hover information var_type: int = var_obj.get_type() hover_array = [] - if var_type in (SUBROUTINE_TYPE_ID, FUNCTION_TYPE_ID): + if var_type in ( + SUBROUTINE_TYPE_ID, + FUNCTION_TYPE_ID, + MODULE_TYPE_ID, + CLASS_TYPE_ID, + ): hover_array.append(var_obj.get_hover_md(long=True)) elif var_type == INTERFACE_TYPE_ID: for member in var_obj.mems: diff --git a/fortls/objects.py b/fortls/objects.py index bc76a758..472ff4b7 100644 --- a/fortls/objects.py +++ b/fortls/objects.py @@ -804,6 +804,11 @@ def get_type(self, no_link=False): def get_desc(self): return "MODULE" + def get_hover(self, long=False, drop_arg=-1) -> tuple[str, str]: + hover = f"{self.get_desc()} {self.name}" + doc_str = self.get_documentation() + return hover, doc_str + def check_valid_parent(self): if self.parent is not None: return False @@ -1287,7 +1292,7 @@ def __init__( self.inherit_var = None self.inherit_tmp = None self.inherit_version = -1 - if keywords.count(KEYWORD_ID_DICT["abstract"]) > 0: + if self.keywords.count(KEYWORD_ID_DICT["abstract"]) > 0: self.abstract = True else: self.abstract = False @@ -1436,6 +1441,17 @@ def get_actions(self, sline, eline): ] return actions + def get_hover(self, long=False, drop_arg=-1) -> tuple[str, str]: + keywords = [self.get_desc()] + if self.abstract: + keywords.append("ABSTRACT") + if self.inherit: + keywords.append(f"EXTENDS({self.inherit})") + decl = ", ".join(keywords) + hover = f"{decl} :: {self.name}" + doc_str = self.get_documentation() + return hover, doc_str + class Block(Scope): def __init__(self, file_ast: FortranAST, line_number: int, name: str): diff --git a/test/test_server_documentation.py b/test/test_server_documentation.py index 06f377ab..760aa0e8 100644 --- a/test/test_server_documentation.py +++ b/test/test_server_documentation.py @@ -300,3 +300,73 @@ def test_doc_multiline_type_bound_procedure_arg_list(): ), True, ) + + +def test_doxygen_doc_for_module_use(): + string = write_rpc_request(1, "initialize", {"rootPath": str(test_dir / "docs")}) + file_path = test_dir / "docs" / "test_module_and_type_doc.f90" + string += hover_request(file_path, 24, 14) + errcode, results = run_request(string) + assert errcode == 0 + + ref = ( + (0, "```fortran90"), + (1, "MODULE doxygen_doc_mod"), + (2, "```"), + (3, "-----"), + (4, "module doc for doxygen_doc_mod"), + (5, ""), + (6, "with info"), + ) + check_return(results[1], ref) + + +def test_ford_doc_for_module_use(): + string = write_rpc_request(1, "initialize", {"rootPath": str(test_dir / "docs")}) + file_path = test_dir / "docs" / "test_module_and_type_doc.f90" + string += hover_request(file_path, 25, 14) + errcode, results = run_request(string) + assert errcode == 0 + + ref = ( + (0, "```fortran90"), + (1, "MODULE ford_doc_mod"), + (2, "```"), + (3, "-----"), + (4, "Doc for ford_doc_mod"), + ) + check_return(results[1], ref) + + +def test_doxygen_doc_for_type(): + string = write_rpc_request(1, "initialize", {"rootPath": str(test_dir / "docs")}) + file_path = test_dir / "docs" / "test_module_and_type_doc.f90" + string += hover_request(file_path, 27, 11) + errcode, results = run_request(string) + assert errcode == 0 + + ref = ( + (0, "```fortran90"), + (1, "TYPE :: a_t"), + (2, "```"), + (3, "-----"), + (4, "Doc for a_t"), + ) + check_return(results[1], ref) + + +def test_ford_doc_for_type(): + string = write_rpc_request(1, "initialize", {"rootPath": str(test_dir / "docs")}) + file_path = test_dir / "docs" / "test_module_and_type_doc.f90" + string += hover_request(file_path, 28, 11) + errcode, results = run_request(string) + assert errcode == 0 + + ref = ( + (0, "```fortran90"), + (1, "TYPE :: b_t"), + (2, "```"), + (3, "-----"), + (4, "Doc for b_t"), + ) + check_return(results[1], ref) diff --git a/test/test_server_hover.py b/test/test_server_hover.py index 4269ebe7..a2fc1b39 100644 --- a/test/test_server_hover.py +++ b/test/test_server_hover.py @@ -538,3 +538,20 @@ def test_intrinsics(): intrinsics = json.load(f) ref_results = ["\n-----\n" + intrinsics["SIZE"]] validate_hover(results, ref_results) + + +def test_types(): + string = write_rpc_request(1, "initialize", {"rootPath": str(test_dir / "hover")}) + file_path = test_dir / "hover" / "types.f90" + string += hover_req(file_path, 3, 25) + string += hover_req(file_path, 6, 44) + string += hover_req(file_path, 9, 35) + + errcode, results = run_request(string, fortls_args=["-n", "1"]) + assert errcode == 0 + ref_results = [ + "```fortran90\nTYPE, ABSTRACT :: base_t\n```", + "```fortran90\nTYPE, ABSTRACT, EXTENDS(base_t) :: extends_t\n```", + "```fortran90\nTYPE, EXTENDS(extends_t) :: a_t\n```", + ] + validate_hover(results, ref_results) diff --git a/test/test_source/docs/test_module_and_type_doc.f90 b/test/test_source/docs/test_module_and_type_doc.f90 new file mode 100644 index 00000000..de563e45 --- /dev/null +++ b/test/test_source/docs/test_module_and_type_doc.f90 @@ -0,0 +1,30 @@ +!> module doc for doxygen_doc_mod +!! +!! with info +module doxygen_doc_mod + implicit none + + !> Doc for a_t + type :: a_t + end type +end module + + +module ford_doc_mod + !! Doc for ford_doc_mod + implicit none + + type :: b_t + !! Doc for b_t + end type + +end module + + +program main + use doxygen_doc_mod + use ford_doc_mod + + type(a_t) :: a + type(b_t) :: b +end program diff --git a/test/test_source/hover/types.f90 b/test/test_source/hover/types.f90 new file mode 100644 index 00000000..222127c1 --- /dev/null +++ b/test/test_source/hover/types.f90 @@ -0,0 +1,12 @@ +module types_mod + implicit none + + type, abstract :: base_t + end type + + type, abstract, extends(base_t) :: extends_t + end type + + type, extends(extends_t) :: a_t + end type +end module