Skip to content

Commit 2c5810b

Browse files
committed
fix: Go To Implementation works for submodules
It is now possible for interfaces with implementations in submodules i.e. a Function or a Subroutine Fixes #74
1 parent 691a3e8 commit 2c5810b

File tree

5 files changed

+48
-0
lines changed

5 files changed

+48
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
### Fixed
3131

32+
- Fixed bug where Go To Implementation would not work for submodules
33+
([#74](https://github.com/fortran-lang/fortls/issues/74))
3234
- Fixed bug where `associate` blocks for variables pointing to function results
3335
where not properly resolved
3436
([#269](https://github.com/fortran-lang/fortls/issues/269))

fortls/langserver.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,10 @@ def serve_implementation(self, request: dict):
11651165
impl_obj = var_obj.link_obj
11661166
if (impl_obj is not None) and (impl_obj.file_ast.file is not None):
11671167
return self._create_ref_link(impl_obj)
1168+
elif var_obj.parent.get_type() == INTERFACE_TYPE_ID:
1169+
# Find the first implementation of the interface
1170+
if var_obj.link_obj is not None:
1171+
return self._create_ref_link(var_obj.link_obj)
11681172
return None
11691173

11701174
def serve_rename(self, request: dict):

fortls/objects.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,8 @@ def resolve_link(self, obj_tree):
897897
if file_scope is child_old:
898898
child.file_ast.scope_list[j] = child
899899
if child.get_type() == prototype.get_type():
900+
# Link the interface with the implementation
901+
prototype.link_obj = child
900902
prototype.resolve_link(obj_tree)
901903
child.copy_interface(prototype)
902904
break
@@ -922,6 +924,7 @@ def __init__(
922924
self.in_children: list = []
923925
self.missing_args: list = []
924926
self.mod_scope: bool = mod_flag
927+
self.link_obj: Subroutine | Function | None = None
925928

926929
def is_mod_scope(self):
927930
return self.mod_scope

test/test_server_implementation.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,18 @@ def test_implementation_no_file():
7575
errcode, results = run_request(string, ["-n", "1"])
7676
assert errcode == 0
7777
assert results[1] is None
78+
79+
80+
def test_implementation_submodule():
81+
"""Go to implementation for submodule"""
82+
root = test_dir / "imp"
83+
string = write_rpc_request(1, "initialize", {"rootPath": str(root)})
84+
file_path = root / "submodule.f90"
85+
string += imp_request(file_path, 5, 30)
86+
string += imp_request(file_path, 8, 30)
87+
string += imp_request(file_path, 9, 30)
88+
errcode, results = run_request(string, ["-n", "1"])
89+
assert errcode == 0
90+
assert results[1] == create(str(root / "submodule.f90"), 19, 20, 34)
91+
assert results[2] == create(str(root / "submodule.f90"), 19, 20, 34)
92+
assert results[3] is None

test/test_source/imp/submodule.f90

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module parent_mod
2+
implicit none
3+
type :: typ
4+
real(kind=8) :: value
5+
contains
6+
procedure :: method1 => submod_method1
7+
end type typ
8+
interface
9+
module subroutine submod_method1(this)
10+
class(typ), intent(inout) :: this
11+
end subroutine submod_method1
12+
module subroutine submod_method2(this, value)
13+
class(typ), intent(inout) :: this
14+
real, intent(in) :: value
15+
end subroutine submod_method2
16+
end interface
17+
end module parent_mod
18+
submodule(parent_mod) submod
19+
contains
20+
module subroutine submod_method1(this)
21+
class(typ), intent(inout) :: this
22+
this%value = 0
23+
end subroutine submod_method1
24+
end submodule submod

0 commit comments

Comments
 (0)