6
6
import os
7
7
from collections import defaultdict
8
8
from dataclasses import dataclass
9
- from typing import Any , Dict , Iterator , List , Optional , Set , Tuple , Union , cast
9
+ from typing import Any , Dict , Iterator , List , Optional , Set , Tuple , Union
10
10
11
11
from robot .parsing .lexer .tokens import Token
12
12
from robot .parsing .model .blocks import Keyword , TestCase
15
15
DocumentationOrMetadata ,
16
16
Fixture ,
17
17
KeywordCall ,
18
- KeywordName ,
19
18
LibraryImport ,
20
19
ResourceImport ,
21
20
Statement ,
@@ -148,10 +147,8 @@ def yield_argument_name_and_rest(self, node: ast.AST, token: Token) -> Iterator[
148
147
else :
149
148
yield token
150
149
151
- async def visit_Variable (self , node : ast .AST ) -> None : # noqa: N802
152
- variable = cast (Variable , node )
153
-
154
- name_token = variable .get_token (Token .VARIABLE )
150
+ async def visit_Variable (self , node : Variable ) -> None : # noqa: N802
151
+ name_token = node .get_token (Token .VARIABLE )
155
152
if name_token is None :
156
153
return
157
154
@@ -197,7 +194,9 @@ async def visit(self, node: ast.AST) -> None:
197
194
self .node_stack .append (node )
198
195
try :
199
196
severity = (
200
- DiagnosticSeverity .HINT if isinstance (node , DocumentationOrMetadata ) else DiagnosticSeverity .ERROR
197
+ DiagnosticSeverity .HINT
198
+ if isinstance (node , (DocumentationOrMetadata , TestCaseName ))
199
+ else DiagnosticSeverity .ERROR
201
200
)
202
201
203
202
if isinstance (node , KeywordCall ) and node .keyword :
@@ -762,9 +761,8 @@ def skip_args() -> List[Token]:
762
761
763
762
return argument_tokens
764
763
765
- async def visit_Fixture (self , node : ast .AST ) -> None : # noqa: N802
766
- value = cast (Fixture , node )
767
- keyword_token = cast (Token , value .get_token (Token .NAME ))
764
+ async def visit_Fixture (self , node : Fixture ) -> None : # noqa: N802
765
+ keyword_token = node .get_token (Token .NAME )
768
766
769
767
# TODO: calculate possible variables in NAME
770
768
@@ -774,58 +772,55 @@ async def visit_Fixture(self, node: ast.AST) -> None: # noqa: N802
774
772
and keyword_token .value .upper () not in ("" , "NONE" )
775
773
):
776
774
await self ._analyze_keyword_call (
777
- value .name ,
778
- value ,
775
+ node .name ,
776
+ node ,
779
777
keyword_token ,
780
- [cast ( Token , e ) for e in value .get_tokens (Token .ARGUMENT )],
778
+ [e for e in node .get_tokens (Token .ARGUMENT )],
781
779
allow_variables = True ,
782
780
ignore_errors_if_contains_variables = True ,
783
781
)
784
782
785
783
await self .generic_visit (node )
786
784
787
- async def visit_TestTemplate (self , node : ast .AST ) -> None : # noqa: N802
788
- value = cast (TestTemplate , node )
789
- keyword_token = cast (Token , value .get_token (Token .NAME ))
785
+ async def visit_TestTemplate (self , node : TestTemplate ) -> None : # noqa: N802
786
+ keyword_token = node .get_token (Token .NAME )
790
787
791
788
if keyword_token is not None and keyword_token .value .upper () not in ("" , "NONE" ):
792
789
await self ._analyze_keyword_call (
793
- value .value , value , keyword_token , [], analyse_run_keywords = False , allow_variables = True
790
+ node .value , node , keyword_token , [], analyse_run_keywords = False , allow_variables = True
794
791
)
795
792
796
- self .test_template = value
793
+ self .test_template = node
797
794
await self .generic_visit (node )
798
795
799
- async def visit_Template (self , node : ast .AST ) -> None : # noqa: N802
800
- value = cast (Template , node )
801
- keyword_token = cast (Token , value .get_token (Token .NAME ))
796
+ async def visit_Template (self , node : Template ) -> None : # noqa: N802
797
+ keyword_token = node .get_token (Token .NAME )
802
798
803
799
if keyword_token is not None and keyword_token .value .upper () not in ("" , "NONE" ):
804
800
await self ._analyze_keyword_call (
805
- value .value , value , keyword_token , [], analyse_run_keywords = False , allow_variables = True
801
+ node .value , node , keyword_token , [], analyse_run_keywords = False , allow_variables = True
806
802
)
807
- self .template = value
803
+ self .template = node
808
804
await self .generic_visit (node )
809
805
810
- async def visit_KeywordCall (self , node : ast .AST ) -> None : # noqa: N802
811
- value = cast (KeywordCall , node )
812
- keyword_token = cast (Token , value .get_token (Token .KEYWORD ))
806
+ async def visit_KeywordCall (self , node : KeywordCall ) -> None : # noqa: N802
807
+ keyword_token = node .get_token (Token .KEYWORD )
813
808
814
- if value .assign and not value . keyword :
809
+ if node .assign and keyword_token is None :
815
810
self .append_diagnostics (
816
- range = range_from_node_or_token (value , value .get_token (Token .ASSIGN )),
811
+ range = range_from_node_or_token (node , node .get_token (Token .ASSIGN )),
817
812
message = "Keyword name cannot be empty." ,
818
813
severity = DiagnosticSeverity .ERROR ,
819
814
code = Error .KEYWORD_NAME_EMPTY ,
820
815
)
821
816
else :
822
817
await self ._analyze_keyword_call (
823
- value .keyword , value , keyword_token , [cast ( Token , e ) for e in value .get_tokens (Token .ARGUMENT )]
818
+ node .keyword , node , keyword_token , [e for e in node .get_tokens (Token .ARGUMENT )]
824
819
)
825
820
826
821
if not self .current_testcase_or_keyword_name :
827
822
self .append_diagnostics (
828
- range = range_from_node_or_token (value , value .get_token (Token .ASSIGN )),
823
+ range = range_from_node_or_token (node , node .get_token (Token .ASSIGN )),
829
824
message = "Code is unreachable." ,
830
825
severity = DiagnosticSeverity .HINT ,
831
826
tags = [DiagnosticTag .UNNECESSARY ],
@@ -834,56 +829,52 @@ async def visit_KeywordCall(self, node: ast.AST) -> None: # noqa: N802
834
829
835
830
await self .generic_visit (node )
836
831
837
- async def visit_TestCase (self , node : ast .AST ) -> None : # noqa: N802
838
- testcase = cast (TestCase , node )
839
-
840
- if not testcase .name :
841
- name_token = cast (TestCaseName , testcase .header ).get_token (Token .TESTCASE_NAME )
832
+ async def visit_TestCase (self , node : TestCase ) -> None : # noqa: N802
833
+ if not node .name :
834
+ name_token = node .header .get_token (Token .TESTCASE_NAME )
842
835
self .append_diagnostics (
843
- range = range_from_node_or_token (testcase , name_token ),
836
+ range = range_from_node_or_token (node , name_token ),
844
837
message = "Test case name cannot be empty." ,
845
838
severity = DiagnosticSeverity .ERROR ,
846
839
code = Error .TESTCASE_NAME_EMPTY ,
847
840
)
848
841
849
- self .current_testcase_or_keyword_name = testcase .name
842
+ self .current_testcase_or_keyword_name = node .name
850
843
try :
851
844
await self .generic_visit (node )
852
845
finally :
853
846
self .current_testcase_or_keyword_name = None
854
847
self .template = None
855
848
856
- async def visit_Keyword (self , node : ast .AST ) -> None : # noqa: N802
857
- keyword = cast (Keyword , node )
858
-
859
- if keyword .name :
860
- name_token = cast (KeywordName , keyword .header ).get_token (Token .KEYWORD_NAME )
849
+ async def visit_Keyword (self , node : Keyword ) -> None : # noqa: N802
850
+ if node .name :
851
+ name_token = node .header .get_token (Token .KEYWORD_NAME )
861
852
kw_doc = self .get_keyword_definition_at_token (await self .namespace .get_library_doc (), name_token )
862
853
863
854
if kw_doc is not None and kw_doc not in self ._keyword_references :
864
855
self ._keyword_references [kw_doc ] = set ()
865
856
866
857
if (
867
858
get_robot_version () < (6 , 1 )
868
- and is_embedded_keyword (keyword .name )
869
- and any (isinstance (v , Arguments ) and len (v .values ) > 0 for v in keyword .body )
859
+ and is_embedded_keyword (node .name )
860
+ and any (isinstance (v , Arguments ) and len (v .values ) > 0 for v in node .body )
870
861
):
871
862
self .append_diagnostics (
872
- range = range_from_node_or_token (keyword , name_token ),
863
+ range = range_from_node_or_token (node , name_token ),
873
864
message = "Keyword cannot have both normal and embedded arguments." ,
874
865
severity = DiagnosticSeverity .ERROR ,
875
866
code = Error .KEYWORD_CONTAINS_NORMAL_AND_EMBBEDED_ARGUMENTS ,
876
867
)
877
868
else :
878
- name_token = cast ( KeywordName , keyword .header ) .get_token (Token .KEYWORD_NAME )
869
+ name_token = node .header .get_token (Token .KEYWORD_NAME )
879
870
self .append_diagnostics (
880
- range = range_from_node_or_token (keyword , name_token ),
871
+ range = range_from_node_or_token (node , name_token ),
881
872
message = "Keyword name cannot be empty." ,
882
873
severity = DiagnosticSeverity .ERROR ,
883
874
code = Error .KEYWORD_NAME_EMPTY ,
884
875
)
885
876
886
- self .current_testcase_or_keyword_name = keyword .name
877
+ self .current_testcase_or_keyword_name = node .name
887
878
try :
888
879
await self .generic_visit (node )
889
880
finally :
@@ -911,12 +902,10 @@ def _format_template(self, template: str, arguments: Tuple[str, ...]) -> Tuple[s
911
902
temp .append (var .after )
912
903
return "" .join (temp ), ()
913
904
914
- async def visit_TemplateArguments (self , node : ast .AST ) -> None : # noqa: N802
915
- arguments = cast (TemplateArguments , node )
916
-
905
+ async def visit_TemplateArguments (self , node : TemplateArguments ) -> None : # noqa: N802
917
906
template = self .template or self .test_template
918
907
if template is not None and template .value is not None and template .value .upper () not in ("" , "NONE" ):
919
- argument_tokens = arguments .get_tokens (Token .ARGUMENT )
908
+ argument_tokens = node .get_tokens (Token .ARGUMENT )
920
909
args = tuple (t .value for t in argument_tokens )
921
910
keyword = template .value
922
911
keyword , args = self ._format_template (keyword , args )
@@ -935,15 +924,15 @@ async def visit_TemplateArguments(self, node: ast.AST) -> None: # noqa: N802
935
924
raise
936
925
except BaseException as e :
937
926
self .append_diagnostics (
938
- range = range_from_node (arguments , skip_non_data = True ),
927
+ range = range_from_node (node , skip_non_data = True ),
939
928
message = str (e ),
940
929
severity = DiagnosticSeverity .ERROR ,
941
930
code = type (e ).__qualname__ ,
942
931
)
943
932
944
933
for d in self .finder .diagnostics :
945
934
self .append_diagnostics (
946
- range = range_from_node (arguments , skip_non_data = True ),
935
+ range = range_from_node (node , skip_non_data = True ),
947
936
message = d .message ,
948
937
severity = d .severity ,
949
938
code = d .code ,
@@ -1011,13 +1000,11 @@ def _check_import_name(self, value: Optional[str], node: ast.AST, type: str) ->
1011
1000
code = Error .IMPORT_REQUIRES_VALUE ,
1012
1001
)
1013
1002
1014
- async def visit_VariablesImport (self , node : ast . AST ) -> None : # noqa: N802
1003
+ async def visit_VariablesImport (self , node : VariablesImport ) -> None : # noqa: N802
1015
1004
if get_robot_version () >= (6 , 1 ):
1016
- import_node = cast (VariablesImport , node )
1017
- self ._check_import_name (import_node .name , node , "Variables" )
1005
+ self ._check_import_name (node .name , node , "Variables" )
1018
1006
1019
- n = cast (VariablesImport , node )
1020
- name_token = n .get_token (Token .NAME )
1007
+ name_token = node .get_token (Token .NAME )
1021
1008
if name_token is None :
1022
1009
return
1023
1010
@@ -1028,13 +1015,11 @@ async def visit_VariablesImport(self, node: ast.AST) -> None: # noqa: N802
1028
1015
if v not in self ._namespace_references :
1029
1016
self ._namespace_references [v ] = set ()
1030
1017
1031
- async def visit_ResourceImport (self , node : ast . AST ) -> None : # noqa: N802
1018
+ async def visit_ResourceImport (self , node : ResourceImport ) -> None : # noqa: N802
1032
1019
if get_robot_version () >= (6 , 1 ):
1033
- import_node = cast (ResourceImport , node )
1034
- self ._check_import_name (import_node .name , node , "Resource" )
1020
+ self ._check_import_name (node .name , node , "Resource" )
1035
1021
1036
- n = cast (ResourceImport , node )
1037
- name_token = n .get_token (Token .NAME )
1022
+ name_token = node .get_token (Token .NAME )
1038
1023
if name_token is None :
1039
1024
return
1040
1025
@@ -1045,13 +1030,11 @@ async def visit_ResourceImport(self, node: ast.AST) -> None: # noqa: N802
1045
1030
if v not in self ._namespace_references :
1046
1031
self ._namespace_references [v ] = set ()
1047
1032
1048
- async def visit_LibraryImport (self , node : ast . AST ) -> None : # noqa: N802
1033
+ async def visit_LibraryImport (self , node : LibraryImport ) -> None : # noqa: N802
1049
1034
if get_robot_version () >= (6 , 1 ):
1050
- import_node = cast (LibraryImport , node )
1051
- self ._check_import_name (import_node .name , node , "Library" )
1035
+ self ._check_import_name (node .name , node , "Library" )
1052
1036
1053
- n = cast (LibraryImport , node )
1054
- name_token = n .get_token (Token .NAME )
1037
+ name_token = node .get_token (Token .NAME )
1055
1038
if name_token is None :
1056
1039
return
1057
1040
0 commit comments