From fc7a8ec7324631ca4de67ffda2d1d9fa25b07706 Mon Sep 17 00:00:00 2001 From: Dominik Jain Date: Sun, 2 Aug 2026 12:36:59 +0200 Subject: [PATCH] Fix: LSPFileBuffer: a stale content hash could be returned if files are kept open and file contents were not read before trying to retrieve the hash value --- CHANGELOG.md | 2 ++ src/solidlsp/ls.py | 23 +++++++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf014908..dc03e18d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ Status of the `main` branch. Changes prior to the next official version change w - Fix: F#'s `module ` declarations reported a `selectionRange` pointing at the `module` keyword instead of at ``, so looking up hover/references from a module symbol's position returned the keyword's own docs instead of the module's #925 + - Fix: `LSPFileBuffer`: a stale content hash could be returned if files are kept open + and file contents were not read before trying to retrieve the hash value * JetBrains: - `jet_brains_find_symbol`: Disallow wildcard-only search, delegating to overview tool if request is for file diff --git a/src/solidlsp/ls.py b/src/solidlsp/ls.py index 1d117dba..6d64d76b 100644 --- a/src/solidlsp/ls.py +++ b/src/solidlsp/ls.py @@ -149,21 +149,27 @@ class LSPFileBuffer: """Ensure that the file is opened in the language server.""" self._open_in_ls() + def _invalidate_cached_data(self, mtime: float | None = None) -> float | None: + """ + Invalidates cached data (file contents, hash) if the file was modified since it was read + + :param: the current modification time if it was already read + """ + if self._read_file_modified_date is not None: + if mtime is None: + mtime = self.abs_path.stat().st_mtime + if mtime > self._read_file_modified_date: + self._contents = None + self._content_hash = None + @property def contents(self) -> str: file_modified_date = self.abs_path.stat().st_mtime - - # if contents are cached, check if they are stale (file modification since last read) and invalidate if so - if self._contents is not None: - assert self._read_file_modified_date is not None - if file_modified_date > self._read_file_modified_date: - self._contents = None - + self._invalidate_cached_data(file_modified_date) if self._contents is None: self._read_file_modified_date = file_modified_date self._contents = FileUtils.read_file(str(self.abs_path), self.encoding) self._content_hash = None - return self._contents @contents.setter @@ -179,6 +185,7 @@ class LSPFileBuffer: @property def content_hash(self) -> str: + self._invalidate_cached_data() if self._content_hash is None: self._content_hash = hashlib.md5(self.contents.encode(self.encoding)).hexdigest() return self._content_hash