Skip to content

Commit 81cc997

Browse files
authored
Merge pull request #121 from gnikit/bug/scope-overreach
Bug/scope-overreach
2 parents 07333e4 + 3aa9c6e commit 81cc997

6 files changed

+81
-3
lines changed

.coveragerc

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
[run]
2-
dynamic_context = test_function
32
omit =
43
fortls/__init__.py
54
fortls/version.py
@@ -10,3 +9,6 @@ exclude_lines =
109
log.debug
1110
except:
1211
if not PY3K:
12+
13+
[html]
14+
show_contexts = True

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
- Redesigned the `fortls` website to be more aesthetically pleasing and user-friendly
1010
([#112](https://github.com/gnikit/fortls/issues/112))
1111

12+
### Fixed
13+
14+
- Fixed bug where submodule procedure scopes would terminate early if keyword modifiers were used
15+
([#119](https://github.com/gnikit/fortls/issues/119))
16+
1217
## 2.5.0
1318

1419
### Added

fortls/parse_fortran.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,12 @@ def read_generic_def(line: str):
532532

533533

534534
def read_mod_def(line: str):
535-
"""Attempt to read MODULE and MODULE PROCEDURE definition lines"""
535+
"""Attempt to read MODULE and MODULE PROCEDURE, MODULE FUNCTION definition lines"""
536+
# Get all the keyword modifier mathces
537+
keywords = re.findall(FRegex.SUB_MOD, line)
538+
# remove modifiers from line
539+
line = re.sub(FRegex.SUB_MOD, "", line)
540+
536541
mod_match = FRegex.MOD.match(line)
537542
if mod_match is None:
538543
return None
@@ -547,15 +552,19 @@ def read_mod_def(line: str):
547552
return "int_pro", pro_names
548553
# Check for submodule definition
549554
trailing_line = line[mod_match.start(1) :]
555+
# module procedure
550556
sub_res = read_sub_def(trailing_line, mod_flag=True)
551557
if sub_res is not None:
552558
return sub_res
559+
# module function
553560
fun_res = read_var_def(trailing_line, fun_only=True)
554561
if fun_res is not None:
555562
fun_res[1].mod_flag = True
556-
return fun_res[0], fun_res[1]
563+
fun_res[1].keywords = keywords
564+
return fun_res
557565
fun_res = read_fun_def(trailing_line, mod_flag=True)
558566
if fun_res is not None:
567+
fun_res[1].keywords = keywords
559568
return fun_res
560569
return "mod", name
561570

test/test_server_diagnostics.py

+13
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,16 @@ def test_function():
391391
"severity": 1,
392392
}
393393
]
394+
395+
396+
def test_submodule_scopes():
397+
"""Test that submodule procedures and functions with modifier keywords are correctly
398+
parsed and their scopes correctly closed."""
399+
string = write_rpc_request(1, "initialize", {"rootPath": str(test_dir / "diag")})
400+
file_path = str(test_dir / "diag" / "test_scope_overreach.f90")
401+
string += write_rpc_notification(
402+
"textDocument/didOpen", {"textDocument": {"uri": file_path}}
403+
)
404+
errcode, results = run_request(string, ["-n", "1"])
405+
assert errcode == 0
406+
assert results[1]["diagnostics"] == []

test/test_server_hover.py

+21
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,24 @@ def test_hover_block():
327327
assert errcode == 0
328328
ref_results = ["REAL, DIMENSION(5)", "REAL"]
329329
validate_hover(results, ref_results)
330+
331+
332+
def test_hover_submodule_procedure():
333+
"""Test that submodule procedures and functions with modifier keywords
334+
are correctly displayed when hovering.
335+
"""
336+
string = write_rpc_request(1, "initialize", {"rootPath": str(test_dir / "diag")})
337+
file_path = test_dir / "diag" / "test_scope_overreach.f90"
338+
string += hover_req(file_path, 18, 37)
339+
string += hover_req(file_path, 23, 37)
340+
errcode, results = run_request(string, fortls_args=["-n", "1"])
341+
assert errcode == 0
342+
ref_results = [
343+
"""PURE RECURSIVE FUNCTION foo_sp(x) RESULT(fi)
344+
REAL(sp), INTENT(IN) :: x
345+
REAL(sp) :: fi""",
346+
"""PURE RECURSIVE FUNCTION foo_dp(x) RESULT(fi)
347+
REAL(dp), INTENT(IN) :: x
348+
REAL(dp) :: fi""",
349+
]
350+
validate_hover(results, ref_results)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module m
2+
interface
3+
module subroutine sub(arg)
4+
integer :: arg
5+
end subroutine
6+
end interface
7+
end module m
8+
9+
submodule (m) n
10+
11+
use, intrinsic :: iso_fortran_env, only: int8, int16, int32, int64
12+
implicit none
13+
14+
integer, parameter :: sp = selected_real_kind(6)
15+
integer, parameter :: dp = selected_real_kind(15)
16+
17+
contains
18+
19+
pure recursive module function foo_sp(x) result(fi)
20+
real(sp), intent(in) :: x
21+
real(sp) :: fi
22+
end function foo_sp
23+
24+
pure recursive module function foo_dp(x) result(fi)
25+
real(dp), intent(in) :: x
26+
real(dp) :: fi
27+
end function foo_dp
28+
end submodule n

0 commit comments

Comments
 (0)