Skip to content

Commit 484abe4

Browse files
committed
implement reporting of unused suite variables
1 parent 2caa826 commit 484abe4

File tree

4 files changed

+81
-50
lines changed

4 files changed

+81
-50
lines changed

robotcode/language_server/common/parts/documents.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,10 +245,10 @@ async def _text_document_did_open(self, text_document: TextDocumentItem, *args:
245245
uri = str(Uri(text_document.uri).normalized())
246246
document = self._documents.get(uri, None)
247247

248-
text_changed = True
249248
normalized_text = self._normalize_line_endings(text_document.text)
250249

251250
if document is None:
251+
text_changed = False
252252
document = await self._create_document(
253253
text_document.uri, normalized_text, text_document.language_id, text_document.version
254254
)

robotcode/language_server/robotframework/diagnostics/namespace.py

Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -737,60 +737,63 @@ async def ensure_initialized(self) -> bool:
737737
if not self._initialized:
738738
async with self._initialize_lock:
739739
if not self._initialized:
740+
try:
741+
self._logger.debug(f"ensure_initialized -> initialize {self.document}")
740742

741-
self._logger.debug(f"ensure_initialized -> initialize {self.document}")
742-
743-
imports = await self.get_imports()
744-
745-
data_entry: Optional[Namespace.DataEntry] = None
746-
if self.document is not None:
747-
# check or save several data in documents data cache,
748-
# if imports are different, then the data is invalid
749-
old_imports: List[Import] = self.document.get_data(Namespace)
750-
if old_imports is None:
751-
self.document.set_data(Namespace, imports)
752-
elif old_imports != imports:
753-
new_imports = []
754-
for e in old_imports:
755-
if e in imports:
756-
new_imports.append(e)
757-
for e in imports:
758-
if e not in new_imports:
759-
new_imports.append(e)
760-
self.document.set_data(Namespace, new_imports)
761-
self.document.set_data(Namespace.DataEntry, None)
762-
else:
763-
data_entry = self.document.get_data(Namespace.DataEntry)
764-
765-
if data_entry is not None:
766-
self._libraries = data_entry.libraries.copy()
767-
self._resources = data_entry.resources.copy()
768-
self._variables = data_entry.variables.copy()
769-
self._diagnostics = data_entry.diagnostics.copy()
770-
self._import_entries = data_entry.import_entries.copy()
771-
else:
772-
variables = await self.get_resolvable_variables()
773-
774-
await self._import_default_libraries(variables)
775-
await self._import_imports(
776-
imports, str(Path(self.source).parent), top_level=True, variables=variables
777-
)
743+
imports = await self.get_imports()
778744

745+
data_entry: Optional[Namespace.DataEntry] = None
779746
if self.document is not None:
780-
self.document.set_data(
781-
Namespace.DataEntry,
782-
Namespace.DataEntry(
783-
self._libraries.copy(),
784-
self._resources.copy(),
785-
self._variables.copy(),
786-
self._diagnostics.copy(),
787-
self._import_entries.copy(),
788-
),
747+
# check or save several data in documents data cache,
748+
# if imports are different, then the data is invalid
749+
old_imports: List[Import] = self.document.get_data(Namespace)
750+
if old_imports is None:
751+
self.document.set_data(Namespace, imports)
752+
elif old_imports != imports:
753+
new_imports = []
754+
for e in old_imports:
755+
if e in imports:
756+
new_imports.append(e)
757+
for e in imports:
758+
if e not in new_imports:
759+
new_imports.append(e)
760+
self.document.set_data(Namespace, new_imports)
761+
self.document.set_data(Namespace.DataEntry, None)
762+
else:
763+
data_entry = self.document.get_data(Namespace.DataEntry)
764+
765+
if data_entry is not None:
766+
self._libraries = data_entry.libraries.copy()
767+
self._resources = data_entry.resources.copy()
768+
self._variables = data_entry.variables.copy()
769+
self._diagnostics = data_entry.diagnostics.copy()
770+
self._import_entries = data_entry.import_entries.copy()
771+
else:
772+
variables = await self.get_resolvable_variables()
773+
774+
await self._import_default_libraries(variables)
775+
await self._import_imports(
776+
imports, str(Path(self.source).parent), top_level=True, variables=variables
789777
)
790778

791-
await self._reset_global_variables()
779+
if self.document is not None:
780+
self.document.set_data(
781+
Namespace.DataEntry,
782+
Namespace.DataEntry(
783+
self._libraries.copy(),
784+
self._resources.copy(),
785+
self._variables.copy(),
786+
self._diagnostics.copy(),
787+
self._import_entries.copy(),
788+
),
789+
)
792790

793-
self._initialized = True
791+
await self._reset_global_variables()
792+
793+
self._initialized = True
794+
except BaseException:
795+
await self.invalidate()
796+
raise
794797

795798
return self._initialized
796799

robotcode/language_server/robotframework/parts/diagnostics.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ async def documents_did_change(self, sender: Any, document: TextDocument) -> Non
7777
if res_document is not None:
7878
await self.parent.diagnostics.create_publish_document_diagnostics_task(
7979
res_document,
80-
wait_time=DOCUMENT_DIAGNOSTICS_DEBOUNCE
80+
wait_time=DOCUMENT_DIAGNOSTICS_DEBOUNCE * 2
8181
if res_document.opened_in_editor
8282
else WORKSPACE_DIAGNOSTICS_DEBOUNCE,
8383
)
@@ -284,6 +284,21 @@ async def collect_unused_references(self, sender: Any, document: TextDocument) -
284284
tags=[DiagnosticTag.Unnecessary],
285285
)
286286
)
287+
288+
for var in await namespace.get_own_variables():
289+
references = await self.parent.robot_references.find_variable_references(document, var, False)
290+
if not references and not await Analyzer.should_ignore(document, var.name_range):
291+
result.append(
292+
Diagnostic(
293+
range=var.name_range,
294+
message=f"Variable '{var.name}' is not used.",
295+
severity=DiagnosticSeverity.WARNING,
296+
source=self.source_name,
297+
code="VariableNotUsed",
298+
tags=[DiagnosticTag.Unnecessary],
299+
)
300+
)
301+
287302
return DiagnosticsResult(self.collect_unused_references, result)
288303
except (asyncio.CancelledError, SystemExit, KeyboardInterrupt):
289304
raise

robotcode/language_server/robotframework/parts/references.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def __init__(self, parent: RobotLanguageServerProtocol) -> None:
5050
parent.references.collect.add(self.collect)
5151
parent.documents.did_change.add(self.document_did_change)
5252
self._keyword_reference_cache = AsyncSimpleLRUCache(max_items=None)
53+
self._variable_reference_cache = AsyncSimpleLRUCache(max_items=None)
5354

5455
@async_event
5556
async def cache_cleared(sender) -> None: # NOSONAR
@@ -146,8 +147,20 @@ async def _references_default(
146147

147148
return None
148149

150+
async def has_cached_variable_references(
151+
self, document: TextDocument, variable: VariableDefinition, include_declaration: bool = True
152+
) -> bool:
153+
return await self._variable_reference_cache.has(document, variable, include_declaration)
154+
149155
async def find_variable_references(
150156
self, document: TextDocument, variable: VariableDefinition, include_declaration: bool = True
157+
) -> List[Location]:
158+
return await self._variable_reference_cache.get(
159+
self._find_variable_references, document, variable, include_declaration
160+
)
161+
162+
async def _find_variable_references(
163+
self, document: TextDocument, variable: VariableDefinition, include_declaration: bool = True
151164
) -> List[Location]:
152165
result = []
153166

0 commit comments

Comments
 (0)