Skip to content

Commit 91e242f

Browse files
committed
enhance fatal error detection of diagnostics and discovering
1 parent e833ecf commit 91e242f

File tree

4 files changed

+105
-33
lines changed

4 files changed

+105
-33
lines changed

robotcode/language_server/robotframework/diagnostics/imports_manager.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,12 @@ async def _get_libdoc() -> LibraryDoc:
679679

680680
@_logger.call
681681
async def get_libdoc_from_model(
682-
self, model: ast.AST, source: str, model_type: str = "RESOURCE", scope: str = "GLOBAL"
682+
self,
683+
model: ast.AST,
684+
source: str,
685+
model_type: str = "RESOURCE",
686+
scope: str = "GLOBAL",
687+
append_model_errors: bool = True,
683688
) -> LibraryDoc:
684689

685690
from robot.errors import DataError
@@ -697,10 +702,11 @@ async def get_libdoc_from_model(
697702
error = node.error if isinstance(node, HasError) else None
698703
if error is not None:
699704
errors.append(Error(message=error, type_name="ModelError", source=source, line_no=node.lineno))
700-
node_errors = node.errors if isinstance(node, HasErrors) else None
701-
if node_errors is not None:
702-
for e in node_errors:
703-
errors.append(Error(message=e, type_name="ModelError", source=source, line_no=node.lineno))
705+
if append_model_errors:
706+
node_errors = node.errors if isinstance(node, HasErrors) else None
707+
if node_errors is not None:
708+
for e in node_errors:
709+
errors.append(Error(message=e, type_name="ModelError", source=source, line_no=node.lineno))
704710

705711
res = ResourceFile(source=source)
706712

robotcode/language_server/robotframework/diagnostics/namespace.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ async def get_library_doc(self) -> LibraryDoc:
557557
async with self._library_doc_lock:
558558
if self._library_doc is None:
559559
self._library_doc = await self.imports_manager.get_libdoc_from_model(
560-
self.model, self.source, model_type="RESOURCE"
560+
self.model, self.source, model_type="RESOURCE", append_model_errors=False
561561
)
562562

563563
return self._library_doc

robotcode/language_server/robotframework/parts/diagnostics.py

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,38 @@ async def namespace_invalidated(self, sender: Any, document: TextDocument) -> No
4242
async def collect_namespace_diagnostics(
4343
self, sender: Any, document: TextDocument, cancelation_token: CancelationToken
4444
) -> DiagnosticsResult:
45-
namespace = await self.parent.documents_cache.get_namespace(document)
46-
if namespace is None:
47-
return DiagnosticsResult(self.collect_namespace_diagnostics, None)
45+
try:
46+
namespace = await self.parent.documents_cache.get_namespace(document)
47+
if namespace is None:
48+
return DiagnosticsResult(self.collect_namespace_diagnostics, None)
4849

49-
return DiagnosticsResult(self.collect_namespace_diagnostics, await namespace.get_diagnostisc(cancelation_token))
50+
return DiagnosticsResult(
51+
self.collect_namespace_diagnostics, await namespace.get_diagnostisc(cancelation_token)
52+
)
53+
except (asyncio.CancelledError, SystemExit, KeyboardInterrupt):
54+
raise
55+
except BaseException as e:
56+
return DiagnosticsResult(
57+
self.collect_namespace_diagnostics,
58+
[
59+
Diagnostic(
60+
range=Range(
61+
start=Position(
62+
line=0,
63+
character=0,
64+
),
65+
end=Position(
66+
line=len(await document.get_lines()),
67+
character=len((await document.get_lines())[-1] or ""),
68+
),
69+
),
70+
message=f"Fatal: can't get namespace diagnostics '{e}' ({type(e).__qualname__})",
71+
severity=DiagnosticSeverity.ERROR,
72+
source=self.source_name,
73+
code=type(e).__qualname__,
74+
)
75+
],
76+
)
5077

5178
def _create_error_from_node(self, node: ast.AST, msg: str, source: Optional[str] = None) -> Diagnostic:
5279
return Diagnostic(
@@ -121,7 +148,7 @@ async def collect_token_errors(
121148
character=len((await document.get_lines())[-1] or ""),
122149
),
123150
),
124-
message=f"Fatal {type(e).__qualname__}: {e}",
151+
message=f"Fatal: can't get token diagnostics '{e}' ({type(e).__qualname__})",
125152
severity=DiagnosticSeverity.ERROR,
126153
source=self.source_name,
127154
code=type(e).__qualname__,
@@ -141,16 +168,42 @@ async def collect_walk_model_errors(
141168
from ..utils.ast import HasError, HasErrors
142169
from ..utils.async_ast import iter_nodes
143170

144-
model = await self.parent.documents_cache.get_model(document)
171+
try:
172+
model = await self.parent.documents_cache.get_model(document)
145173

146-
result: List[Diagnostic] = []
147-
async for node in iter_nodes(model):
148-
error = node.error if isinstance(node, HasError) else None
149-
if error is not None:
150-
result.append(self._create_error_from_node(node, error))
151-
errors = node.errors if isinstance(node, HasErrors) else None
152-
if errors is not None:
153-
for e in errors:
154-
result.append(self._create_error_from_node(node, e))
155-
156-
return DiagnosticsResult(self.collect_walk_model_errors, result)
174+
result: List[Diagnostic] = []
175+
async for node in iter_nodes(model):
176+
error = node.error if isinstance(node, HasError) else None
177+
if error is not None:
178+
result.append(self._create_error_from_node(node, error))
179+
errors = node.errors if isinstance(node, HasErrors) else None
180+
if errors is not None:
181+
for e in errors:
182+
result.append(self._create_error_from_node(node, e))
183+
184+
return DiagnosticsResult(self.collect_walk_model_errors, result)
185+
186+
except (asyncio.CancelledError, SystemExit, KeyboardInterrupt):
187+
raise
188+
except BaseException as e:
189+
return DiagnosticsResult(
190+
self.collect_walk_model_errors,
191+
[
192+
Diagnostic(
193+
range=Range(
194+
start=Position(
195+
line=0,
196+
character=0,
197+
),
198+
end=Position(
199+
line=len(await document.get_lines()),
200+
character=len((await document.get_lines())[-1] or ""),
201+
),
202+
),
203+
message=f"Fatal: can't get model diagnostics '{e}' ({type(e).__qualname__})",
204+
severity=DiagnosticSeverity.ERROR,
205+
source=self.source_name,
206+
code=type(e).__qualname__,
207+
)
208+
],
209+
)

robotcode/language_server/robotframework/parts/discovering.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,15 @@ def _build(
146146
if defaults is None:
147147
defaults = TestDefaults()
148148
if model is None:
149-
model = get_model(self._get_source(source), data_only=True, curdir=self._get_curdir(source))
149+
try:
150+
model = get_model(self._get_source(source), data_only=True, curdir=self._get_curdir(source))
151+
except (asyncio.CancelledError, SystemExit, KeyboardInterrupt):
152+
raise
153+
except BaseException:
154+
pass
155+
156+
if model is None:
157+
return suite
150158

151159
SettingsBuilder(suite, defaults).visit(model)
152160
SuiteBuilder(suite, defaults).visit(model)
@@ -312,14 +320,19 @@ async def get_tests_from_document(
312320
self, text_document: TextDocumentIdentifier, id: Optional[str], *args: Any, **kwargs: Any
313321
) -> List[TestItem]:
314322
async def run() -> List[TestItem]:
315-
return await FindTestCasesVisitor().get(
316-
text_document.uri,
317-
await self.parent.documents_cache.get_model(
318-
await self.parent.robot_workspace.get_or_open_document(
319-
Uri(text_document.uri).to_path(), language_id="robotframework"
320-
)
321-
),
322-
id,
323-
)
323+
try:
324+
return await FindTestCasesVisitor().get(
325+
text_document.uri,
326+
await self.parent.documents_cache.get_model(
327+
await self.parent.robot_workspace.get_or_open_document(
328+
Uri(text_document.uri).to_path(), language_id="robotframework"
329+
)
330+
),
331+
id,
332+
)
333+
except (asyncio.CancelledError, SystemExit, KeyboardInterrupt):
334+
raise
335+
except BaseException:
336+
return []
324337

325338
return await run_coroutine_in_thread(run)

0 commit comments

Comments
 (0)