robotcode-robot 1.3.0.dev4__py3-none-any.whl → 1.3.0.dev5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- __version__ = "1.3.0-dev.4"
1
+ __version__ = "1.3.0-dev.5"
@@ -19,7 +19,7 @@ from robot.parsing.lexer.tokens import Token
19
19
  from robotcode.core.lsp.types import Position, Range
20
20
 
21
21
  from ..utils.ast import range_from_token
22
- from ..utils.variables import VariableMatcher
22
+ from ..utils.variables import VariableMatcher, search_variable
23
23
 
24
24
  if TYPE_CHECKING:
25
25
  from robotcode.robot.diagnostics.library_doc import KeywordDoc, LibraryDoc
@@ -187,10 +187,17 @@ class VariableDefinition(SourceEntity):
187
187
 
188
188
  value: Any = field(default=None, compare=False)
189
189
  value_is_native: bool = field(default=False, compare=False)
190
+ value_type: Optional[str] = field(default=None, compare=False)
190
191
 
191
192
  @functools.cached_property
192
193
  def matcher(self) -> VariableMatcher:
193
- return VariableMatcher(self.name)
194
+ return search_variable(self.name)
195
+
196
+ @functools.cached_property
197
+ def convertable_name(self) -> str:
198
+ m = self.matcher
199
+ value_type = f": {self.value_type}" if self.value_type else ""
200
+ return f"{m.identifier}{{{m.base.strip()}{value_type}}}"
194
201
 
195
202
  @single_call
196
203
  def __hash__(self) -> int:
@@ -268,6 +275,15 @@ class ArgumentDefinition(LocalVariableDefinition):
268
275
  return hash((type(self), self.name, self.type, self.range, self.source))
269
276
 
270
277
 
278
+ @dataclass
279
+ class EmbeddedArgumentDefinition(ArgumentDefinition):
280
+ pattern: Optional[str] = field(default=None, compare=False)
281
+
282
+ @single_call
283
+ def __hash__(self) -> int:
284
+ return hash((type(self), self.name, self.type, self.range, self.source))
285
+
286
+
271
287
  @dataclass
272
288
  class LibraryArgumentDefinition(ArgumentDefinition):
273
289
  @single_call
@@ -87,9 +87,25 @@ class KeywordFinder:
87
87
  try:
88
88
  result = self._find_keyword(name, handle_bdd_style)
89
89
  if result is None:
90
+ error_message = "No keyword with found."
91
+
92
+ if name and name.strip(": ").upper() == "FOR":
93
+ error_message = (
94
+ f"Support for the old FOR loop syntax has been removed. "
95
+ f"Replace '{name}' with 'FOR', end the loop with 'END', and "
96
+ f"remove escaping backslashes."
97
+ )
98
+ elif name and name == "\\":
99
+ error_message = (
100
+ "No keyword with name '\\' found. If it is used inside a for "
101
+ "loop, remove escaping backslashes and end the loop with 'END'."
102
+ )
103
+ else:
104
+ error_message = f"No keyword with name '{name}' found."
105
+
90
106
  self.diagnostics.append(
91
107
  DiagnosticsEntry(
92
- f"No keyword with name '{name}' found.",
108
+ error_message,
93
109
  DiagnosticSeverity.ERROR,
94
110
  Error.KEYWORD_NOT_FOUND,
95
111
  )
@@ -67,7 +67,7 @@ from robotcode.core.utils.path import normalized_path
67
67
  from ..utils import get_robot_version
68
68
  from ..utils.ast import (
69
69
  cached_isinstance,
70
- get_variable_token,
70
+ get_first_variable_token,
71
71
  range_from_token,
72
72
  strip_variable_token,
73
73
  )
@@ -2785,7 +2785,7 @@ def _get_argument_definitions_from_line(
2785
2785
 
2786
2786
  for argument_token in (cast(RobotToken, e) for e in arguments):
2787
2787
  try:
2788
- argument = get_variable_token(argument_token)
2788
+ argument = get_first_variable_token(argument_token)
2789
2789
 
2790
2790
  if argument is not None and argument.value != "@{}":
2791
2791
  if argument.value not in args:
@@ -46,7 +46,9 @@ from robotcode.core.uri import Uri
46
46
  from robotcode.core.utils.logging import LoggingDescriptor
47
47
  from robotcode.core.utils.path import same_file
48
48
 
49
+ from ..utils import get_robot_version
49
50
  from ..utils.ast import (
51
+ get_first_variable_token,
50
52
  range_from_node,
51
53
  range_from_token,
52
54
  strip_variable_token,
@@ -58,7 +60,6 @@ from ..utils.variables import (
58
60
  InvalidVariableError,
59
61
  VariableMatcher,
60
62
  is_scalar_assign,
61
- is_variable,
62
63
  search_variable,
63
64
  )
64
65
  from ..utils.visitor import Visitor
@@ -93,6 +94,9 @@ from .library_doc import (
93
94
  )
94
95
  from .namespace_analyzer import NamespaceAnalyzer
95
96
 
97
+ if get_robot_version() >= (7, 0):
98
+ from robot.parsing.model.statements import Var
99
+
96
100
 
97
101
  class DiagnosticsError(Exception):
98
102
  pass
@@ -126,16 +130,11 @@ class VariablesVisitor(Visitor):
126
130
  if name_token is None:
127
131
  return
128
132
 
129
- name = name_token.value
130
-
131
- if name is not None:
132
- match = search_variable(name, ignore_errors=True)
133
- if not match.is_assign(allow_assign_mark=True):
133
+ if name_token.value is not None:
134
+ matcher = search_variable(name_token.value, ignore_errors=True, parse_type=True)
135
+ if not matcher.is_assign(allow_assign_mark=True) or matcher.name is None:
134
136
  return
135
137
 
136
- if name.endswith("="):
137
- name = name[:-1].rstrip()
138
-
139
138
  values = node.get_values(Token.ARGUMENT)
140
139
  has_value = bool(values)
141
140
  value = tuple(
@@ -146,26 +145,21 @@ class VariablesVisitor(Visitor):
146
145
  for s in values
147
146
  )
148
147
 
148
+ stripped_name_token = strip_variable_token(name_token, matcher=matcher, parse_type=True)
149
+
149
150
  self._results.append(
150
151
  VariableDefinition(
151
- name=name,
152
- name_token=strip_variable_token(
153
- Token(
154
- name_token.type,
155
- name,
156
- name_token.lineno,
157
- name_token.col_offset,
158
- name_token.error,
159
- )
160
- ),
161
- line_no=node.lineno,
162
- col_offset=node.col_offset,
163
- end_line_no=node.lineno,
164
- end_col_offset=node.end_col_offset,
152
+ name=matcher.name,
153
+ name_token=stripped_name_token,
154
+ line_no=stripped_name_token.lineno,
155
+ col_offset=stripped_name_token.col_offset,
156
+ end_line_no=stripped_name_token.lineno,
157
+ end_col_offset=stripped_name_token.end_col_offset,
165
158
  source=self.source,
166
159
  has_value=has_value,
167
160
  resolvable=True,
168
161
  value=value,
162
+ value_type=matcher.type,
169
163
  )
170
164
  )
171
165
 
@@ -185,24 +179,11 @@ class VariableVisitorBase(Visitor):
185
179
  self.position = position
186
180
  self.in_args = in_args
187
181
 
188
- self._results: Dict[str, VariableDefinition] = {}
182
+ self._results: Dict[VariableMatcher, VariableDefinition] = {}
189
183
  self.current_kw_doc: Optional[KeywordDoc] = None
190
184
  self.current_kw: Optional[Keyword] = None
191
185
  self._resolved_variables: Any = resolved_variables
192
186
 
193
- def get_variable_token(self, token: Token) -> Optional[Token]:
194
- return next(
195
- (
196
- v
197
- for v in itertools.dropwhile(
198
- lambda t: t.type in Token.NON_DATA_TOKENS,
199
- tokenize_variables(token, ignore_errors=True, extra_types={Token.VARIABLE}),
200
- )
201
- if v.type == Token.VARIABLE
202
- ),
203
- None,
204
- )
205
-
206
187
 
207
188
  class ArgumentVisitor(VariableVisitorBase):
208
189
  def __init__(
@@ -217,7 +198,7 @@ class ArgumentVisitor(VariableVisitorBase):
217
198
 
218
199
  self.current_kw_doc: Optional[KeywordDoc] = current_kw_doc
219
200
 
220
- def get(self, model: ast.AST) -> Dict[str, VariableDefinition]:
201
+ def get(self, model: ast.AST) -> Dict[VariableMatcher, VariableDefinition]:
221
202
  self._results = {}
222
203
 
223
204
  self.visit(model)
@@ -225,13 +206,11 @@ class ArgumentVisitor(VariableVisitorBase):
225
206
  return self._results
226
207
 
227
208
  def visit_Arguments(self, node: Statement) -> None: # noqa: N802
228
- args: List[str] = []
209
+ args: Dict[VariableMatcher, VariableDefinition] = {}
229
210
 
230
- arguments = node.get_tokens(Token.ARGUMENT)
231
-
232
- for argument_token in arguments:
211
+ for argument_token in node.get_tokens(Token.ARGUMENT):
233
212
  try:
234
- argument = self.get_variable_token(argument_token)
213
+ argument = get_first_variable_token(argument_token)
235
214
 
236
215
  if argument is not None and argument.value != "@{}":
237
216
  if (
@@ -242,19 +221,27 @@ class ArgumentVisitor(VariableVisitorBase):
242
221
  ):
243
222
  break
244
223
 
245
- if argument.value not in args:
246
- args.append(argument.value)
224
+ matcher = VariableMatcher(argument.value, parse_type=True, ignore_errors=True)
225
+ if not matcher.is_variable() or matcher.name is None:
226
+ continue
227
+
228
+ stripped_argument_token = strip_variable_token(argument, parse_type=True, matcher=matcher)
229
+
230
+ if matcher not in args:
247
231
  arg_def = ArgumentDefinition(
248
- name=argument.value,
249
- name_token=strip_variable_token(argument),
250
- line_no=argument.lineno,
251
- col_offset=argument.col_offset,
252
- end_line_no=argument.lineno,
253
- end_col_offset=argument.end_col_offset,
232
+ name=matcher.name,
233
+ name_token=stripped_argument_token,
234
+ line_no=stripped_argument_token.lineno,
235
+ col_offset=stripped_argument_token.col_offset,
236
+ end_line_no=stripped_argument_token.lineno,
237
+ end_col_offset=stripped_argument_token.end_col_offset,
254
238
  source=self.namespace.source,
255
239
  keyword_doc=self.current_kw_doc,
240
+ value_type=matcher.type,
256
241
  )
257
- self._results[argument.value] = arg_def
242
+
243
+ args[matcher] = arg_def
244
+ self._results[matcher] = arg_def
258
245
 
259
246
  except VariableError:
260
247
  pass
@@ -301,7 +288,7 @@ class OnlyArgumentsVisitor(VariableVisitorBase):
301
288
  full_name = f"{match.identifier}{{{name}}}"
302
289
  var_token = strip_variable_token(variable_token)
303
290
  var_token.value = name
304
- self._results[full_name] = ArgumentDefinition(
291
+ self._results[match] = ArgumentDefinition(
305
292
  name=full_name,
306
293
  name_token=var_token,
307
294
  line_no=variable_token.lineno,
@@ -325,7 +312,7 @@ class BlockVariableVisitor(OnlyArgumentsVisitor):
325
312
  variables = node.get_tokens(Token.VARIABLE)[:1]
326
313
  if variables and is_scalar_assign(variables[0].value):
327
314
  try:
328
- variable = self.get_variable_token(variables[0])
315
+ variable = get_first_variable_token(variables[0])
329
316
 
330
317
  if variable is not None:
331
318
  self._results[variable.value] = LocalVariableDefinition(
@@ -384,171 +371,213 @@ class BlockVariableVisitor(OnlyArgumentsVisitor):
384
371
  # TODO analyze "Set Local/Global/Suite Variable"
385
372
 
386
373
  for assign_token in node.get_tokens(Token.ASSIGN):
387
- variable_token = self.get_variable_token(assign_token)
388
-
374
+ if (
375
+ self.position is not None
376
+ and self.position in range_from_node(node)
377
+ and self.position > range_from_token(assign_token).end
378
+ ):
379
+ continue
389
380
  try:
390
- if variable_token is not None:
391
- if (
392
- self.position is not None
393
- and self.position in range_from_node(node)
394
- and self.position > range_from_token(variable_token).end
395
- ):
396
- continue
381
+ matcher = search_variable(
382
+ assign_token.value[:-1].rstrip() if assign_token.value.endswith("=") else assign_token.value,
383
+ parse_type=True,
384
+ ignore_errors=True,
385
+ )
397
386
 
398
- if variable_token.value not in self._results:
399
- self._results[variable_token.value] = LocalVariableDefinition(
400
- name=variable_token.value,
401
- name_token=strip_variable_token(variable_token),
402
- line_no=variable_token.lineno,
403
- col_offset=variable_token.col_offset,
404
- end_line_no=variable_token.lineno,
405
- end_col_offset=variable_token.end_col_offset,
406
- source=self.namespace.source,
407
- )
387
+ if not matcher.is_assign(allow_assign_mark=True) or matcher.name is None:
388
+ continue
389
+
390
+ if matcher not in self._results:
391
+ stripped_name_token = strip_variable_token(assign_token, matcher=matcher, parse_type=True)
392
+
393
+ self._results[matcher] = LocalVariableDefinition(
394
+ name=matcher.name,
395
+ name_token=stripped_name_token,
396
+ line_no=stripped_name_token.lineno,
397
+ col_offset=stripped_name_token.col_offset,
398
+ end_line_no=stripped_name_token.lineno,
399
+ end_col_offset=stripped_name_token.end_col_offset,
400
+ source=self.namespace.source,
401
+ value_type=matcher.type,
402
+ )
408
403
 
409
404
  except VariableError:
410
405
  pass
411
406
 
412
- keyword_token = node.get_token(Token.KEYWORD)
413
- if keyword_token is None or not keyword_token.value:
414
- return
415
-
416
- keyword = self.namespace.find_keyword(keyword_token.value, raise_keyword_error=False)
417
- if keyword is None:
418
- return
407
+ # TODO: analyse Set Suite/Test/Global Variable keywords
408
+ # keyword_token = node.get_token(Token.KEYWORD)
409
+ # if keyword_token is None or not keyword_token.value:
410
+ # return
411
+
412
+ # keyword = self.namespace.find_keyword(keyword_token.value, raise_keyword_error=False)
413
+ # if keyword is None:
414
+ # return
415
+
416
+ # if keyword.libtype == "LIBRARY" and keyword.libname == "BuiltIn":
417
+ # var_type = None
418
+ # if keyword.name == "Set Suite Variable":
419
+ # var_type = VariableDefinition
420
+ # elif keyword.name == "Set Global Variable":
421
+ # var_type = GlobalVariableDefinition
422
+ # elif keyword.name == "Set Test Variable" or keyword.name == "Set Task Variable":
423
+ # var_type = TestVariableDefinition
424
+ # elif keyword.name == "Set Local Variable":
425
+ # var_type = LocalVariableDefinition
426
+ # else:
427
+ # return
428
+ # try:
429
+ # variable = node.get_token(Token.ARGUMENT)
430
+ # if variable is None:
431
+ # return
432
+
433
+ # position = range_from_node(node).start
434
+ # position.character = 0
435
+ # var_name = self._get_var_name(variable.value, position)
436
+
437
+ # if var_name is None or not is_variable(var_name):
438
+ # return
439
+
440
+ # var = var_type(
441
+ # name=var_name,
442
+ # name_token=strip_variable_token(variable),
443
+ # line_no=variable.lineno,
444
+ # col_offset=variable.col_offset,
445
+ # end_line_no=variable.lineno,
446
+ # end_col_offset=variable.end_col_offset,
447
+ # source=self.namespace.source,
448
+ # )
449
+
450
+ # if var_name not in self._results or type(self._results[var_name]) is not type(var):
451
+ # if isinstance(var, LocalVariableDefinition) or not any(
452
+ # l for l in self.namespace.get_global_variables() if l.matcher == var.matcher
453
+ # ):
454
+ # self._results[var_name] = var
455
+ # else:
456
+ # self._results.pop(var_name, None)
457
+
458
+ # except VariableError:
459
+ # pass
419
460
 
420
- if keyword.libtype == "LIBRARY" and keyword.libname == "BuiltIn":
421
- var_type = None
422
- if keyword.name == "Set Suite Variable":
423
- var_type = VariableDefinition
424
- elif keyword.name == "Set Global Variable":
425
- var_type = GlobalVariableDefinition
426
- elif keyword.name == "Set Test Variable" or keyword.name == "Set Task Variable":
427
- var_type = TestVariableDefinition
428
- elif keyword.name == "Set Local Variable":
429
- var_type = LocalVariableDefinition
430
- else:
431
- return
461
+ def visit_InlineIfHeader(self, node: Statement) -> None: # noqa: N802
462
+ for assign_token in node.get_tokens(Token.ASSIGN):
463
+ if (
464
+ self.position is not None
465
+ and self.position in range_from_node(node)
466
+ and self.position > range_from_token(assign_token).end
467
+ ):
468
+ continue
432
469
  try:
433
- variable = node.get_token(Token.ARGUMENT)
434
- if variable is None:
435
- return
436
-
437
- position = range_from_node(node).start
438
- position.character = 0
439
- var_name = self._get_var_name(variable.value, position)
470
+ matcher = search_variable(
471
+ assign_token.value[:-1].rstrip() if assign_token.value.endswith("=") else assign_token.value,
472
+ parse_type=True,
473
+ ignore_errors=True,
474
+ )
440
475
 
441
- if var_name is None or not is_variable(var_name):
442
- return
476
+ if not matcher.is_assign(allow_assign_mark=True) or matcher.name is None:
477
+ continue
443
478
 
444
- var = var_type(
445
- name=var_name,
446
- name_token=strip_variable_token(variable),
447
- line_no=variable.lineno,
448
- col_offset=variable.col_offset,
449
- end_line_no=variable.lineno,
450
- end_col_offset=variable.end_col_offset,
451
- source=self.namespace.source,
452
- )
479
+ if matcher not in self._results:
480
+ stripped_name_token = strip_variable_token(assign_token, matcher=matcher, parse_type=True)
453
481
 
454
- if var_name not in self._results or type(self._results[var_name]) is not type(var):
455
- if isinstance(var, LocalVariableDefinition) or not any(
456
- l for l in self.namespace.get_global_variables() if l.matcher == var.matcher
457
- ):
458
- self._results[var_name] = var
459
- else:
460
- self._results.pop(var_name, None)
482
+ self._results[matcher] = LocalVariableDefinition(
483
+ name=matcher.name,
484
+ name_token=stripped_name_token,
485
+ line_no=stripped_name_token.lineno,
486
+ col_offset=stripped_name_token.col_offset,
487
+ end_line_no=stripped_name_token.lineno,
488
+ end_col_offset=stripped_name_token.end_col_offset,
489
+ source=self.namespace.source,
490
+ value_type=matcher.type,
491
+ )
461
492
 
462
493
  except VariableError:
463
494
  pass
464
495
 
465
- def visit_InlineIfHeader(self, node: Statement) -> None: # noqa: N802
466
- for assign_token in node.get_tokens(Token.ASSIGN):
467
- variable_token = self.get_variable_token(assign_token)
468
-
496
+ def visit_ForHeader(self, node: Statement) -> None: # noqa: N802
497
+ for assign_token in node.get_tokens(Token.VARIABLE):
498
+ if (
499
+ self.position is not None
500
+ and self.position in range_from_node(node)
501
+ and self.position > range_from_token(assign_token).end
502
+ ):
503
+ continue
469
504
  try:
470
- if variable_token is not None:
471
- if (
472
- self.position is not None
473
- and self.position in range_from_node(node)
474
- and self.position > range_from_token(variable_token).end
475
- ):
476
- continue
505
+ matcher = search_variable(
506
+ assign_token.value[:-1].rstrip() if assign_token.value.endswith("=") else assign_token.value,
507
+ parse_type=True,
508
+ ignore_errors=True,
509
+ )
477
510
 
478
- if variable_token.value not in self._results:
479
- self._results[variable_token.value] = LocalVariableDefinition(
480
- name=variable_token.value,
481
- name_token=strip_variable_token(variable_token),
482
- line_no=variable_token.lineno,
483
- col_offset=variable_token.col_offset,
484
- end_line_no=variable_token.lineno,
485
- end_col_offset=variable_token.end_col_offset,
486
- source=self.namespace.source,
487
- )
511
+ if not matcher.is_assign(allow_assign_mark=True) or matcher.name is None:
512
+ continue
488
513
 
489
- except VariableError:
490
- pass
514
+ if matcher not in self._results:
515
+ stripped_name_token = strip_variable_token(assign_token, matcher=matcher, parse_type=True)
491
516
 
492
- def visit_ForHeader(self, node: Statement) -> None: # noqa: N802
493
- variables = node.get_tokens(Token.VARIABLE)
494
- for variable in variables:
495
- variable_token = self.get_variable_token(variable)
496
- if variable_token is not None and variable_token.value and variable_token.value not in self._results:
497
- self._results[variable_token.value] = LocalVariableDefinition(
498
- name=variable_token.value,
499
- name_token=strip_variable_token(variable_token),
500
- line_no=variable_token.lineno,
501
- col_offset=variable_token.col_offset,
502
- end_line_no=variable_token.lineno,
503
- end_col_offset=variable_token.end_col_offset,
504
- source=self.namespace.source,
505
- )
517
+ self._results[matcher] = LocalVariableDefinition(
518
+ name=matcher.name,
519
+ name_token=stripped_name_token,
520
+ line_no=stripped_name_token.lineno,
521
+ col_offset=stripped_name_token.col_offset,
522
+ end_line_no=stripped_name_token.lineno,
523
+ end_col_offset=stripped_name_token.end_col_offset,
524
+ source=self.namespace.source,
525
+ value_type=matcher.type,
526
+ )
506
527
 
507
- def visit_Var(self, node: Statement) -> None: # noqa: N802
508
- from robot.parsing.model.statements import Var
528
+ except VariableError:
529
+ pass
509
530
 
510
- variable = node.get_token(Token.VARIABLE)
511
- if variable is None:
512
- return
513
- try:
514
- var_name = variable.value
515
- if var_name.endswith("="):
516
- var_name = var_name[:-1].rstrip()
531
+ if get_robot_version() >= (7, 0):
517
532
 
518
- if not is_variable(var_name):
533
+ def visit_Var(self, node: Var) -> None: # noqa: N802
534
+ name_token = node.get_token(Token.VARIABLE)
535
+ if name_token is None:
519
536
  return
520
537
 
521
- scope = cast(Var, node).scope
538
+ try:
539
+ matcher = search_variable(
540
+ name_token.value[:-1].rstrip() if name_token.value.endswith("=") else name_token.value,
541
+ parse_type=True,
542
+ ignore_errors=True,
543
+ )
544
+ if not matcher.is_assign(allow_assign_mark=True) or matcher.name is None:
545
+ return
546
+
547
+ stripped_name_token = strip_variable_token(name_token, matcher=matcher, parse_type=True)
522
548
 
523
- if scope in ("SUITE",):
524
- var_type = VariableDefinition
525
- elif scope in ("TEST", "TASK"):
526
- var_type = TestVariableDefinition
527
- elif scope in ("GLOBAL",):
528
- var_type = GlobalVariableDefinition
529
- else:
530
- var_type = LocalVariableDefinition
531
-
532
- var = var_type(
533
- name=var_name,
534
- name_token=strip_variable_token(variable),
535
- line_no=variable.lineno,
536
- col_offset=variable.col_offset,
537
- end_line_no=variable.lineno,
538
- end_col_offset=variable.end_col_offset,
539
- source=self.namespace.source,
540
- )
549
+ scope = node.scope
541
550
 
542
- if var_name not in self._results or type(self._results[var_name]) is not type(var):
543
- if isinstance(var, LocalVariableDefinition) or not any(
544
- l for l in self.namespace.get_global_variables() if l.matcher == var.matcher
545
- ):
546
- self._results[var_name] = var
551
+ if scope in ("SUITE",):
552
+ var_type = VariableDefinition
553
+ elif scope in ("TEST", "TASK"):
554
+ var_type = TestVariableDefinition
555
+ elif scope in ("GLOBAL",):
556
+ var_type = GlobalVariableDefinition
547
557
  else:
548
- self._results.pop(var_name, None)
558
+ var_type = LocalVariableDefinition
549
559
 
550
- except VariableError:
551
- pass
560
+ var = var_type(
561
+ name=matcher.name,
562
+ name_token=stripped_name_token,
563
+ line_no=stripped_name_token.lineno,
564
+ col_offset=stripped_name_token.col_offset,
565
+ end_line_no=stripped_name_token.lineno,
566
+ end_col_offset=stripped_name_token.end_col_offset,
567
+ source=self.namespace.source,
568
+ value_type=matcher.type,
569
+ )
570
+
571
+ if matcher not in self._results or type(self._results[matcher]) is not type(var):
572
+ if isinstance(var, LocalVariableDefinition) or not any(
573
+ l for l in self.namespace.get_global_variables() if l.matcher == var.matcher
574
+ ):
575
+ self._results[matcher] = var
576
+ else:
577
+ self._results.pop(matcher, None)
578
+
579
+ except VariableError:
580
+ pass
552
581
 
553
582
 
554
583
  class ImportVisitor(Visitor):
@@ -1119,7 +1148,7 @@ class Namespace:
1119
1148
  ) -> Dict[str, Any]:
1120
1149
  if nodes:
1121
1150
  return {
1122
- v.name: v.value
1151
+ v.convertable_name: v.value
1123
1152
  for k, v in self.yield_variables(nodes, position, skip_commandline_variables=True)
1124
1153
  if v.has_value
1125
1154
  }
@@ -1127,7 +1156,7 @@ class Namespace:
1127
1156
  with self._global_resolvable_variables_lock:
1128
1157
  if self._global_resolvable_variables is None:
1129
1158
  self._global_resolvable_variables = {
1130
- v.name: v.value
1159
+ v.convertable_name: v.value
1131
1160
  for k, v in self.yield_variables(nodes, position, skip_commandline_variables=True)
1132
1161
  if v.has_value
1133
1162
  }
@@ -1153,7 +1182,9 @@ class Namespace:
1153
1182
  ) -> Dict[VariableMatcher, VariableDefinition]:
1154
1183
  self.ensure_initialized()
1155
1184
 
1156
- return {m: v for m, v in self.yield_variables(nodes, position)}
1185
+ # return {m: v for m, v in self.yield_variables(nodes, position)}
1186
+ l = list(self.yield_variables(nodes, position))
1187
+ return dict(reversed(l))
1157
1188
 
1158
1189
  @_logger.call
1159
1190
  def find_variable(