6
6
import re
7
7
from dataclasses import dataclass
8
8
from typing import Pattern
9
+ from typing import Type as T
9
10
10
11
from fortls .constants import (
11
12
ASSOC_TYPE_ID ,
@@ -570,7 +571,7 @@ def __init__(self, file_ast, line_number: int, name: str, keywords: list = None)
570
571
self .sline : int = line_number
571
572
self .eline : int = line_number
572
573
self .name : str = name
573
- self .children : list = []
574
+ self .children : list [ T [ Scope ]] = []
574
575
self .members : list = []
575
576
self .use : list [Use | Import ] = []
576
577
self .keywords : list = keywords
@@ -621,7 +622,7 @@ def update_fqsn(self, enc_scope=None):
621
622
def add_member (self , member ):
622
623
self .members .append (member )
623
624
624
- def get_children (self , public_only = False ):
625
+ def get_children (self , public_only = False ) -> list [ T [ FortranObj ]] :
625
626
if not public_only :
626
627
return copy .copy (self .children )
627
628
pub_children = []
@@ -634,40 +635,40 @@ def get_children(self, public_only=False):
634
635
pub_children .append (child )
635
636
return pub_children
636
637
637
- def check_definitions (self , obj_tree ):
638
+ def check_definitions (self , obj_tree ) -> list [ Diagnostic ] :
638
639
"""Check for definition errors in scope"""
639
- FQSN_dict = {}
640
+ fqsn_dict : dict [str , int ] = {}
641
+ errors : list [Diagnostic ] = []
642
+ known_types : dict [str , FortranObj ] = {}
643
+
640
644
for child in self .children :
641
645
# Skip masking/double checks for interfaces
642
646
if child .get_type () == INTERFACE_TYPE_ID :
643
647
continue
644
648
# Check other variables in current scope
645
- if child .FQSN in FQSN_dict :
646
- if child .sline < FQSN_dict [child .FQSN ]:
647
- FQSN_dict [child .FQSN ] = child .sline - 1
649
+ if child .FQSN in fqsn_dict :
650
+ if child .sline < fqsn_dict [child .FQSN ]:
651
+ fqsn_dict [child .FQSN ] = child .sline - 1
648
652
else :
649
- FQSN_dict [child .FQSN ] = child .sline - 1
650
- #
653
+ fqsn_dict [child .FQSN ] = child .sline - 1
654
+
651
655
contains_line = - 1
652
- after_contains_list = (SUBROUTINE_TYPE_ID , FUNCTION_TYPE_ID )
653
656
if self .get_type () in (
654
657
MODULE_TYPE_ID ,
655
658
SUBMODULE_TYPE_ID ,
656
659
SUBROUTINE_TYPE_ID ,
657
660
FUNCTION_TYPE_ID ,
658
661
):
659
- if self .contains_start is None :
660
- contains_line = self .eline
661
- else :
662
- contains_line = self .contains_start
662
+ contains_line = (
663
+ self .contains_start if self .contains_start is not None else self .eline
664
+ )
663
665
# Detect interface definitions
664
666
is_interface = (
665
667
self .parent is not None
666
668
and self .parent .get_type () == INTERFACE_TYPE_ID
667
669
and not self .is_mod_scope ()
668
670
)
669
- errors = []
670
- known_types = {}
671
+
671
672
for child in self .children :
672
673
if child .name .startswith ("#" ):
673
674
continue
@@ -679,8 +680,9 @@ def check_definitions(self, obj_tree):
679
680
if def_error is not None :
680
681
errors .append (def_error )
681
682
# Detect contains errors
682
- if (contains_line >= child .sline ) and (
683
- child .get_type (no_link = True ) in after_contains_list
683
+ if contains_line >= child .sline and child .get_type (no_link = True ) in (
684
+ SUBROUTINE_TYPE_ID ,
685
+ FUNCTION_TYPE_ID ,
684
686
):
685
687
new_diag = Diagnostic (
686
688
line_number ,
@@ -689,12 +691,13 @@ def check_definitions(self, obj_tree):
689
691
)
690
692
errors .append (new_diag )
691
693
# Skip masking/double checks for interfaces and members
692
- if (self .get_type () == INTERFACE_TYPE_ID ) or (
693
- child .get_type () == INTERFACE_TYPE_ID
694
+ if (
695
+ self .get_type () == INTERFACE_TYPE_ID
696
+ or child .get_type () == INTERFACE_TYPE_ID
694
697
):
695
698
continue
696
699
# Check other variables in current scope
697
- if child .FQSN in FQSN_dict and line_number > FQSN_dict [child .FQSN ]:
700
+ if child .FQSN in fqsn_dict and line_number > fqsn_dict [child .FQSN ]:
698
701
new_diag = Diagnostic (
699
702
line_number ,
700
703
message = f'Variable "{ child .name } " declared twice in scope' ,
@@ -703,22 +706,26 @@ def check_definitions(self, obj_tree):
703
706
)
704
707
new_diag .add_related (
705
708
path = self .file_ast .path ,
706
- line = FQSN_dict [child .FQSN ],
709
+ line = fqsn_dict [child .FQSN ],
707
710
message = "First declaration" ,
708
711
)
709
712
errors .append (new_diag )
710
713
continue
711
714
# Check for masking from parent scope in subroutines, functions, and blocks
712
- if (self .parent is not None ) and (
713
- self .get_type () in (SUBROUTINE_TYPE_ID , FUNCTION_TYPE_ID , BLOCK_TYPE_ID )
715
+ if self .parent is not None and self .get_type () in (
716
+ SUBROUTINE_TYPE_ID ,
717
+ FUNCTION_TYPE_ID ,
718
+ BLOCK_TYPE_ID ,
714
719
):
715
720
parent_var = find_in_scope (self .parent , child .name , obj_tree )
716
721
if parent_var is not None :
717
722
# Ignore if function return variable
718
- if (self .get_type () == FUNCTION_TYPE_ID ) and (
719
- parent_var .FQSN == self .FQSN
723
+ if (
724
+ self .get_type () == FUNCTION_TYPE_ID
725
+ and parent_var .FQSN == self .FQSN
720
726
):
721
727
continue
728
+
722
729
new_diag = Diagnostic (
723
730
line_number ,
724
731
message = (
@@ -733,6 +740,7 @@ def check_definitions(self, obj_tree):
733
740
message = "First declaration" ,
734
741
)
735
742
errors .append (new_diag )
743
+
736
744
return errors
737
745
738
746
def check_use (self , obj_tree ):
@@ -854,7 +862,9 @@ def require_inherit(self):
854
862
return True
855
863
856
864
def resolve_link (self , obj_tree ):
857
- def get_ancestor_interfaces (ancestor_children : list [FortranObj ]):
865
+ def get_ancestor_interfaces (
866
+ ancestor_children : list [Scope ],
867
+ ) -> list [T [Interface ]]:
858
868
interfaces = []
859
869
for child in ancestor_children :
860
870
if child .get_type () != INTERFACE_TYPE_ID :
0 commit comments