Skip to content

Commit 782d83d

Browse files
committed
fix(language-server): honor semantic model setting changes
1 parent 116ccb5 commit 782d83d

4 files changed

Lines changed: 51 additions & 9 deletions

File tree

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

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -419,11 +419,14 @@ def __get_namespace_for_document_type(
419419
) -> Namespace:
420420
source = str(document.uri.to_path())
421421
imports_manager = self.get_imports_manager(document)
422+
semantic_model_enabled = self._is_semantic_model_enabled(document)
422423

423424
# --- Try disk cache (cold-start acceleration) ---
424425
cache_namespaces = self.analysis_config.cache.cache_namespaces
425426
if cache_namespaces and document.version is None:
426-
result = self._try_load_cached_namespace(source, document, document_type, imports_manager)
427+
result = self._try_load_cached_namespace(
428+
source, document, document_type, imports_manager, semantic_model_enabled
429+
)
427430
if result is not None:
428431
return result
429432

@@ -438,8 +441,6 @@ def __get_namespace_for_document_type(
438441
model = self.get_model(document)
439442

440443
languages, workspace_languages = self.build_languages_from_model(document, model)
441-
experimental_config = self.workspace.get_configuration(ExperimentalConfig, document.uri)
442-
443444
builder = NamespaceBuilder(
444445
imports_manager,
445446
model,
@@ -449,13 +450,13 @@ def __get_namespace_for_document_type(
449450
languages,
450451
workspace_languages,
451452
)
452-
builder.set_semantic_model_enabled(self.analysis_config.semantic_model or experimental_config.semantic_model)
453+
builder.set_semantic_model_enabled(semantic_model_enabled)
453454

454455
result = builder.build()
455456

456457
# Save to disk cache
457458
if cache_namespaces:
458-
self._save_namespace_to_cache(source, result, imports_manager)
459+
self._save_namespace_to_cache(source, result, imports_manager, semantic_model_enabled)
459460

460461
# Update the folder-scoped reference index
461462
self.get_project_index(document).update_file(result.source, result)
@@ -469,12 +470,17 @@ def __get_namespace_for_document_type(
469470

470471
return result
471472

473+
def _is_semantic_model_enabled(self, document: TextDocument) -> bool:
474+
experimental_config = self.workspace.get_configuration(ExperimentalConfig, document.uri)
475+
return self.analysis_config.semantic_model or experimental_config.semantic_model
476+
472477
def _try_load_cached_namespace(
473478
self,
474479
source: str,
475480
document: TextDocument,
476481
document_type: Optional[DocumentType],
477482
imports_manager: ImportsManager,
483+
semantic_model_enabled: bool,
478484
) -> Optional[Namespace]:
479485
"""Attempt to load a Namespace from the disk cache.
480486
@@ -498,14 +504,22 @@ def _try_load_cached_namespace(
498504
)
499505
return None
500506

501-
if entry is None or entry.meta is None:
507+
meta = entry.meta if entry is not None else None
508+
if entry is None or meta is None:
502509
self._logger.debug(
503510
lambda: f"Cache miss for {source}: no cached entry found",
504511
context_name="cache",
505512
)
506513
return None
507514

508-
if not imports_manager.validate_namespace_meta(entry.meta):
515+
if getattr(meta, "semantic_model_enabled", None) != semantic_model_enabled:
516+
self._logger.debug(
517+
lambda: f"Cache miss for {source}: semantic model setting changed",
518+
context_name="cache",
519+
)
520+
return None
521+
522+
if not imports_manager.validate_namespace_meta(meta):
509523
self._logger.debug(
510524
lambda: f"Cache miss for {source}: cached entry is stale, re-analyzing",
511525
context_name="cache",
@@ -559,10 +573,13 @@ def _save_namespace_to_cache(
559573
source: str,
560574
namespace: Namespace,
561575
imports_manager: ImportsManager,
576+
semantic_model_enabled: bool,
562577
) -> None:
563578
"""Save a Namespace to the disk cache."""
564579
try:
565-
meta = imports_manager.build_namespace_meta(source, namespace)
580+
meta = imports_manager.build_namespace_meta(
581+
source, namespace, semantic_model_enabled=semantic_model_enabled
582+
)
566583
data = namespace.to_data()
567584

568585
data_cache = imports_manager.data_cache

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ class NamespaceMetaData:
579579
source_mtime_ns: int
580580
config_fingerprint: Any
581581
dependency_fingerprints: Dict[str, Any] = field(default_factory=dict)
582+
semantic_model_enabled: bool = False
582583

583584

584585
class ImportsManager:
@@ -814,7 +815,9 @@ def compute_dependency_fingerprints(self, namespace: "Namespace") -> Dict[str, A
814815

815816
return fingerprints
816817

817-
def build_namespace_meta(self, source: str, namespace: "Namespace") -> NamespaceMetaData:
818+
def build_namespace_meta(
819+
self, source: str, namespace: "Namespace", *, semantic_model_enabled: bool = False
820+
) -> NamespaceMetaData:
818821
"""Build a NamespaceMetaData for the given namespace and its dependencies."""
819822
try:
820823
source_mtime_ns = os.stat(source, follow_symlinks=False).st_mtime_ns
@@ -826,6 +829,7 @@ def build_namespace_meta(self, source: str, namespace: "Namespace") -> Namespace
826829
source_mtime_ns=source_mtime_ns,
827830
config_fingerprint=self.config_fingerprint,
828831
dependency_fingerprints=self.compute_dependency_fingerprints(namespace),
832+
semantic_model_enabled=semantic_model_enabled,
829833
)
830834

831835
def validate_namespace_meta(self, meta: NamespaceMetaData) -> bool:

tests/robotcode/robot/diagnostics/test_namespace_cache.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ def test_meta_inequality_mtime(self, mocker: MockerFixture) -> None:
138138
meta2 = NamespaceMetaData("/a.robot", 200, ())
139139
assert meta1 != meta2
140140

141+
def test_meta_default_semantic_model_disabled(self, mocker: MockerFixture) -> None:
142+
meta = NamespaceMetaData("/a.robot", 100, ())
143+
assert meta.semantic_model_enabled is False
144+
145+
def test_meta_inequality_semantic_model_mode(self, mocker: MockerFixture) -> None:
146+
meta1 = NamespaceMetaData("/a.robot", 100, (), semantic_model_enabled=False)
147+
meta2 = NamespaceMetaData("/a.robot", 100, (), semantic_model_enabled=True)
148+
assert meta1 != meta2
149+
141150

142151
# ===========================================================================
143152
# 1e-f: Fingerprint computation
@@ -258,6 +267,17 @@ def test_builds_meta_with_correct_fields(self, tmp_path: Path, mocker: MockerFix
258267
assert meta.source_mtime_ns > 0
259268
assert isinstance(meta.config_fingerprint, tuple)
260269
assert isinstance(meta.dependency_fingerprints, dict)
270+
assert meta.semantic_model_enabled is False
271+
272+
def test_builds_meta_with_semantic_model_enabled(self, tmp_path: Path, mocker: MockerFixture) -> None:
273+
source = tmp_path / "test.robot"
274+
source.write_text("*** Test Cases ***\n")
275+
276+
ns = _mock_namespace(mocker, source=str(source))
277+
im = _mock_imports_manager(mocker)
278+
279+
meta = ImportsManager.build_namespace_meta(im, str(source), ns, semantic_model_enabled=True)
280+
assert meta.semantic_model_enabled is True
261281

262282
def test_source_set(self, tmp_path: Path, mocker: MockerFixture) -> None:
263283
source = tmp_path / "test.robot"

vscode-client/extension/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ export async function activateAsync(context: vscode.ExtensionContext): Promise<v
183183
"robotcode.documentationServer",
184184
"robotcode.completion",
185185
"robotcode.inlayHints",
186+
"robotcode.experimental",
186187
"robotcode.disableExtension",
187188
]) {
188189
for (const ws of vscode.workspace.workspaceFolders ?? []) {

0 commit comments

Comments
 (0)