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.
- robotcode/robot/__version__.py +1 -1
- robotcode/robot/diagnostics/entities.py +18 -2
- robotcode/robot/diagnostics/keyword_finder.py +17 -1
- robotcode/robot/diagnostics/library_doc.py +2 -2
- robotcode/robot/diagnostics/namespace.py +225 -194
- robotcode/robot/diagnostics/namespace_analyzer.py +173 -157
- robotcode/robot/utils/ast.py +7 -5
- robotcode/robot/utils/variables.py +99 -24
- {robotcode_robot-1.3.0.dev4.dist-info → robotcode_robot-1.3.0.dev5.dist-info}/METADATA +2 -2
- {robotcode_robot-1.3.0.dev4.dist-info → robotcode_robot-1.3.0.dev5.dist-info}/RECORD +12 -12
- {robotcode_robot-1.3.0.dev4.dist-info → robotcode_robot-1.3.0.dev5.dist-info}/WHEEL +0 -0
- {robotcode_robot-1.3.0.dev4.dist-info → robotcode_robot-1.3.0.dev5.dist-info}/licenses/LICENSE.txt +0 -0
robotcode/robot/__version__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "1.3.0-dev.
|
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
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
130
|
-
|
131
|
-
|
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=
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
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[
|
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[
|
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:
|
209
|
+
args: Dict[VariableMatcher, VariableDefinition] = {}
|
229
210
|
|
230
|
-
|
231
|
-
|
232
|
-
for argument_token in arguments:
|
211
|
+
for argument_token in node.get_tokens(Token.ARGUMENT):
|
233
212
|
try:
|
234
|
-
argument =
|
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
|
-
|
246
|
-
|
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=
|
249
|
-
name_token=
|
250
|
-
line_no=
|
251
|
-
col_offset=
|
252
|
-
end_line_no=
|
253
|
-
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
|
-
|
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[
|
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 =
|
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
|
-
|
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
|
-
|
391
|
-
if (
|
392
|
-
|
393
|
-
|
394
|
-
|
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
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
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
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
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
|
-
|
421
|
-
|
422
|
-
if
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
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
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
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
|
442
|
-
|
476
|
+
if not matcher.is_assign(allow_assign_mark=True) or matcher.name is None:
|
477
|
+
continue
|
443
478
|
|
444
|
-
|
445
|
-
|
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
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
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
|
466
|
-
for assign_token in node.get_tokens(Token.
|
467
|
-
|
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
|
-
|
471
|
-
if (
|
472
|
-
|
473
|
-
|
474
|
-
|
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
|
-
|
479
|
-
|
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
|
-
|
490
|
-
|
514
|
+
if matcher not in self._results:
|
515
|
+
stripped_name_token = strip_variable_token(assign_token, matcher=matcher, parse_type=True)
|
491
516
|
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
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
|
-
|
508
|
-
|
528
|
+
except VariableError:
|
529
|
+
pass
|
509
530
|
|
510
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
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
|
-
|
558
|
+
var_type = LocalVariableDefinition
|
549
559
|
|
550
|
-
|
551
|
-
|
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.
|
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.
|
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(
|