Skip to content

Commit c391deb

Browse files
committed
implement variables and arguments in document symbols, correct collecting of variables
1 parent 0ad6324 commit c391deb

File tree

2 files changed

+219
-124
lines changed

2 files changed

+219
-124
lines changed

robotcode/language_server/robotframework/diagnostics/namespace.py

Lines changed: 75 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -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

393354
class ImportVisitor(AsyncVisitor):

0 commit comments

Comments
 (0)