mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-06 10:15:38 +00:00
Fix PHP symbol retrieval: declare missing Intelephense client capabilities (#1099)
Fix PHP symbol retrieval via Intelephense LSP * intelephense.py: Add missing client capability declarations for documentSymbol (with hierarchical support), references, hover, and workspace symbol. Without these, Intelephense does not advertise documentSymbolProvider and returns empty results for get_symbols_overview. Add PHP tests validating hierarchical symbols and LS routing fix - test_document_symbols_hierarchical_structure: verifies Intelephense returns DocumentSymbol[] with class/method hierarchy (not flat SymbolInformation[]) when hierarchicalDocumentSymbolSupport is declared - test_full_symbol_tree_within_file: verifies request_full_symbol_tree scoped to sample.php returns Dog/Animal/greet/fetch with Dog containing greet as a child (not at root level) - test_find_symbol_within_php_file: verifies find_symbol with a PHP file path (relative_path=) routes to the PHP language server via get_language_server() rather than iterating all servers Peripheral changes: - symbol.py (LanguageServerSymbolRetriever.find_symbols): When searching within a specific file, route to the file-type-appropriate language server via get_language_server() instead of querying all servers. This ensures PHP files are served by Intelephense and not silently skipped.
This commit is contained in:
1 parent
b3a6045f7e
commit
18cee10fa9
5 files changed
+246
-6
No files matched your search
@@ -184,3 +184,75 @@ class TestPhpLanguageServers:
|
||||
|
||||
usage_in_index_php = {"uri_suffix": "index.php", "line": 13, "character": 0}
|
||||
assert usage_in_index_php in actual_locations_comparable, "Usage of helperFunction in index.php not found"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.PHP], indirect=True)
|
||||
def test_find_symbol(self, language_server: SolidLanguageServer) -> None:
|
||||
"""Test that document symbols are properly retrieved after Intelephense capability fix."""
|
||||
from solidlsp.ls_utils import SymbolUtils
|
||||
|
||||
symbols = language_server.request_full_symbol_tree()
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "helperFunction"), "helperFunction not found in symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "greet"), "greet function not found in symbol tree"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.PHP], indirect=True)
|
||||
def test_document_symbols(self, language_server: SolidLanguageServer) -> None:
|
||||
"""Test that document symbols are properly retrieved for a specific file."""
|
||||
doc_symbols = language_server.request_document_symbols("helper.php")
|
||||
all_symbols = doc_symbols.get_all_symbols_and_roots()
|
||||
symbol_names = [sym.get("name") for sym in all_symbols[0] if sym.get("name")]
|
||||
assert "helperFunction" in symbol_names, f"helperFunction not found in document symbols. Found: {symbol_names}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.PHP], indirect=True)
|
||||
def test_document_symbols_hierarchical_structure(self, language_server: SolidLanguageServer) -> None:
|
||||
"""Verify Intelephense returns hierarchical DocumentSymbol format.
|
||||
|
||||
When hierarchicalDocumentSymbolSupport is declared in client capabilities,
|
||||
Intelephense returns DocumentSymbol[] where class methods appear as children
|
||||
of their parent class. Without this declaration, it falls back to a flat
|
||||
SymbolInformation[] list where all symbols appear at root level with no
|
||||
parent-child relationships.
|
||||
"""
|
||||
all_symbols, root_symbols = language_server.request_document_symbols("sample.php").get_all_symbols_and_roots()
|
||||
|
||||
root_names = [s.get("name") for s in root_symbols]
|
||||
assert "Animal" in root_names, f"Animal class not found at root level. Roots: {root_names}"
|
||||
assert "Dog" in root_names, f"Dog class not found at root level. Roots: {root_names}"
|
||||
assert "Cat" in root_names, f"Cat class not found at root level. Roots: {root_names}"
|
||||
|
||||
# Verify Dog has method children — this is the key assertion for hierarchical support.
|
||||
# With a flat response, Dog would have no children and all methods would be at root level.
|
||||
dog_symbol = next((s for s in root_symbols if s.get("name") == "Dog"), None)
|
||||
assert dog_symbol is not None, "Dog class not found in root symbols"
|
||||
dog_children = dog_symbol.get("children", [])
|
||||
dog_child_names = [c.get("name") for c in dog_children]
|
||||
assert (
|
||||
len(dog_child_names) > 0
|
||||
), f"Dog class has no children — hierarchicalDocumentSymbolSupport is not working. All root symbols: {root_names}"
|
||||
expected_methods = {"greet", "fetch", "getBreed", "describe"}
|
||||
missing = expected_methods - set(dog_child_names)
|
||||
assert not missing, f"Dog class missing expected methods: {missing}. Children found: {dog_child_names}"
|
||||
|
||||
# Methods must NOT appear at root level (that would indicate the flat fallback format).
|
||||
assert "greet" not in root_names, f"greet should be a child of Dog, not at root level. Roots: {root_names}"
|
||||
assert "fetch" not in root_names, f"fetch should be a child of Dog, not at root level. Roots: {root_names}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.PHP], indirect=True)
|
||||
def test_full_symbol_tree_within_file(self, language_server: SolidLanguageServer) -> None:
|
||||
"""Verify request_full_symbol_tree scoped to a PHP file returns correct symbols.
|
||||
|
||||
This validates that Intelephense responds correctly when symbols are requested
|
||||
for a single file, including class/method hierarchy in sample.php.
|
||||
"""
|
||||
from solidlsp.ls_utils import SymbolUtils
|
||||
|
||||
symbols = language_server.request_full_symbol_tree(within_relative_path="sample.php")
|
||||
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "Dog"), "Dog not found in sample.php symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "Animal"), "Animal not found in sample.php symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "greet"), "greet method not found in sample.php symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "fetch"), "fetch method not found in sample.php symbol tree"
|
||||
|
||||
# Methods must appear as children of Dog, not as root-level symbols
|
||||
dog_root = next((s for s in symbols if s.get("name") == "Dog"), None)
|
||||
if dog_root is not None:
|
||||
assert SymbolUtils.symbol_tree_contains_name([dog_root], "greet"), "greet should be nested under Dog in symbol tree"
|
||||
Reference in new issue
Block a user