Fix: Properly differentiate between raw and high-level symbol cache fingerprints,

avoiding unnecessary invalidations of the raw cache when only the derived
high-level representation changes

Fixes #1722
This commit is contained in:
Dominik Jain authored and Dr. Dominik Jain committed 2026-07-19 21:24:36 +02:00
1 parent 4379b4e58a
commit f5824231be
4 files changed
+56 -22

No files matched your search

+2
View File
@@ -16,6 +16,8 @@ Status of the `main` branch. Changes prior to the next official version change w
rather than guessing at a body that could be wrong #1498
* Language Servers:
- Fix: Properly differentiate between raw and high-level symbol cache fingerprints, avoiding unnecessary
invalidations of the raw cache when only the derived high-level representation changes
- Java (JDT-LS): add `runtimes` to `ls_specific_settings.java`, a list of extra JRE/JDK entries
(`name`, `path`, optional `default`/`sources`/`javadoc`) passed through to JDT-LS's
`java.configuration.runtimes`. Fixes silently broken JDK type resolution (`java.lang.Object`
@@ -78,7 +78,7 @@ class ClangdLanguageServer(SolidLanguageServer):
self.resolve_main_method_available = threading.Event()
@override
def _document_symbols_cache_fingerprint(self) -> Hashable:
def _raw_document_symbols_cache_fingerprint(self) -> Hashable:
cache_format_version = 1
cpp_settings = self._custom_settings or {}
return (
+5 -7
View File
@@ -169,12 +169,12 @@ class Gopls(SolidLanguageServer):
@override
def _document_symbols_cache_fingerprint(self) -> Hashable:
"""
Compute a deterministic fingerprint of method/implementation versions and Gopls settings/the Go build context.
"""
normalize_symbol_name_version = 1
request_document_symbols_impl_version = 2
return normalize_symbol_name_version, request_document_symbols_impl_version
@override
def _raw_document_symbols_cache_fingerprint(self) -> Hashable:
gopls_settings_raw = self._custom_settings.settings.get("gopls_settings")
gopls_settings: dict | None
@@ -193,7 +193,7 @@ class Gopls(SolidLanguageServer):
# Version processed symbols even when the build context itself is empty.
if gopls_settings is None and not env_subset:
additional_settings_fingerprint = ""
return None
else:
fingerprint_data: dict[str, object] = {
"env": env_subset,
@@ -201,9 +201,7 @@ class Gopls(SolidLanguageServer):
if gopls_settings is not None:
fingerprint_data["gopls_settings"] = gopls_settings
canonical_json = self._canonical_json_or_raise(json, fingerprint_data)
additional_settings_fingerprint = hashlib.sha256(canonical_json.encode("utf-8")).hexdigest()[:16]
return normalize_symbol_name_version, request_document_symbols_impl_version, additional_settings_fingerprint
return hashlib.sha256(canonical_json.encode("utf-8")).hexdigest()[:16]
@override
def _normalize_symbol_name(self, symbol: RawDocumentSymbol, relative_file_path: str) -> str:
+48 -14
View File
@@ -324,6 +324,12 @@ class SolidLanguageServer(ABC):
RAW_DOCUMENT_SYMBOL_CACHE_FILENAME = "raw_document_symbols.pkl"
RAW_DOCUMENT_SYMBOL_CACHE_FILENAME_LEGACY_FALLBACK = "document_symbols_cache_v23-06-25.pkl"
DOCUMENT_SYMBOL_CACHE_VERSION = 4
"""
defines the version of the high-level document symbol format.
This should be incremented whenever there is a change in the way document symbols are stored.
For changes that affect the symbols of a particular language server implementation (subclass),
change :meth:`_document_symbols_cache_fingerprint` instead.
"""
DOCUMENT_SYMBOL_CACHE_FILENAME = "document_symbols.pkl"
# Directories that should always be ignored regardless of language:
@@ -2891,13 +2897,14 @@ class SolidLanguageServer(ABC):
Returns a fingerprint of any language server-specific aspects that result in changes
to the high-level document symbol information.
Language servers must implement this method/change the return value
* whenever they change the `request_document_symbols` implementation to modify the returned content
* are reconfigured in a way that affects the returned contents (e.g. context-specific configuration
such as build flags or environment variables); configuration options can, in such cases, be
hashed together to produce a single fingerprint value.
Language servers must implement this method/change the return value if
the `request_document_symbols` implementation (or any of the methods called by it)
are changed to modify the returned content.
Whenever the value changes, the document symbols cache will be invalidated and re-populated.
Whenever the value changes, the high-level document symbols cache will be invalidated and re-populated.
Note: For aspects that change the values returned by the language server itself,
change `_raw_document_symbols_cache_fingerprint` instead.
The value must be hashable and safe for inclusion in cache version tuples.
E.g. use an integer, a string or a tuple of integers/strings.
@@ -2912,12 +2919,16 @@ class SolidLanguageServer(ABC):
"""
Return the version for the document symbols cache.
Incorporates cache context fingerprint if provided by the language server.
Incorporates cache fingerprints if provided by the language server.
"""
fingerprint = self._document_symbols_cache_fingerprint()
if fingerprint is not None:
return (self.DOCUMENT_SYMBOL_CACHE_VERSION, fingerprint)
return self.DOCUMENT_SYMBOL_CACHE_VERSION
version: list[Hashable] = [self.DOCUMENT_SYMBOL_CACHE_VERSION]
high_level_fingerprint = self._document_symbols_cache_fingerprint()
if high_level_fingerprint is not None:
version.append(high_level_fingerprint)
raw_fingerprint = self._raw_document_symbols_cache_fingerprint()
if raw_fingerprint is not None:
version.append(raw_fingerprint)
return version[0] if len(version) == 1 else tuple(version)
def _save_raw_document_symbols_cache(self) -> None:
cache_file = self.cache_dir / self.RAW_DOCUMENT_SYMBOL_CACHE_FILENAME
@@ -2937,9 +2948,32 @@ class SolidLanguageServer(ABC):
e,
)
def _raw_document_symbols_cache_version(self) -> tuple[Hashable, ...]:
base_version: tuple[Hashable, ...] = (self.RAW_DOCUMENT_SYMBOLS_CACHE_VERSION, self._ls_specific_raw_document_symbols_cache_version)
fingerprint = self._document_symbols_cache_fingerprint()
def _raw_document_symbols_cache_fingerprint(self) -> Hashable | None:
"""
Returns a fingerprint of any language server-specific aspects that result in changes
to the raw document symbol information produced by the language server.
Language servers must implement this method/change the return value whenever they
are reconfigured or otherwise affected in a way that affects the contents returned
by the language server for document symbol requests (raw request result).
For example, this could be context-specific configuration such as build flags or environment variables;
configuration options can, in such cases, be hashed together to produce a single fingerprint value.
Whenever the value changes, the raw document symbols cache (as well as the high-level cache that
builds on the raw results) will be invalidated and re-populated.
The value must be hashable and safe for inclusion in cache version tuples.
E.g. use an integer, a string or a tuple of integers/strings.
For example, if there is a single aspect being considered, use an integer to reflect the version
of this aspect (incrementing it whenever the implementation changes).
If multiple versioned aspects exist, use a tuple of versions, etc.
"""
return None
def _raw_document_symbols_cache_version(self) -> Hashable:
base_version = (self.RAW_DOCUMENT_SYMBOLS_CACHE_VERSION, self._ls_specific_raw_document_symbols_cache_version)
fingerprint = self._raw_document_symbols_cache_fingerprint()
if fingerprint is not None:
return (*base_version, fingerprint)
return base_version