Skip to content

Commit 7b3eb0c

Browse files
committed
perf(analyzer): move model and token analyzing to the normal analysing stage
1 parent 42f96b4 commit 7b3eb0c

File tree

7 files changed

+106
-202
lines changed

7 files changed

+106
-202
lines changed

packages/language_server/src/robotcode/language_server/common/parts/workspace.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
from robotcode.core.uri import Uri
5454
from robotcode.core.utils.dataclasses import from_dict
5555
from robotcode.core.utils.logging import LoggingDescriptor
56-
from robotcode.core.utils.path import path_is_relative_to
5756
from robotcode.core.workspace import ConfigBase, TConfig, WorkspaceFolder
5857
from robotcode.core.workspace import Workspace as CoreWorkspace
5958
from robotcode.jsonrpc2.protocol import rpc_method
@@ -327,21 +326,6 @@ def get_configuration_raw(
327326
result_future.set_result([result])
328327
return result_future
329328

330-
def get_workspace_folder(self, uri: Union[Uri, str]) -> Optional[WorkspaceFolder]:
331-
if isinstance(uri, str):
332-
uri = Uri(uri)
333-
334-
result = sorted(
335-
[f for f in self.workspace_folders if path_is_relative_to(uri.to_path(), f.uri.to_path())],
336-
key=lambda v1: len(v1.uri),
337-
reverse=True,
338-
)
339-
340-
if len(result) > 0:
341-
return result[0]
342-
343-
return None
344-
345329
@rpc_method(name="workspace/didChangeWorkspaceFolders", param_type=DidChangeWorkspaceFoldersParams)
346330
def _workspace_did_change_workspace_folders(
347331
self, event: WorkspaceFoldersChangeEvent, *args: Any, **kwargs: Any

packages/language_server/src/robotcode/language_server/robotframework/parts/diagnostics.py

Lines changed: 0 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
1-
import ast
21
from concurrent.futures import CancelledError
32
from typing import TYPE_CHECKING, Any, List, Optional
43

5-
from robot.parsing.lexer.tokens import Token
6-
74
from robotcode.core.concurrent import check_current_task_canceled
85
from robotcode.core.language import language_id
96
from robotcode.core.lsp.types import (
@@ -25,12 +22,6 @@
2522
)
2623
from robotcode.robot.diagnostics.library_doc import LibraryDoc
2724
from robotcode.robot.diagnostics.namespace import Namespace
28-
from robotcode.robot.utils.ast import (
29-
iter_nodes,
30-
range_from_node,
31-
range_from_token,
32-
)
33-
from robotcode.robot.utils.stubs import HasError, HasErrors, HeaderAndBodyBlock
3425

3526
from ...common.parts.diagnostics import DiagnosticsCollectType, DiagnosticsResult
3627

@@ -50,9 +41,6 @@ def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
5041

5142
self.parent.on_initialized.add(self._on_initialized)
5243

53-
self.parent.diagnostics.collect.add(self.collect_token_errors)
54-
self.parent.diagnostics.collect.add(self.collect_model_errors)
55-
5644
self.parent.diagnostics.collect.add(self.collect_namespace_diagnostics)
5745

5846
self.parent.diagnostics.collect.add(self.collect_unused_keyword_references)
@@ -62,7 +50,6 @@ def __init__(self, parent: "RobotLanguageServerProtocol") -> None:
6250

6351
def _on_initialized(self, sender: Any) -> None:
6452
self.parent.diagnostics.analyze.add(self.analyze)
65-
self.parent.documents_cache.namespace_invalidated.add(self._on_namespace_invalidated)
6653
self.parent.documents_cache.namespace_initialized(self._on_namespace_initialized)
6754
self.parent.documents_cache.libraries_changed.add(self._on_libraries_changed)
6855
self.parent.documents_cache.variables_changed.add(self._on_variables_changed)
@@ -92,12 +79,6 @@ def _on_namespace_initialized(self, sender: Any, namespace: Namespace) -> None:
9279
if namespace.document is not None:
9380
self.parent.diagnostics.force_refresh_document(namespace.document)
9481

95-
@language_id("robotframework")
96-
def _on_namespace_invalidated(self, sender: Any, namespace: Namespace) -> None:
97-
if namespace.document is not None:
98-
namespace.document.remove_cache_entry(self._collect_model_errors)
99-
namespace.document.remove_cache_entry(self._collect_token_errors)
100-
10182
@language_id("robotframework")
10283
def _on_get_related_documents(self, sender: Any, document: TextDocument) -> Optional[List[TextDocument]]:
10384
namespace = self.parent.documents_cache.get_only_initialized_namespace(document)
@@ -165,148 +146,6 @@ def collect_namespace_diagnostics(
165146
],
166147
)
167148

168-
def _create_error_from_node(
169-
self,
170-
node: ast.AST,
171-
msg: str,
172-
source: Optional[str] = None,
173-
only_start: bool = True,
174-
) -> Diagnostic:
175-
from robot.parsing.model.statements import Statement
176-
177-
if isinstance(node, HeaderAndBodyBlock):
178-
if node.header is not None:
179-
node = node.header
180-
elif node.body:
181-
stmt = next((n for n in node.body if isinstance(n, Statement)), None)
182-
if stmt is not None:
183-
node = stmt
184-
185-
return Diagnostic(
186-
range=range_from_node(node, True, only_start),
187-
message=msg,
188-
severity=DiagnosticSeverity.ERROR,
189-
source=source if source is not None else self.source_name,
190-
code="ModelError",
191-
)
192-
193-
def _create_error_from_token(self, token: Token, source: Optional[str] = None) -> Diagnostic:
194-
return Diagnostic(
195-
range=range_from_token(token),
196-
message=token.error if token.error is not None else "(No Message).",
197-
severity=DiagnosticSeverity.ERROR,
198-
source=source if source is not None else self.source_name,
199-
code="TokenError",
200-
)
201-
202-
@language_id("robotframework")
203-
@_logger.call
204-
def collect_token_errors(
205-
self, sender: Any, document: TextDocument, diagnostics_type: DiagnosticsCollectType
206-
) -> DiagnosticsResult:
207-
return document.get_cache(self._collect_token_errors)
208-
209-
def _collect_token_errors(self, document: TextDocument) -> DiagnosticsResult:
210-
from robot.errors import VariableError
211-
from robot.parsing.lexer.tokens import Token
212-
213-
result: List[Diagnostic] = []
214-
try:
215-
for token in self.parent.documents_cache.get_tokens(document):
216-
check_current_task_canceled()
217-
218-
if token.type in [Token.ERROR, Token.FATAL_ERROR]:
219-
result.append(self._create_error_from_token(token))
220-
221-
try:
222-
for variable_token in token.tokenize_variables():
223-
if variable_token == token:
224-
break
225-
226-
if variable_token.type in [Token.ERROR, Token.FATAL_ERROR]:
227-
result.append(self._create_error_from_token(variable_token))
228-
229-
except VariableError as e:
230-
result.append(
231-
Diagnostic(
232-
range=range_from_token(token),
233-
message=str(e),
234-
severity=DiagnosticSeverity.ERROR,
235-
source=self.source_name,
236-
code=type(e).__qualname__,
237-
)
238-
)
239-
except (CancelledError, SystemExit, KeyboardInterrupt):
240-
raise
241-
except BaseException as e:
242-
return DiagnosticsResult(
243-
self.collect_token_errors,
244-
[
245-
Diagnostic(
246-
range=Range(
247-
start=Position(line=0, character=0),
248-
end=Position(
249-
line=len(document.get_lines()),
250-
character=len((document.get_lines())[-1] or ""),
251-
),
252-
),
253-
message=f"Fatal: can't get token diagnostics '{e}' ({type(e).__qualname__})",
254-
severity=DiagnosticSeverity.ERROR,
255-
source=self.source_name,
256-
code=type(e).__qualname__,
257-
)
258-
],
259-
)
260-
261-
return DiagnosticsResult(self.collect_token_errors, self.modify_diagnostics(document, result))
262-
263-
@language_id("robotframework")
264-
@_logger.call
265-
def collect_model_errors(
266-
self, sender: Any, document: TextDocument, diagnostics_type: DiagnosticsCollectType
267-
) -> DiagnosticsResult:
268-
return document.get_cache(self._collect_model_errors)
269-
270-
def _collect_model_errors(self, document: TextDocument) -> DiagnosticsResult:
271-
try:
272-
model = self.parent.documents_cache.get_model(document, True)
273-
274-
result: List[Diagnostic] = []
275-
for node in iter_nodes(model):
276-
check_current_task_canceled()
277-
278-
error = node.error if isinstance(node, HasError) else None
279-
if error is not None:
280-
result.append(self._create_error_from_node(node, error))
281-
errors = node.errors if isinstance(node, HasErrors) else None
282-
if errors is not None:
283-
for e in errors:
284-
result.append(self._create_error_from_node(node, e))
285-
286-
return DiagnosticsResult(self.collect_model_errors, self.modify_diagnostics(document, result))
287-
288-
except (CancelledError, SystemExit, KeyboardInterrupt):
289-
raise
290-
except BaseException as e:
291-
return DiagnosticsResult(
292-
self.collect_model_errors,
293-
[
294-
Diagnostic(
295-
range=Range(
296-
start=Position(line=0, character=0),
297-
end=Position(
298-
line=len(document.get_lines()),
299-
character=len((document.get_lines())[-1] or ""),
300-
),
301-
),
302-
message=f"Fatal: can't get model diagnostics '{e}' ({type(e).__qualname__})",
303-
severity=DiagnosticSeverity.ERROR,
304-
source=self.source_name,
305-
code=type(e).__qualname__,
306-
)
307-
],
308-
)
309-
310149
@language_id("robotframework")
311150
@_logger.call
312151
def collect_unused_keyword_references(

packages/language_server/src/robotcode/language_server/robotframework/parts/hover.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ def _hover_default(self, nodes: List[ast.AST], document: TextDocument, position:
114114
),
115115
)
116116
)
117-
117+
value = None
118118
if found_range is not None:
119119
highlight_range = found_range
120120
if variable.has_value or variable.resolvable:

packages/robot/src/robotcode/robot/diagnostics/errors.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import final
22

3-
DIAGNOSTICS_SOURCE_NAME = "robotcode.namespace"
3+
DIAGNOSTICS_SOURCE_NAME = "robotcode"
44

55

66
@final
@@ -38,3 +38,5 @@ class Error:
3838
OVERRIDDEN_BY_COMMANDLINE = "OverriddenByCommandLine"
3939
VARIABLE_ALREADY_DEFINED = "VariableAlreadyDefined"
4040
VARIABLE_OVERRIDDEN = "VariableOverridden"
41+
MODEL_ERROR = "ModelError"
42+
TOKEN_ERROR = "TokenError"

packages/robot/src/robotcode/robot/diagnostics/model_helper.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from typing import (
99
TYPE_CHECKING,
1010
Any,
11+
Callable,
1112
Iterator,
1213
List,
1314
Optional,
@@ -18,6 +19,7 @@
1819
Union,
1920
)
2021

22+
from robot.errors import VariableError
2123
from robot.parsing.lexer.tokens import Token
2224
from robot.utils.escaping import split_from_equals, unescape
2325
from robot.variables.finders import NOT_FOUND, NumberFinder
@@ -358,21 +360,30 @@ def tokenize_variables(
358360
ignore_errors: bool = False,
359361
*,
360362
extra_types: Optional[Set[str]] = None,
363+
exception_handler: Optional[Callable[[Exception, Token], None]] = None,
361364
) -> Iterator[Token]:
362-
for t in tokenize_variables(token, identifiers, ignore_errors, extra_types=extra_types):
363-
if t.type == Token.VARIABLE:
364-
var, rest = cls.remove_index_from_variable_token(t)
365-
if var is not None:
366-
yield var
367-
if rest is not None:
368-
yield from cls.tokenize_variables(
369-
rest,
370-
identifiers,
371-
ignore_errors,
372-
extra_types=extra_types,
373-
)
374-
else:
375-
yield t
365+
if exception_handler is not None:
366+
ignore_errors = False
367+
try:
368+
for t in tokenize_variables(token, identifiers, ignore_errors, extra_types=extra_types):
369+
if t.type == Token.VARIABLE:
370+
var, rest = cls.remove_index_from_variable_token(t)
371+
if var is not None:
372+
yield var
373+
if rest is not None:
374+
yield from cls.tokenize_variables(
375+
rest,
376+
identifiers,
377+
ignore_errors,
378+
extra_types=extra_types,
379+
)
380+
else:
381+
yield t
382+
except VariableError as e:
383+
if exception_handler is not None:
384+
exception_handler(e, token)
385+
elif not ignore_errors:
386+
raise
376387

377388
@classmethod
378389
def iter_variables_from_token(

packages/robot/src/robotcode/robot/diagnostics/namespace.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -739,8 +739,6 @@ def __init__(
739739

740740
self._in_initialize = False
741741

742-
self._ignored_lines: Optional[List[int]] = None
743-
744742
@event
745743
def has_invalidated(sender) -> None: ...
746744

0 commit comments

Comments
 (0)