@@ -207,15 +207,15 @@ async def visit_Variable(self, node: ast.AST) -> None: # noqa: N802
207207
208208 n = cast (Variable , node )
209209 name = n .get_token (Token .VARIABLE )
210- if n . name :
210+ if name is not None :
211211 self ._results .append (
212212 VariableDefinition (
213213 name = n .name ,
214- name_token = name if name is not None else None ,
215- line_no = node .lineno ,
216- col_offset = node .col_offset ,
217- end_line_no = node . end_lineno if node . end_lineno is not None else - 1 ,
218- end_col_offset = node .end_col_offset if node . end_col_offset is not None else - 1 ,
214+ name_token = name ,
215+ line_no = name .lineno ,
216+ col_offset = name .col_offset ,
217+ end_line_no = name . lineno ,
218+ end_col_offset = name .end_col_offset ,
219219 source = self .source ,
220220 )
221221 )
@@ -226,11 +226,11 @@ async def get(self, source: str, model: ast.AST, position: Optional[Position] =
226226 self .source = source
227227 self .position = position
228228
229- self ._results : List [ VariableDefinition ] = []
229+ self ._results : Dict [ str , VariableDefinition ] = {}
230230
231231 await self .visit (model )
232232
233- return self ._results
233+ return list ( self ._results . values ())
234234
235235 async def visit (self , node : ast .AST ) -> None :
236236 if self .position is None or self .position >= range_from_node (node ).start :
@@ -245,149 +245,110 @@ async def visit_KeywordName(self, node: ast.AST) -> None: # noqa: N802
245245 name_token = cast (Token , n .get_token (RobotToken .KEYWORD_NAME ))
246246
247247 if name_token is not None and name_token .value :
248- for a in filter (
248+ for variable_token in filter (
249249 lambda e : e .type == RobotToken .VARIABLE ,
250250 tokenize_variables (name_token , identifiers = "$" , ignore_errors = True ),
251251 ):
252- if a .value :
252+ if variable_token .value :
253253 searcher = VariableSearcher ("$" , ignore_errors = True )
254- match = searcher .search (a .value )
254+ match = searcher .search (variable_token .value )
255255 if match .base is None :
256256 continue
257257 name = f"{ match .identifier } {{{ match .base .split (':' , 1 )[0 ]} }}"
258258
259- self ._results .append (
260- ArgumentDefinition (
261- name = name ,
262- name_token = a ,
263- line_no = a .lineno ,
264- col_offset = node .col_offset ,
265- end_line_no = node .end_lineno
266- if node .end_lineno is not None
267- else a .lineno
268- if a .lineno is not None
269- else - 1 ,
270- end_col_offset = node .end_col_offset
271- if node .end_col_offset is not None
272- else a .end_col_offset
273- if name_token .end_col_offset is not None
274- else - 1 ,
275- source = self .source ,
276- )
259+ self ._results [name ] = ArgumentDefinition (
260+ name = name ,
261+ name_token = variable_token ,
262+ line_no = variable_token .lineno ,
263+ col_offset = variable_token .col_offset ,
264+ end_line_no = variable_token .lineno ,
265+ end_col_offset = variable_token .end_col_offset ,
266+ source = self .source ,
277267 )
278268
269+ def get_variable_token (self , token : Token ) -> Optional [Token ]:
270+ from robot .parsing .lexer .tokens import Token as RobotToken
271+
272+ return next (
273+ (
274+ v
275+ for v in itertools .dropwhile (
276+ lambda t : t .type in RobotToken .NON_DATA_TOKENS ,
277+ tokenize_variables (token , ignore_errors = True ),
278+ )
279+ if v .type == RobotToken .VARIABLE
280+ ),
281+ None ,
282+ )
283+
279284 async def visit_Arguments (self , node : ast .AST ) -> None : # noqa: N802
280285 from robot .errors import VariableError
281286 from robot .parsing .lexer .tokens import Token as RobotToken
282287 from robot .parsing .model .statements import Arguments
283288
284289 n = cast (Arguments , node )
285290 arguments = n .get_tokens (RobotToken .ARGUMENT )
286- for argument1 in (cast (RobotToken , e ) for e in arguments ):
291+ for argument_token in (cast (RobotToken , e ) for e in arguments ):
287292 try :
288- argument = None
289- try :
290- argument = next (
291- (
292- v
293- for v in itertools .dropwhile (
294- lambda t : t .type in RobotToken .NON_DATA_TOKENS , argument1 .tokenize_variables ()
295- )
296- if v .type == RobotToken .VARIABLE
297- ),
298- None ,
299- )
300- except VariableError :
301- pass
293+ argument = self .get_variable_token (argument_token )
294+
302295 if argument is not None :
303- self ._results .append (
304- ArgumentDefinition (
305- name = argument .value ,
306- name_token = argument ,
307- line_no = node .lineno ,
308- col_offset = node .col_offset ,
309- end_line_no = node .end_lineno
310- if node .end_lineno is not None
311- else argument .lineno
312- if argument .lineno is not None
313- else - 1 ,
314- end_col_offset = node .end_col_offset
315- if node .end_col_offset is not None
316- else argument .end_col_offset
317- if argument .end_col_offset is not None
318- else - 1 ,
319- source = self .source ,
320- )
296+ self ._results [argument .value ] = ArgumentDefinition (
297+ name = argument .value ,
298+ name_token = argument ,
299+ line_no = argument .lineno ,
300+ col_offset = argument .col_offset ,
301+ end_line_no = argument .lineno ,
302+ end_col_offset = argument .end_col_offset ,
303+ source = self .source ,
321304 )
305+
322306 except VariableError :
323307 pass
324308
325309 async def visit_KeywordCall (self , node : ast .AST ) -> None : # noqa: N802
326310 from robot .errors import VariableError
327311 from robot .parsing .lexer .tokens import Token as RobotToken
328312 from robot .parsing .model .statements import KeywordCall
329- from robot .variables .search import contains_variable
330313
331314 # TODO analyse "Set Local/Global/Suite Variable"
332315
333- try :
334- n = cast (KeywordCall , node )
335- assign_token = n .get_token (RobotToken .ASSIGN )
336- if assign_token is not None and assign_token .value and contains_variable (assign_token .value ):
337- self ._results .append (
338- VariableDefinition (
339- name = assign_token .value ,
340- name_token = assign_token ,
341- line_no = node .lineno ,
342- col_offset = node .col_offset ,
343- end_line_no = node .end_lineno
344- if node .end_lineno is not None
345- else assign_token .lineno
346- if assign_token .lineno is not None
347- else - 1 ,
348- end_col_offset = node .end_col_offset
349- if node .end_col_offset is not None
350- else assign_token .end_col_offset
351- if assign_token .end_col_offset is not None
352- else - 1 ,
316+ n = cast (KeywordCall , node )
317+ for assign_token in n .get_tokens (RobotToken .ASSIGN ):
318+ variable_token = self .get_variable_token (assign_token )
319+ try :
320+ if variable_token is not None and variable_token .value not in self ._results :
321+ self ._results [variable_token .value ] = VariableDefinition (
322+ name = variable_token .value ,
323+ name_token = variable_token ,
324+ line_no = variable_token .lineno ,
325+ col_offset = variable_token .col_offset ,
326+ end_line_no = variable_token .lineno ,
327+ end_col_offset = variable_token .end_col_offset ,
353328 source = self .source ,
354329 )
355- )
356- except VariableError :
357- pass
330+
331+ except VariableError :
332+ pass
358333
359334 async def visit_ForHeader (self , node : ast .AST ) -> None : # noqa: N802
360- from robot .errors import VariableError
361335 from robot .parsing .lexer .tokens import Token as RobotToken
362336 from robot .parsing .model .statements import ForHeader
363- from robot .variables .search import contains_variable
364337
365- try :
366- n = cast (ForHeader , node )
367- variables = n .get_tokens (RobotToken .VARIABLE )
368- for variable in variables :
369- if variable is not None and variable .value and contains_variable (variable .value ):
370- self ._results .append (
371- VariableDefinition (
372- name = variable .value ,
373- name_token = variable ,
374- line_no = node .lineno ,
375- col_offset = node .col_offset ,
376- end_line_no = node .end_lineno
377- if node .end_lineno is not None
378- else variable .lineno
379- if variable .lineno is not None
380- else - 1 ,
381- end_col_offset = node .end_col_offset
382- if node .end_col_offset is not None
383- else variable .end_col_offset
384- if variable .end_col_offset is not None
385- else - 1 ,
386- source = self .source ,
387- )
388- )
389- except VariableError :
390- pass
338+ n = cast (ForHeader , node )
339+ variables = n .get_tokens (RobotToken .VARIABLE )
340+ for variable in variables :
341+ variable_token = self .get_variable_token (variable )
342+ if variable_token is not None and variable_token .value and variable_token .value not in self ._results :
343+ self ._results [variable_token .value ] = VariableDefinition (
344+ name = variable_token .value ,
345+ name_token = variable_token ,
346+ line_no = node .lineno ,
347+ col_offset = node .col_offset ,
348+ end_line_no = variable_token .lineno ,
349+ end_col_offset = variable_token .end_col_offset ,
350+ source = self .source ,
351+ )
391352
392353
393354class ImportVisitor (AsyncVisitor ):
0 commit comments