From f41365fd0aa59e701b907b8ef20d3806ba095e23 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 1 Jun 2026 00:32:01 +0900 Subject: [PATCH 1/5] Fix Go generic method references (#1440) --- changelog.d/unreleased/1440.fixed.md | 16 +++++++++ .../LanguageReferenceExtractionSupport.cs | 19 ++++++++++- .../ReferenceExtractorTests.cs | 34 +++++++++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 changelog.d/unreleased/1440.fixed.md diff --git a/changelog.d/unreleased/1440.fixed.md b/changelog.d/unreleased/1440.fixed.md new file mode 100644 index 0000000000..9489c71acc --- /dev/null +++ b/changelog.d/unreleased/1440.fixed.md @@ -0,0 +1,16 @@ +--- +category: fixed +issues: + - 1440 +affected: + - src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs + - tests/CodeIndex.Tests/ReferenceExtractorTests.cs +--- + +## English + +- **Go generic methods now keep method type parameters in reference extraction (#1440)** - receiver methods such as `func (r *Repo) Get[T Constraint](input Input) T` no longer treat the type-parameter list as the value-parameter list, so constraints, parameter types, and returns stay attributed to the method. + +## 日本語 + +- **Go のジェネリックメソッドで型パラメータを参照抽出に残すようになりました (#1440)** - `func (r *Repo) Get[T Constraint](input Input) T` のような receiver メソッドで型パラメータリストを値パラメータリストと誤認せず、制約・引数型・戻り値の参照をメソッドに紐づけます。 diff --git a/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs b/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs index 2e93b8928a..2bf830b23a 100644 --- a/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs +++ b/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs @@ -4725,8 +4725,25 @@ private static void EmitGoFunctionSignatureTypes( if (nextParen > afterReceiver) { EmitGoParameterListTypes(preparedLine, firstParen + 1, receiverClose, references, seen, fileId, context, lineNumber, resolveContainerForColumn); - parameterOpen = nextParen; functionHeaderStart = afterReceiver; + + var afterName = afterReceiver + 1; + while (afterName < preparedLine.Length && IsSimpleIdentifierPart(preparedLine[afterName])) + afterName++; + while (afterName < preparedLine.Length && char.IsWhiteSpace(preparedLine[afterName])) + afterName++; + + if (afterName < preparedLine.Length && preparedLine[afterName] == '[') + { + var typeParameterClose = ReferenceExtractor.FindMatchingChar(preparedLine, afterName, '[', ']'); + if (typeParameterClose > afterName) + { + EmitGoTypeParameterConstraints(preparedLine, afterName, typeParameterClose + 1, references, seen, fileId, context, lineNumber, resolveContainerForColumn); + nextParen = preparedLine.IndexOf('(', typeParameterClose + 1); + } + } + + parameterOpen = nextParen; } } } diff --git a/tests/CodeIndex.Tests/ReferenceExtractorTests.cs b/tests/CodeIndex.Tests/ReferenceExtractorTests.cs index 5a9e33fcd8..f848a513de 100644 --- a/tests/CodeIndex.Tests/ReferenceExtractorTests.cs +++ b/tests/CodeIndex.Tests/ReferenceExtractorTests.cs @@ -264,6 +264,40 @@ go worker() && reference.Line == 18); } + [Fact] + public void Extract_Go_GenericMethodsEmitTypeParameterAndParameterReferences() + { + const string content = """ + package demo + + type Repo struct {} + type Constraint interface {} + type Input struct {} + + func (r *Repo) Get[T Constraint](input Input) T { + var zero T + return zero + } + """; + + var symbols = SymbolExtractor.Extract(1, "go", content); + var references = ReferenceExtractor.Extract(1, "go", content, symbols); + + Assert.Contains(symbols, symbol => symbol.Kind == "function" && symbol.Name == "Get"); + Assert.Contains(references, reference => + reference.SymbolName == "Constraint" + && reference.ReferenceKind == "type_reference" + && reference.ContainerName == "Get"); + Assert.Contains(references, reference => + reference.SymbolName == "Input" + && reference.ReferenceKind == "type_reference" + && reference.ContainerName == "Get"); + Assert.Contains(references, reference => + reference.SymbolName == "T" + && reference.ReferenceKind == "type_reference" + && reference.ContainerName == "Get"); + } + [Fact] public void TryGetExtractor_RegisteredLanguage_ReturnsAddressableExtractor() { From e735b8acbc108f5e683e89774cb33ab6fc215c5a Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 1 Jun 2026 00:37:31 +0900 Subject: [PATCH 2/5] Fix PHP property hook references (#1445) --- changelog.d/unreleased/1445.fixed.md | 18 +++++ .../Indexer/References/ReferenceExtractor.cs | 2 +- .../Indexer/Symbols/SymbolExtractor.cs | 72 +++++++++++++++++++ .../ReferenceExtractorTests.cs | 35 +++++++++ tests/CodeIndex.Tests/SymbolExtractorTests.cs | 25 +++++++ 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 changelog.d/unreleased/1445.fixed.md diff --git a/changelog.d/unreleased/1445.fixed.md b/changelog.d/unreleased/1445.fixed.md new file mode 100644 index 0000000000..f8b7e33611 --- /dev/null +++ b/changelog.d/unreleased/1445.fixed.md @@ -0,0 +1,18 @@ +--- +category: fixed +issues: + - 1445 +affected: + - src/CodeIndex/Indexer/References/ReferenceExtractor.cs + - src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs + - tests/CodeIndex.Tests/SymbolExtractorTests.cs + - tests/CodeIndex.Tests/ReferenceExtractorTests.cs +--- + +## English + +- **PHP 8.4 property hooks now expose accessor scopes and hook-body references (#1445)** - `get` and `set` hook bodies are attached to the property, so references inside hook expressions resolve under `property.get` / `property.set` accessors. + +## 日本語 + +- **PHP 8.4 property hook が accessor scope と hook 本文の参照を公開するようになりました (#1445)** - `get` / `set` hook 本文をプロパティに紐づけ、hook 式内の参照を `property.get` / `property.set` accessor 配下で解決します。 diff --git a/src/CodeIndex/Indexer/References/ReferenceExtractor.cs b/src/CodeIndex/Indexer/References/ReferenceExtractor.cs index 2d6f6f6865..6e4f734718 100644 --- a/src/CodeIndex/Indexer/References/ReferenceExtractor.cs +++ b/src/CodeIndex/Indexer/References/ReferenceExtractor.cs @@ -952,7 +952,7 @@ private static StringComparer GetDefinitionNamesComparer(string language) private static List BuildReferenceContainerCandidates(IReadOnlyList symbols) => symbols .Where(symbol => symbol.BodyStartLine != null && symbol.BodyEndLine != null && - (IsFunctionLikeSymbolKind(symbol.Kind) || symbol.Kind == "hook" || symbol.Kind == "class" + (IsFunctionLikeSymbolKind(symbol.Kind) || symbol.Kind == "hook" || symbol.Kind == "accessor" || symbol.Kind == "class" || symbol.Kind == "struct" || symbol.Kind == "namespace" || symbol.Kind == "object" || symbol.Kind == "property" || symbol.Kind == "class_hook")) .OrderBy(symbol => (symbol.BodyEndLine ?? symbol.EndLine) - (symbol.BodyStartLine ?? symbol.StartLine)) diff --git a/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs b/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs index 976d5a5c3f..92c50baad7 100644 --- a/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs +++ b/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs @@ -645,6 +645,9 @@ private readonly record struct JavaScriptClassScanTarget( private static readonly Regex JavaCompactConstructorRegex = new( @"^\s*(?:(?public|private|protected)\s+)?(?\w+)\s*(?=\{|$)", RegexOptions.Compiled | RegexOptions.CultureInvariant); + private static readonly Regex PhpPropertyHookAccessorRegex = new( + @"^\s*(?get|set)\b", + RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex DartClassDeclarationRegex = new( @"^\s*(?:(?:abstract|base|final|interface|sealed)\s+)*(?:mixin\s+)?class\s+\w+", RegexOptions.Compiled | RegexOptions.CultureInvariant); @@ -4060,6 +4063,8 @@ public static List Extract(long fileId, string? lang, string conte ExtractPhpDocblockTypeAliasSymbols(fileId, lines, symbols); if (lang == "php") ExtractPhpDocblockImportTypeSymbols(fileId, lines, symbols); + if (lang == "php") + ExtractPhpPropertyHookSupplementalSymbols(fileId, lines, structuralLines, symbols); if (lang == "swift") ExtractSwiftPropertySupplementalSymbols(fileId, lines, structuralLines, symbols); if (lang == "sql") @@ -4856,6 +4861,73 @@ internal static bool IsJavaScriptTypeScriptReactHookName(string name) && IsJavaScriptTypeScriptIdentifierStart(name[3]) && char.IsUpper(name[3]); + private static void ExtractPhpPropertyHookSupplementalSymbols( + long fileId, + string[] lines, + string[] structuralLines, + List symbols) + { + var existing = new HashSet( + symbols.Select(symbol => $"{symbol.Kind}:{symbol.Name}:{symbol.Line}"), + StringComparer.Ordinal); + + foreach (var property in symbols + .Where(symbol => symbol.Kind == "property" + && symbol.Line >= 1 + && symbol.Line <= lines.Length) + .ToArray()) + { + var lineIndex = property.Line - 1; + var openBraceColumn = structuralLines[lineIndex].IndexOf('{', StringComparison.Ordinal); + if (openBraceColumn < 0) + continue; + + var closeBraceLine = FindBraceRangeEndLine(structuralLines, lineIndex, openBraceColumn); + if (closeBraceLine <= lineIndex) + continue; + + var sawAccessor = false; + for (var accessorLine = lineIndex + 1; accessorLine <= closeBraceLine; accessorLine++) + { + var accessorMatch = PhpPropertyHookAccessorRegex.Match(structuralLines[accessorLine]); + if (!accessorMatch.Success) + continue; + + var accessorName = accessorMatch.Groups["name"].Value; + var symbolName = $"{property.Name}.{accessorName}"; + var key = $"accessor:{symbolName}:{accessorLine + 1}"; + if (!existing.Add(key)) + continue; + + sawAccessor = true; + symbols.Add(new SymbolRecord + { + FileId = fileId, + Kind = "accessor", + Name = symbolName, + Line = accessorLine + 1, + StartLine = accessorLine + 1, + StartColumn = accessorMatch.Groups["name"].Index, + EndLine = accessorLine + 1, + BodyStartLine = accessorLine + 1, + BodyEndLine = accessorLine + 1, + Signature = lines[accessorLine].Trim(), + ContainerKind = "property", + ContainerName = property.Name, + ContainerQualifiedName = property.ContainerQualifiedName, + }); + } + + if (sawAccessor) + { + property.SubKind = CombineSubKinds(property.SubKind, "php_property_hook"); + property.EndLine = Math.Max(property.EndLine, closeBraceLine + 1); + property.BodyStartLine = lineIndex + 1; + property.BodyEndLine = closeBraceLine + 1; + } + } + } + private static void ExtractSwiftPropertySupplementalSymbols( long fileId, string[] lines, diff --git a/tests/CodeIndex.Tests/ReferenceExtractorTests.cs b/tests/CodeIndex.Tests/ReferenceExtractorTests.cs index f848a513de..a70c80eeb8 100644 --- a/tests/CodeIndex.Tests/ReferenceExtractorTests.cs +++ b/tests/CodeIndex.Tests/ReferenceExtractorTests.cs @@ -11514,6 +11514,41 @@ function inspect(User $user): void { Assert.Contains(references, reference => reference.SymbolName == "greet" && reference.ReferenceKind == "call"); } + [Fact] + public void Extract_PhpPropertyHooks_EmitReferencesInsideHookBodies() + { + const string content = """ + $this->firstName . ' ' . $this->lastName; + set => $this->_displayName = strtoupper($value); + } + } + ?> + """; + + var symbols = SymbolExtractor.Extract(1, "php", content); + var references = ReferenceExtractor.Extract(1, "php", content, symbols); + + Assert.Contains(references, reference => + reference.SymbolName == "firstName" + && reference.ReferenceKind == "reference" + && reference.ContainerName == "displayName.get"); + Assert.Contains(references, reference => + reference.SymbolName == "lastName" + && reference.ReferenceKind == "reference" + && reference.ContainerName == "displayName.get"); + Assert.Contains(references, reference => + reference.SymbolName == "_displayName" + && reference.ReferenceKind == "reference" + && reference.ContainerName == "displayName.set"); + Assert.Contains(references, reference => + reference.SymbolName == "strtoupper" + && reference.ReferenceKind == "call" + && reference.ContainerName == "displayName.set"); + } + [Fact] public void Extract_PhpLanguageConstructCalls_AreIgnored() { diff --git a/tests/CodeIndex.Tests/SymbolExtractorTests.cs b/tests/CodeIndex.Tests/SymbolExtractorTests.cs index 2d8d779614..82e727471b 100644 --- a/tests/CodeIndex.Tests/SymbolExtractorTests.cs +++ b/tests/CodeIndex.Tests/SymbolExtractorTests.cs @@ -13741,6 +13741,31 @@ class User { Assert.DoesNotContain(symbols, s => s.Kind == "property" && s.Name == "notAProperty"); } + [Fact] + public void Extract_PHP_DetectsPropertyHookAccessors() + { + var content = """ + $this->firstName . ' ' . $this->lastName; + set => $this->_displayName = strtoupper($value); + } + } + """; + + var symbols = SymbolExtractor.Extract(1, "php", content); + + var property = Assert.Single(symbols, s => s.Kind == "property" && s.Name == "displayName"); + Assert.Equal("php_property_hook", property.SubKind); + Assert.Equal(3, property.StartLine); + Assert.Equal(6, property.EndLine); + Assert.Equal(3, property.BodyStartLine); + Assert.Equal(6, property.BodyEndLine); + Assert.Contains(symbols, s => s.Kind == "accessor" && s.Name == "displayName.get" && s.ContainerKind == "property" && s.ContainerName == "displayName"); + Assert.Contains(symbols, s => s.Kind == "accessor" && s.Name == "displayName.set" && s.ContainerKind == "property" && s.ContainerName == "displayName"); + } + [Fact] public void Extract_PHP_DetectsSameLinePromotedConstructorProperties() { From 847fdcd441e3d331cdfc7cc72909c9685d0b03bc Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 1 Jun 2026 00:39:44 +0900 Subject: [PATCH 3/5] Fix Razor dotted component references (#1479) --- changelog.d/unreleased/1479.fixed.md | 16 ++++++++++++++++ .../LanguageReferenceExtractionSupport.cs | 7 +++---- tests/CodeIndex.Tests/ReferenceExtractorTests.cs | 10 ++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 changelog.d/unreleased/1479.fixed.md diff --git a/changelog.d/unreleased/1479.fixed.md b/changelog.d/unreleased/1479.fixed.md new file mode 100644 index 0000000000..82856d4dff --- /dev/null +++ b/changelog.d/unreleased/1479.fixed.md @@ -0,0 +1,16 @@ +--- +category: fixed +issues: + - 1479 +affected: + - src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs + - tests/CodeIndex.Tests/ReferenceExtractorTests.cs +--- + +## English + +- **Razor component tag references now preserve dotted component names (#1479)** - tags such as `` emit a call reference to the fully qualified component name instead of dropping namespace segments. + +## 日本語 + +- **Razor component tag 参照で dot 付き component 名を保持するようになりました (#1479)** - `` のようなタグで namespace 部分を落とさず、完全修飾 component 名への call 参照を出します。 diff --git a/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs b/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs index 2bf830b23a..fc487e8cf8 100644 --- a/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs +++ b/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs @@ -535,7 +535,7 @@ internal static class LanguageReferenceExtractionSupport RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex RazorComponentTagRegex = new( - @"<(?[A-Z][A-Za-z0-9_]*(?:\.[A-Za-z_]\w*)?)(?=[\s>/])", + @"<(?[A-Z][A-Za-z0-9_]*(?:\.[A-Za-z_]\w*)*)(?=[\s>/])", RegexOptions.Compiled | RegexOptions.CultureInvariant); private static readonly Regex RazorDirectiveTypeRegex = new( @"^\s*@(?:inherits|implements|model)\s+(?[A-Za-z_]\w*(?:\.[A-Za-z_]\w*)*)", @@ -660,11 +660,10 @@ public static void EmitRazorReferences( { var group = match.Groups["name"]; var rawName = group.Value; - var name = LastQualifiedSegment(rawName); + var name = rawName; if (definitionNames?.Contains(name) == true) continue; - var nameOffset = rawName.LastIndexOf(name, StringComparison.Ordinal); - var nameIndex = group.Index + Math.Max(0, nameOffset); + var nameIndex = group.Index; ReferenceExtractor.AddReference( references, diff --git a/tests/CodeIndex.Tests/ReferenceExtractorTests.cs b/tests/CodeIndex.Tests/ReferenceExtractorTests.cs index a70c80eeb8..83bbba9b2d 100644 --- a/tests/CodeIndex.Tests/ReferenceExtractorTests.cs +++ b/tests/CodeIndex.Tests/ReferenceExtractorTests.cs @@ -13709,6 +13709,7 @@ @inject Services.UserService UserService + @@ -13739,14 +13740,19 @@ @inject Services.UserService UserService var qualifiedComponentColumn = content .Split('\n') .Single(line => line.Contains("Shared.DetailPanel", StringComparison.Ordinal)) - .IndexOf("DetailPanel", StringComparison.Ordinal) + 1; + .IndexOf("Shared.DetailPanel", StringComparison.Ordinal) + 1; + var nestedComponentColumn = content + .Split('\n') + .Single(line => line.Contains("MyApp.Components.Forms.LoginButton", StringComparison.Ordinal)) + .IndexOf("MyApp.Components.Forms.LoginButton", StringComparison.Ordinal) + 1; Assert.Contains(references, r => r.SymbolName == "BasePage" && r.ReferenceKind == "type_reference"); Assert.Contains(references, r => r.SymbolName == "IUserActions" && r.ReferenceKind == "type_reference"); Assert.Contains(references, r => r.SymbolName == "Authorize" && r.ReferenceKind == "type_reference"); Assert.Contains(references, r => r.SymbolName == "UserService" && r.ReferenceKind == "type_reference"); Assert.Contains(references, r => r.SymbolName == "UserCard" && r.ReferenceKind == "call"); - Assert.Contains(references, r => r.SymbolName == "DetailPanel" && r.ReferenceKind == "call" && r.Column == qualifiedComponentColumn); + Assert.Contains(references, r => r.SymbolName == "Shared.DetailPanel" && r.ReferenceKind == "call" && r.Column == qualifiedComponentColumn); + Assert.Contains(references, r => r.SymbolName == "MyApp.Components.Forms.LoginButton" && r.ReferenceKind == "call" && r.Column == nestedComponentColumn); Assert.Contains(references, r => r.SymbolName == "HandleClick" && r.ReferenceKind == "razor_event_binding"); Assert.DoesNotContain(references, r => r.SymbolName == "HandleClick" From 0f31cbbb1086227eba157c0d3e0d41d497022814 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 1 Jun 2026 01:11:14 +0900 Subject: [PATCH 4/5] Harden Go generic method parsing (#1440) --- .../Support/LanguageReferenceExtractionSupport.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs b/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs index fc487e8cf8..6731446adf 100644 --- a/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs +++ b/src/CodeIndex/Indexer/References/Support/LanguageReferenceExtractionSupport.cs @@ -4738,7 +4738,11 @@ private static void EmitGoFunctionSignatureTypes( if (typeParameterClose > afterName) { EmitGoTypeParameterConstraints(preparedLine, afterName, typeParameterClose + 1, references, seen, fileId, context, lineNumber, resolveContainerForColumn); - nextParen = preparedLine.IndexOf('(', typeParameterClose + 1); + var valueParameterOpen = preparedLine.IndexOf('(', typeParameterClose + 1); + if (valueParameterOpen < 0) + return; + + nextParen = valueParameterOpen; } } From 912678267a197c92904105a990dccff37e086f49 Mon Sep 17 00:00:00 2001 From: Widthdom Date: Mon, 1 Jun 2026 01:23:34 +0900 Subject: [PATCH 5/5] Handle PHP property hook block bodies (#1445) --- src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs | 14 ++++++++++++-- tests/CodeIndex.Tests/ReferenceExtractorTests.cs | 4 +++- tests/CodeIndex.Tests/SymbolExtractorTests.cs | 10 ++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs b/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs index 92c50baad7..acffdd257f 100644 --- a/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs +++ b/src/CodeIndex/Indexer/Symbols/SymbolExtractor.cs @@ -4899,6 +4899,16 @@ private static void ExtractPhpPropertyHookSupplementalSymbols( if (!existing.Add(key)) continue; + var accessorBodyEndLine = accessorLine; + var accessorNameEnd = accessorMatch.Groups["name"].Index + accessorMatch.Groups["name"].Length; + var accessorOpenBraceColumn = structuralLines[accessorLine].IndexOf('{', accessorNameEnd); + if (accessorOpenBraceColumn >= 0) + { + var accessorCloseBraceLine = FindBraceRangeEndLine(structuralLines, accessorLine, accessorOpenBraceColumn); + if (accessorCloseBraceLine > accessorLine && accessorCloseBraceLine <= closeBraceLine) + accessorBodyEndLine = accessorCloseBraceLine; + } + sawAccessor = true; symbols.Add(new SymbolRecord { @@ -4908,9 +4918,9 @@ private static void ExtractPhpPropertyHookSupplementalSymbols( Line = accessorLine + 1, StartLine = accessorLine + 1, StartColumn = accessorMatch.Groups["name"].Index, - EndLine = accessorLine + 1, + EndLine = accessorBodyEndLine + 1, BodyStartLine = accessorLine + 1, - BodyEndLine = accessorLine + 1, + BodyEndLine = accessorBodyEndLine + 1, Signature = lines[accessorLine].Trim(), ContainerKind = "property", ContainerName = property.Name, diff --git a/tests/CodeIndex.Tests/ReferenceExtractorTests.cs b/tests/CodeIndex.Tests/ReferenceExtractorTests.cs index 83bbba9b2d..294e40d863 100644 --- a/tests/CodeIndex.Tests/ReferenceExtractorTests.cs +++ b/tests/CodeIndex.Tests/ReferenceExtractorTests.cs @@ -11522,7 +11522,9 @@ public void Extract_PhpPropertyHooks_EmitReferencesInsideHookBodies() class User { public string $displayName { get => $this->firstName . ' ' . $this->lastName; - set => $this->_displayName = strtoupper($value); + set { + $this->_displayName = strtoupper($value); + } } } ?> diff --git a/tests/CodeIndex.Tests/SymbolExtractorTests.cs b/tests/CodeIndex.Tests/SymbolExtractorTests.cs index 82e727471b..b95b8ad2e8 100644 --- a/tests/CodeIndex.Tests/SymbolExtractorTests.cs +++ b/tests/CodeIndex.Tests/SymbolExtractorTests.cs @@ -13749,7 +13749,9 @@ public void Extract_PHP_DetectsPropertyHookAccessors() class User { public string $displayName { get => $this->firstName . ' ' . $this->lastName; - set => $this->_displayName = strtoupper($value); + set { + $this->_displayName = strtoupper($value); + } } } """; @@ -13759,11 +13761,11 @@ public string $displayName { var property = Assert.Single(symbols, s => s.Kind == "property" && s.Name == "displayName"); Assert.Equal("php_property_hook", property.SubKind); Assert.Equal(3, property.StartLine); - Assert.Equal(6, property.EndLine); + Assert.Equal(8, property.EndLine); Assert.Equal(3, property.BodyStartLine); - Assert.Equal(6, property.BodyEndLine); + Assert.Equal(8, property.BodyEndLine); Assert.Contains(symbols, s => s.Kind == "accessor" && s.Name == "displayName.get" && s.ContainerKind == "property" && s.ContainerName == "displayName"); - Assert.Contains(symbols, s => s.Kind == "accessor" && s.Name == "displayName.set" && s.ContainerKind == "property" && s.ContainerName == "displayName"); + Assert.Contains(symbols, s => s.Kind == "accessor" && s.Name == "displayName.set" && s.ContainerKind == "property" && s.ContainerName == "displayName" && s.BodyEndLine == 7); } [Fact]