Skip to content

Commit

Permalink
fix: Go To Implementation works for submodules
Browse files Browse the repository at this point in the history
It is now possible for interfaces with implementations in submodules
i.e. a Function or a Subroutine

Fixes #74
  • Loading branch information
gnikit committed Jul 23, 2023
1 parent 691a3e8 commit 2c5810b
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

### Fixed

- Fixed bug where Go To Implementation would not work for submodules
([#74](https://github.com/fortran-lang/fortls/issues/74))
- Fixed bug where `associate` blocks for variables pointing to function results
where not properly resolved
([#269](https://github.com/fortran-lang/fortls/issues/269))
Expand Down
4 changes: 4 additions & 0 deletions fortls/langserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,10 @@ def serve_implementation(self, request: dict):
impl_obj = var_obj.link_obj
if (impl_obj is not None) and (impl_obj.file_ast.file is not None):
return self._create_ref_link(impl_obj)
elif var_obj.parent.get_type() == INTERFACE_TYPE_ID:
# Find the first implementation of the interface
if var_obj.link_obj is not None:
return self._create_ref_link(var_obj.link_obj)
return None

def serve_rename(self, request: dict):
Expand Down
3 changes: 3 additions & 0 deletions fortls/objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,8 @@ def resolve_link(self, obj_tree):
if file_scope is child_old:
child.file_ast.scope_list[j] = child
if child.get_type() == prototype.get_type():
# Link the interface with the implementation
prototype.link_obj = child
prototype.resolve_link(obj_tree)
child.copy_interface(prototype)
break
Expand All @@ -922,6 +924,7 @@ def __init__(
self.in_children: list = []
self.missing_args: list = []
self.mod_scope: bool = mod_flag
self.link_obj: Subroutine | Function | None = None

def is_mod_scope(self):
return self.mod_scope
Expand Down
15 changes: 15 additions & 0 deletions test/test_server_implementation.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,18 @@ def test_implementation_no_file():
errcode, results = run_request(string, ["-n", "1"])
assert errcode == 0
assert results[1] is None


def test_implementation_submodule():
"""Go to implementation for submodule"""
root = test_dir / "imp"
string = write_rpc_request(1, "initialize", {"rootPath": str(root)})
file_path = root / "submodule.f90"
string += imp_request(file_path, 5, 30)
string += imp_request(file_path, 8, 30)
string += imp_request(file_path, 9, 30)
errcode, results = run_request(string, ["-n", "1"])
assert errcode == 0
assert results[1] == create(str(root / "submodule.f90"), 19, 20, 34)
assert results[2] == create(str(root / "submodule.f90"), 19, 20, 34)
assert results[3] is None
24 changes: 24 additions & 0 deletions test/test_source/imp/submodule.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module parent_mod
implicit none
type :: typ
real(kind=8) :: value
contains
procedure :: method1 => submod_method1
end type typ
interface
module subroutine submod_method1(this)
class(typ), intent(inout) :: this
end subroutine submod_method1
module subroutine submod_method2(this, value)
class(typ), intent(inout) :: this
real, intent(in) :: value
end subroutine submod_method2
end interface
end module parent_mod
submodule(parent_mod) submod
contains
module subroutine submod_method1(this)
class(typ), intent(inout) :: this
this%value = 0
end subroutine submod_method1
end submodule submod

0 comments on commit 2c5810b

Please sign in to comment.