fix(csharp): stop tuple-typed properties losing their name to the method branch (#1967)

* fix(csharp): stop tuple-typed properties losing their name to the method branch

_extract_base_name_and_type split Roslyn's "Name : Type" property names by
checking for a literal '(' anywhere in the raw string. A C# tuple type is
written with parentheses ("(int X, string Y)"), so a tuple-typed property
tripped that guard and fell into the method branch instead, which kept the
trailing " :" as part of the reported name (e.g. "Position :"). Since
find_symbol defaults to exact name-path matching, such a property becomes
unfindable by its real name.

The guard now only checks for '(' in the identifier segment before the
first " : ", not the whole string, so a parenthesis inside the type
annotation no longer affects branch selection.

* fix(csharp): bump the high-level symbol cache fingerprint

_normalize_symbol_name's output changed in this PR, and
_document_symbols_cache_fingerprint gates the cache that stores its
result; leaving the version at 1 would keep serving the old, corrupted
names to anyone with an existing on-disk cache.
This commit is contained in:
Amir Fathi authored and GitHub committed 2026-09-21 12:14:38 +02:00
1 parent fba5258294
commit 941f4ded18
3 files changed
+35 -4

No files matched your search

+23
View File
@@ -7,6 +7,7 @@ import pytest
from solidlsp import SolidLanguageServer
from solidlsp.language_servers.csharp_language_server import (
CSharpLanguageServer,
breadth_first_file_scan,
find_solution_or_project_file,
)
@@ -200,6 +201,28 @@ class TestCSharpLanguageServer:
), f"Expected ConsoleGreeter.FormatGreeting symbol, got: {implementing_symbols}"
class TestCSharpExtractBaseNameAndType:
"""Regression tests for _extract_base_name_and_type, no running language server needed."""
@pytest.mark.parametrize(
("roslyn_name", "expected"),
[
# Property whose type is a tuple: the literal '(' in the type must not be
# mistaken for a method's parameter list.
("Position : (int X, string Y)", ("Position", ": (int X, string Y)")),
("Name : string", ("Name", ": string")),
("Add(int, int) : int", ("Add", "(int, int) : int")),
("ToString()", ("ToString", "()")),
("SimpleMethod", ("SimpleMethod", "")),
# Both still have a '(' before the first " : ", so they keep the method branch.
("GetPair() : (int, int)", ("GetPair", "() : (int, int)")),
("Merge((int, int) a, (int, int) b) : void", ("Merge", "((int, int) a, (int, int) b) : void")),
],
)
def test_extract_base_name_and_type(self, roslyn_name: str, expected: tuple[str, str]) -> None:
assert CSharpLanguageServer._extract_base_name_and_type(roslyn_name) == expected
@pytest.mark.csharp
class TestCSharpSolutionProjectOpening:
"""Test C# language server solution and project opening functionality."""