mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-14 16:18:03 +00:00
Clojure LSP: improve module resolution by parsing source path providers
This commit is contained in:
1 parent
42b5500efc
commit
077dba4d21
8 files changed
+291
-7
No files matched your search
@@ -0,0 +1,110 @@
|
||||
"""Regression tests for clojure-lsp project-wide indexing.
|
||||
|
||||
Bug: ``find_referencing_symbols`` (and the underlying ``request_references``)
|
||||
returns incomplete cross-file results unless the referencing files have already
|
||||
been opened/indexed during the current session via ``find_symbol`` /
|
||||
``get_symbols_overview``. The result is deterministically partial — it grows as
|
||||
more files happen to get indexed by side-effect — which silently biases call
|
||||
graphs towards files the user has already explored.
|
||||
|
||||
The tests here use a fresh module-scoped language server and probe a symbol
|
||||
whose references live in a file (``extra.clj``) that no other test in this
|
||||
module touches. The references must be returned even though no prior tool call
|
||||
has caused the file to be opened in the LSP.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from serena.util.text_utils import find_text_coordinates
|
||||
from solidlsp.ls import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.conftest import language_tests_enabled
|
||||
from test.solidlsp.conftest import read_repo_file
|
||||
|
||||
from . import CORE_PATH, TEST_APP_PATH
|
||||
|
||||
EXTRA_PATH = str(TEST_APP_PATH / "extra.clj")
|
||||
SUBMODULE_CONSUMER_PATH = str(Path("sub_module") / "src" / "sub_module_app" / "consumer.clj")
|
||||
|
||||
|
||||
@pytest.mark.skipif(not language_tests_enabled(Language.CLOJURE), reason="Clojure tests are disabled")
|
||||
@pytest.mark.clojure
|
||||
class TestClojureProjectIndexing:
|
||||
"""Covers the "indexing leaks through results" bug for clojure-lsp.
|
||||
|
||||
The fixture is module-scoped, so all tests within this class share a single
|
||||
server. We deliberately avoid any operation that would open ``extra.clj``
|
||||
(``get_symbols_overview``, ``find_symbol``, ``open_file``) before asserting
|
||||
on references — otherwise the bug would be masked by the side-effectful
|
||||
indexing of those calls.
|
||||
"""
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
|
||||
def test_request_references_includes_unopened_file(self, language_server: SolidLanguageServer) -> None:
|
||||
# locate the definition of `multiply` in core.clj without hardcoding coords
|
||||
core_content = read_repo_file(language_server, CORE_PATH)
|
||||
coords = find_text_coordinates(core_content, r"\(defn (multiply)\b", require_unique=True)
|
||||
assert coords is not None, "Could not locate the 'multiply' definition in core.clj"
|
||||
|
||||
# request references straight away — nothing has caused extra.clj to be opened in the LSP
|
||||
refs = language_server.request_references(CORE_PATH, coords.line, coords.col)
|
||||
ref_paths = {r.get("relativePath", "") for r in refs}
|
||||
|
||||
# extra.clj contains two real call sites (in double-product and triple-product);
|
||||
# they must be returned regardless of whether the file was opened beforehand
|
||||
extra_refs = [r for r in refs if r.get("relativePath", "").endswith("extra.clj")]
|
||||
assert extra_refs, (
|
||||
"Expected references to 'multiply' to include call sites from extra.clj, "
|
||||
f"but got files: {sorted(ref_paths)}. "
|
||||
"This indicates clojure-lsp is only indexing files that have been opened "
|
||||
"during the session, so cross-file references are silently incomplete."
|
||||
)
|
||||
assert len(extra_refs) >= 2, (
|
||||
f"Expected at least 2 references in extra.clj (double-product and triple-product), got {len(extra_refs)}: {extra_refs}"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
|
||||
def test_request_references_includes_unopened_sibling_module_file(self, language_server: SolidLanguageServer) -> None:
|
||||
"""Mirrors the real-world penpot bug repro: ``multiply`` is defined in one
|
||||
module (root ``src/``) and consumed from a sibling module that has its
|
||||
own ``deps.edn`` (``sub_module/``). With clojure-lsp running at the
|
||||
repository root, references to ``multiply`` must include the sibling
|
||||
module's call sites — even when no prior tool call has opened those
|
||||
files in the LSP.
|
||||
"""
|
||||
core_content = read_repo_file(language_server, CORE_PATH)
|
||||
coords = find_text_coordinates(core_content, r"\(defn (multiply)\b", require_unique=True)
|
||||
assert coords is not None, "Could not locate the 'multiply' definition in core.clj"
|
||||
|
||||
refs = language_server.request_references(CORE_PATH, coords.line, coords.col)
|
||||
ref_paths = {r.get("relativePath", "") for r in refs}
|
||||
|
||||
consumer_refs = [
|
||||
r for r in refs if r.get("relativePath", "").replace("\\", "/").endswith("sub_module/src/sub_module_app/consumer.clj")
|
||||
]
|
||||
assert consumer_refs, (
|
||||
"Expected references to 'multiply' to include call sites from the sibling module "
|
||||
"(sub_module/src/sub_module_app/consumer.clj), but got files: "
|
||||
f"{sorted(ref_paths)}. This mirrors the penpot bug: clojure-lsp does not appear to "
|
||||
"index files in sibling modules until they are explicitly opened via find_symbol / "
|
||||
"get_symbols_overview, so reference search returns silently incomplete results."
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.CLOJURE], indirect=True)
|
||||
def test_request_referencing_symbols_includes_unopened_file(self, language_server: SolidLanguageServer) -> None:
|
||||
core_content = read_repo_file(language_server, CORE_PATH)
|
||||
coords = find_text_coordinates(core_content, r"\(defn (multiply)\b", require_unique=True)
|
||||
assert coords is not None, "Could not locate the 'multiply' definition in core.clj"
|
||||
|
||||
# request_referencing_symbols is what the user-facing find_referencing_symbols tool calls into
|
||||
refs = language_server.request_referencing_symbols(CORE_PATH, coords.line, coords.col)
|
||||
|
||||
referencing_names = {ref.symbol.get("name", "") for ref in refs if hasattr(ref, "symbol")}
|
||||
# double-product and triple-product live in extra.clj and both call multiply
|
||||
assert "double-product" in referencing_names or "triple-product" in referencing_names, (
|
||||
"Expected referencing symbols to include functions from extra.clj (double-product / triple-product), "
|
||||
f"but got: {sorted(referencing_names)}. "
|
||||
"extra.clj appears not to have been indexed by clojure-lsp because no prior tool call opened it."
|
||||
)
|
||||
Reference in new issue
Block a user