9999 KeywordError ,
100100 KeywordMatcher ,
101101 LibraryDoc ,
102+ resolve_robot_variables ,
102103)
103104
104105EXTRACT_COMMENT_PATTERN = re .compile (r".*(?:^ *|\t+| {2,})#(?P<comment>.*)$" )
@@ -184,22 +185,19 @@ def visit_Variable(self, node: Statement) -> None: # noqa: N802
184185class BlockVariableVisitor (Visitor ):
185186 def __init__ (
186187 self ,
187- library_doc : LibraryDoc ,
188- global_variables : List [VariableDefinition ],
189- source : str ,
188+ namespace : "Namespace" ,
189+ nodes : Optional [List [ast .AST ]] = None ,
190190 position : Optional [Position ] = None ,
191191 in_args : bool = True ,
192192 ) -> None :
193193 super ().__init__ ()
194- self .library_doc = library_doc
195- self .global_variables = global_variables
196- self .source = source
194+ self .namespace = namespace
195+ self .nodes = nodes
197196 self .position = position
198197 self .in_args = in_args
199198
200199 self ._results : Dict [str , VariableDefinition ] = {}
201200 self .current_kw_doc : Optional [KeywordDoc ] = None
202- self ._var_statements_vars : List [VariableDefinition ] = []
203201
204202 def get (self , model : ast .AST ) -> List [VariableDefinition ]:
205203 self ._results = {}
@@ -224,7 +222,7 @@ def visit_KeywordName(self, node: Statement) -> None: # noqa: N802
224222 name_token = node .get_token (Token .KEYWORD_NAME )
225223
226224 if name_token is not None and name_token .value :
227- keyword = ModelHelper .get_keyword_definition_at_token (self .library_doc , name_token )
225+ keyword = ModelHelper .get_keyword_definition_at_token (self .namespace . get_library_doc () , name_token )
228226 self .current_kw_doc = keyword
229227
230228 for variable_token in filter (
@@ -246,7 +244,7 @@ def visit_KeywordName(self, node: Statement) -> None: # noqa: N802
246244 col_offset = variable_token .col_offset ,
247245 end_line_no = variable_token .lineno ,
248246 end_col_offset = variable_token .end_col_offset ,
249- source = self .source ,
247+ source = self .namespace . source ,
250248 keyword_doc = self .current_kw_doc ,
251249 )
252250
@@ -290,7 +288,7 @@ def visit_Arguments(self, node: Statement) -> None: # noqa: N802
290288 col_offset = argument .col_offset ,
291289 end_line_no = argument .lineno ,
292290 end_col_offset = argument .end_col_offset ,
293- source = self .source ,
291+ source = self .namespace . source ,
294292 keyword_doc = self .current_kw_doc ,
295293 )
296294 self ._results [argument .value ] = arg_def
@@ -312,12 +310,48 @@ def visit_ExceptHeader(self, node: Statement) -> None: # noqa: N802
312310 col_offset = variable .col_offset ,
313311 end_line_no = variable .lineno ,
314312 end_col_offset = variable .end_col_offset ,
315- source = self .source ,
313+ source = self .namespace . source ,
316314 )
317315
318316 except VariableError :
319317 pass
320318
319+ def _get_var_name (self , original : str , position : Position , require_assign : bool = True ) -> Optional [str ]:
320+ robot_variables = resolve_robot_variables (
321+ str (self .namespace .imports_manager .root_folder ),
322+ str (Path (self .namespace .source ).parent ) if self .namespace .source else "." ,
323+ self .namespace .imports_manager .get_resolvable_command_line_variables (),
324+ variables = self .namespace .get_resolvable_variables (),
325+ )
326+
327+ try :
328+ replaced = robot_variables .replace_string (original )
329+ except VariableError :
330+ replaced = original
331+ try :
332+ name = self ._resolve_var_name (replaced , robot_variables )
333+ except ValueError :
334+ name = original
335+ match = search_variable (name , identifiers = "$@&" )
336+ match .resolve_base (robot_variables )
337+ valid = match .is_assign () if require_assign else match .is_variable ()
338+ if not valid :
339+ return None
340+ return str (match )
341+
342+ def _resolve_var_name (self , name : str , variables : Any ) -> str :
343+ if name .startswith ("\\ " ):
344+ name = name [1 :]
345+ if len (name ) < 2 or name [0 ] not in "$@&" :
346+ raise ValueError
347+ if name [1 ] != "{" :
348+ name = f"{ name [0 ]} {{{ name [1 :]} }}"
349+ match = search_variable (name , identifiers = "$@&" , ignore_errors = True )
350+ match .resolve_base (variables )
351+ if not match .is_assign ():
352+ raise ValueError
353+ return str (match )
354+
321355 def visit_KeywordCall (self , node : Statement ) -> None : # noqa: N802
322356 # TODO analyze "Set Local/Global/Suite Variable"
323357
@@ -341,12 +375,65 @@ def visit_KeywordCall(self, node: Statement) -> None: # noqa: N802
341375 col_offset = variable_token .col_offset ,
342376 end_line_no = variable_token .lineno ,
343377 end_col_offset = variable_token .end_col_offset ,
344- source = self .source ,
378+ source = self .namespace . source ,
345379 )
346380
347381 except VariableError :
348382 pass
349383
384+ keyword_token = node .get_token (Token .KEYWORD )
385+ if keyword_token is None or not keyword_token .value :
386+ return
387+
388+ keyword = self .namespace .find_keyword (keyword_token .value , raise_keyword_error = False )
389+ if keyword is None :
390+ return
391+
392+ if keyword .libtype == "LIBRARY" and keyword .libname == "BuiltIn" :
393+ var_type = None
394+ if keyword .name == "Set Suite Variable" :
395+ var_type = VariableDefinition
396+ elif keyword .name == "Set Global Variable" :
397+ var_type = GlobalVariableDefinition
398+ elif keyword .name == "Set Test Variable" or keyword .name == "Set Task Variable" :
399+ var_type = TestVariableDefinition
400+ elif keyword .name == "Set Local Variable" :
401+ var_type = LocalVariableDefinition
402+ else :
403+ return
404+ try :
405+ variable = node .get_token (Token .ARGUMENT )
406+ if variable is None :
407+ return
408+
409+ position = range_from_node (node ).start
410+ position .character = 0
411+ var_name = self ._get_var_name (variable .value , position )
412+
413+ if var_name is None or not is_variable (var_name ):
414+ return
415+
416+ var = var_type (
417+ name = var_name ,
418+ name_token = strip_variable_token (variable ),
419+ line_no = variable .lineno ,
420+ col_offset = variable .col_offset ,
421+ end_line_no = variable .lineno ,
422+ end_col_offset = variable .end_col_offset ,
423+ source = self .namespace .source ,
424+ )
425+
426+ if var_name not in self ._results or type (self ._results [var_name ]) != type (var ):
427+ if isinstance (var , LocalVariableDefinition ) or not any (
428+ l for l in self .namespace .get_global_variables () if l .matcher == var .matcher
429+ ):
430+ self ._results [var_name ] = var
431+ else :
432+ self ._results .pop (var_name , None )
433+
434+ except VariableError :
435+ pass
436+
350437 def visit_InlineIfHeader (self , node : Statement ) -> None : # noqa: N802
351438 for assign_token in node .get_tokens (Token .ASSIGN ):
352439 variable_token = self .get_variable_token (assign_token )
@@ -368,7 +455,7 @@ def visit_InlineIfHeader(self, node: Statement) -> None: # noqa: N802
368455 col_offset = variable_token .col_offset ,
369456 end_line_no = variable_token .lineno ,
370457 end_col_offset = variable_token .end_col_offset ,
371- source = self .source ,
458+ source = self .namespace . source ,
372459 )
373460
374461 except VariableError :
@@ -386,7 +473,7 @@ def visit_ForHeader(self, node: Statement) -> None: # noqa: N802
386473 col_offset = variable_token .col_offset ,
387474 end_line_no = variable_token .lineno ,
388475 end_col_offset = variable_token .end_col_offset ,
389- source = self .source ,
476+ source = self .namespace . source ,
390477 )
391478
392479 def visit_Var (self , node : Statement ) -> None : # noqa: N802
@@ -421,14 +508,12 @@ def visit_Var(self, node: Statement) -> None: # noqa: N802
421508 col_offset = variable .col_offset ,
422509 end_line_no = variable .lineno ,
423510 end_col_offset = variable .end_col_offset ,
424- source = self .source ,
511+ source = self .namespace . source ,
425512 )
426513
427- self ._var_statements_vars .append (var )
428-
429514 if var_name not in self ._results or type (self ._results [var_name ]) != type (var ):
430515 if isinstance (var , LocalVariableDefinition ) or not any (
431- l for l in self .global_variables if l .matcher == var .matcher
516+ l for l in self .namespace . get_global_variables () if l .matcher == var .matcher
432517 ):
433518 self ._results [var_name ] = var
434519 else :
@@ -924,9 +1009,8 @@ def yield_variables(
9241009 (
9251010 (
9261011 BlockVariableVisitor (
927- self .get_library_doc (),
928- self .get_global_variables (),
929- self .source ,
1012+ self ,
1013+ nodes ,
9301014 position ,
9311015 isinstance (test_or_keyword_nodes [- 1 ], Arguments ) if nodes else False ,
9321016 ).get (test_or_keyword )
0 commit comments