Skip to content

Commit 039e092

Browse files
authored
Merge pull request #14 from gnikit/bug/externals
Bug/externals
2 parents 0b979cc + 74e4394 commit 039e092

File tree

9 files changed

+251
-33
lines changed

9 files changed

+251
-33
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- Adds intrinsic support for `OpenACC` version 3.1
1111
- Adds sphinx autogenerated documentation
1212
- Adds `incl_suffixes` as a configuration option
13+
- Adds `EXTERNAL` as an attribute upon hover
1314

1415
### Changes
1516

@@ -21,6 +22,10 @@
2122
- Fixes the hover of preprocessor functions. It now displays the function name
2223
witout the argument list and the function body. The argument list cannot be
2324
multiline but the function body can.
25+
- Fixes objects marked `EXTERNAL` across multiple lines
26+
([#169](https://github.com/hansec/fortran-language-server/issues/169))
27+
- Fixes include with external files
28+
([gnikit/fortls#13](https://github.com/gnikit/fortls/issues/13))
2429

2530
## 1.16.0
2631

fortls/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"elemental",
2727
"recursive",
2828
"abstract",
29+
"external",
2930
]
3031
KEYWORD_ID_DICT = {keyword: ind for (ind, keyword) in enumerate(KEYWORD_LIST)}
3132

fortls/helper_functions.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ def map_keywords(keywords):
322322
for keyword in keywords:
323323
keyword_prefix = keyword.split("(")[0].lower()
324324
keyword_ind = KEYWORD_ID_DICT.get(keyword_prefix)
325-
if keyword_ind is not None:
325+
if keyword_ind:
326326
mapped_keywords.append(keyword_ind)
327327
if keyword_prefix in ("intent", "dimension", "pass"):
328328
keyword_substring = get_paren_substring(keyword)
@@ -340,7 +340,7 @@ def get_keywords(keywords, keyword_info={}):
340340
addl_info = keyword_info.get(string_rep)
341341
string_rep = string_rep.upper()
342342
if addl_info is not None:
343-
string_rep += "({0})".format(addl_info)
343+
string_rep += f"({addl_info})"
344344
keyword_strings.append(string_rep)
345345
return keyword_strings
346346

fortls/objects.py

Lines changed: 50 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,8 @@ def check_scope(
188188
strip_str = strip_str.replace("'", "")
189189
for inc in scope.file_ast.include_statements:
190190
if strip_str == inc.path:
191+
if inc.file is None:
192+
return None
191193
return fortran_include(inc.file.ast, inc.line_number, inc.path)
192194

193195
# Setup USE search
@@ -473,7 +475,7 @@ def __init__(self, file_ast, line_number: int, name: str):
473475
self.base_setup(file_ast, line_number, name)
474476

475477
def base_setup(self, file_ast, sline: int, name: str, keywords: list = []):
476-
self.file_ast = file_ast
478+
self.file_ast: fortran_ast = file_ast
477479
self.sline: int = sline
478480
self.eline: int = sline
479481
self.name: str = name
@@ -585,7 +587,7 @@ def check_definitions(self, obj_tree):
585587
contains_line = self.eline
586588
else:
587589
contains_line = self.contains_start
588-
# Detect interface defintions
590+
# Detect interface definitions
589591
is_interface = False
590592
if (
591593
(self.parent is not None)
@@ -625,9 +627,7 @@ def check_definitions(self, obj_tree):
625627
if line_number > FQSN_dict[child.FQSN]:
626628
new_diag = fortran_diagnostic(
627629
line_number,
628-
message='Variable "{0}" declared twice in scope'.format(
629-
child.name
630-
),
630+
message=f'Variable "{child.name}" declared twice in scope',
631631
severity=1,
632632
find_word=child.name,
633633
)
@@ -651,8 +651,8 @@ def check_definitions(self, obj_tree):
651651
continue
652652
new_diag = fortran_diagnostic(
653653
line_number,
654-
message='Variable "{0}" masks variable in parent scope'.format(
655-
child.name
654+
message=(
655+
f'Variable "{child.name}" masks variable in parent scope'
656656
),
657657
severity=2,
658658
find_word=child.name,
@@ -755,7 +755,11 @@ def get_desc(self):
755755

756756
class fortran_submodule(fortran_module):
757757
def __init__(
758-
self, file_ast, line_number: int, name: str, ancestor_name: str = None
758+
self,
759+
file_ast: fortran_ast,
760+
line_number: int,
761+
name: str,
762+
ancestor_name: str = None,
759763
):
760764
self.base_setup(file_ast, line_number, name)
761765
self.ancestor_name = ancestor_name
@@ -832,7 +836,7 @@ def require_link(self):
832836
class fortran_subroutine(fortran_scope):
833837
def __init__(
834838
self,
835-
file_ast,
839+
file_ast: fortran_ast,
836840
line_number: int,
837841
name: str,
838842
args: str = "",
@@ -1046,7 +1050,7 @@ def get_diagnostics(self):
10461050
class fortran_function(fortran_subroutine):
10471051
def __init__(
10481052
self,
1049-
file_ast,
1053+
file_ast: fortran_ast,
10501054
line_number: int,
10511055
name: str,
10521056
args: str = "",
@@ -1168,7 +1172,9 @@ def get_interface(self, name_replace=None, change_arg=-1, change_strings=None):
11681172

11691173

11701174
class fortran_type(fortran_scope):
1171-
def __init__(self, file_ast, line_number: int, name: str, keywords: list):
1175+
def __init__(
1176+
self, file_ast: fortran_ast, line_number: int, name: str, keywords: list
1177+
):
11721178
self.base_setup(file_ast, line_number, name, keywords=keywords)
11731179
#
11741180
self.in_children: list = []
@@ -1333,7 +1339,7 @@ def get_actions(self, sline, eline):
13331339

13341340

13351341
class fortran_block(fortran_scope):
1336-
def __init__(self, file_ast, line_number: int, name: str):
1342+
def __init__(self, file_ast: fortran_ast, line_number: int, name: str):
13371343
self.base_setup(file_ast, line_number, name)
13381344

13391345
def get_type(self, no_link=False):
@@ -1350,7 +1356,7 @@ def req_named_end(self):
13501356

13511357

13521358
class fortran_do(fortran_block):
1353-
def __init__(self, file_ast, line_number: int, name: str):
1359+
def __init__(self, file_ast: fortran_ast, line_number: int, name: str):
13541360
self.base_setup(file_ast, line_number, name)
13551361

13561362
def get_type(self, no_link=False):
@@ -1361,7 +1367,7 @@ def get_desc(self):
13611367

13621368

13631369
class fortran_where(fortran_block):
1364-
def __init__(self, file_ast, line_number: int, name: str):
1370+
def __init__(self, file_ast: fortran_ast, line_number: int, name: str):
13651371
self.base_setup(file_ast, line_number, name)
13661372

13671373
def get_type(self, no_link=False):
@@ -1372,7 +1378,7 @@ def get_desc(self):
13721378

13731379

13741380
class fortran_if(fortran_block):
1375-
def __init__(self, file_ast, line_number: int, name: str):
1381+
def __init__(self, file_ast: fortran_ast, line_number: int, name: str):
13761382
self.base_setup(file_ast, line_number, name)
13771383

13781384
def get_type(self, no_link=False):
@@ -1383,7 +1389,7 @@ def get_desc(self):
13831389

13841390

13851391
class fortran_associate(fortran_block):
1386-
def __init__(self, file_ast, line_number: int, name: str):
1392+
def __init__(self, file_ast: fortran_ast, line_number: int, name: str):
13871393
self.base_setup(file_ast, line_number, name)
13881394
self.assoc_links = []
13891395

@@ -1418,7 +1424,7 @@ def require_link(self):
14181424

14191425

14201426
class fortran_enum(fortran_block):
1421-
def __init__(self, file_ast, line_number: int, name: str):
1427+
def __init__(self, file_ast: fortran_ast, line_number: int, name: str):
14221428
self.base_setup(file_ast, line_number, name)
14231429

14241430
def get_type(self, no_link=False):
@@ -1429,7 +1435,7 @@ def get_desc(self):
14291435

14301436

14311437
class fortran_select(fortran_block):
1432-
def __init__(self, file_ast, line_number: int, name: str, select_info):
1438+
def __init__(self, file_ast: fortran_ast, line_number: int, name: str, select_info):
14331439
self.base_setup(file_ast, line_number, name)
14341440
self.select_type = select_info.type
14351441
self.binding_name = None
@@ -1486,7 +1492,13 @@ def create_binding_variable(self, file_ast, line_number, var_desc, case_type):
14861492

14871493

14881494
class fortran_int(fortran_scope):
1489-
def __init__(self, file_ast, line_number: list, name: str, abstract: bool = False):
1495+
def __init__(
1496+
self,
1497+
file_ast: fortran_ast,
1498+
line_number: list,
1499+
name: str,
1500+
abstract: bool = False,
1501+
):
14901502
self.base_setup(file_ast, line_number, name)
14911503
self.mems = []
14921504
self.abstract = abstract
@@ -1523,7 +1535,7 @@ def require_link(self):
15231535
class fortran_var(fortran_obj):
15241536
def __init__(
15251537
self,
1526-
file_ast,
1538+
file_ast: fortran_ast,
15271539
line_number: int,
15281540
name: str,
15291541
var_desc: str,
@@ -1537,18 +1549,18 @@ def __init__(
15371549

15381550
def base_setup(
15391551
self,
1540-
file_ast,
1552+
file_ast: fortran_ast,
15411553
line_number: int,
15421554
name: str,
15431555
var_desc: str,
15441556
keywords: list,
15451557
keyword_info: dict,
15461558
link_obj: str,
15471559
):
1548-
self.file_ast = file_ast
1560+
self.file_ast: fortran_ast = file_ast
15491561
self.sline: int = line_number
15501562
self.eline: int = line_number
1551-
self.name: int = name
1563+
self.name: str = name
15521564
self.desc: str = var_desc
15531565
self.keywords: list = keywords
15541566
self.keyword_info: dict = keyword_info
@@ -1561,6 +1573,7 @@ def base_setup(
15611573
self.link_obj = None
15621574
self.type_obj = None
15631575
self.is_const: bool = False
1576+
self.is_external: bool = False
15641577
self.param_val: str = None
15651578
self.link_name: str = None
15661579
self.FQSN: str = self.name.lower()
@@ -1574,6 +1587,11 @@ def base_setup(
15741587
self.vis = -1
15751588
if self.keywords.count(KEYWORD_ID_DICT["parameter"]) > 0:
15761589
self.is_const = True
1590+
if (
1591+
self.keywords.count(KEYWORD_ID_DICT["external"]) > 0
1592+
or self.desc.lower() == "external"
1593+
):
1594+
self.is_external = True
15771595

15781596
def update_fqsn(self, enc_scope=None):
15791597
if enc_scope is not None:
@@ -1665,6 +1683,10 @@ def is_parameter(self):
16651683
def set_parameter_val(self, val: str):
16661684
self.param_val = val
16671685

1686+
def set_external_attr(self):
1687+
self.keywords.append(KEYWORD_ID_DICT["external"])
1688+
self.is_external = True
1689+
16681690
def check_definition(self, obj_tree, known_types={}, interface=False):
16691691
# Check for type definition in scope
16701692
type_match = DEF_KIND_REGEX.match(self.desc)
@@ -1726,7 +1748,7 @@ def check_definition(self, obj_tree, known_types={}, interface=False):
17261748
class fortran_meth(fortran_var):
17271749
def __init__(
17281750
self,
1729-
file_ast,
1751+
file_ast: fortran_ast,
17301752
line_number: int,
17311753
name: str,
17321754
var_desc: str,
@@ -1871,6 +1893,7 @@ def __init__(self, file_obj=None):
18711893
self.parse_errors: list = []
18721894
self.inherit_objs: list = []
18731895
self.linkable_objs: list = []
1896+
self.external_objs: list = []
18741897
self.none_scope = None
18751898
self.inc_scope = None
18761899
self.current_scope = None
@@ -1945,12 +1968,14 @@ def end_scope(self, line_number: int, check: bool = True):
19451968
self.END_SCOPE_REGEX = None
19461969
self.enc_scope_name = self.get_enc_scope_name()
19471970

1948-
def add_variable(self, new_var):
1971+
def add_variable(self, new_var: fortran_var):
19491972
if self.current_scope is None:
19501973
self.create_none_scope()
19511974
new_var.FQSN = self.none_scope.FQSN + "::" + new_var.name.lower()
19521975
self.current_scope.add_child(new_var)
19531976
self.variable_list.append(new_var)
1977+
if new_var.is_external:
1978+
self.external_objs.append(new_var)
19541979
if new_var.require_link():
19551980
self.linkable_objs.append(new_var)
19561981
self.last_obj = new_var

0 commit comments

Comments
 (0)