Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1289,6 +1289,18 @@ the public arrays at runtime.
| `volume` | Dockerfile `VOLUME` paths | Container storage search symbol |
| `workdir` | Dockerfile `WORKDIR` paths | Container filesystem search symbol |

For C#, `test.method` ownership is determined from the complete leading attribute
block rather than from the immediately preceding physical line. The bounded scanner
reuses the C# lexical masking pass, so multiline attribute arguments and consecutive
attribute lists are supported while generic attribute type arguments stay within their
own item and brackets or test-like names in comments and normal, verbatim, raw,
interpolated, and character literals are ignored. Explicit
`return:`, `assembly:`, and `module:` targets do not classify a method. A declaration-
context gate tracks expression-initializer braces and rejects bracket-led collection
expressions. Only shaped ordinary method declarations with return types can receive the
test taxonomy; fields, indexers, and constructors (including implicit-return partial
constructors) consume their attribute ownership without being reclassified.

`SymbolKindCatalog.CompatibilityKindFamilies` maps both `typealias` and
`type_parameter` to the broad `type` family for consumers that only understand
the older coarse taxonomy. The persisted `kind` remains semantic, and `--kind`
Expand Down Expand Up @@ -5363,6 +5375,17 @@ test も更新してください。公開 array を実行時に変更しては
| `volume` | Dockerfile `VOLUME` path | container storage search symbol |
| `workdir` | Dockerfile `WORKDIR` path | container filesystem search symbol |

C# の `test.method` 所有権は、直前の物理行だけではなく、先頭に連続する attribute
block 全体から判定します。上限付き scanner は C# の字句 masking pass を再利用するため、
複数行の attribute 引数と連続する attribute list を扱い、generic attribute の型引数を
同じ item 内に保ちつつ、comment、通常文字列、verbatim 文字列、raw 文字列、interpolated
文字列、文字 literal 内の bracket や test 風の名前を無視します。明示的な `return:`、
`assembly:`、`module:` target は method を `test.method` に分類しません。declaration
context gate は expression initializer の brace を追跡して行頭 bracket の collection
expression を拒否します。return type を持つ shaped な通常 method declaration だけが test
taxonomy を受け取り、field、indexer、constructor(暗黙 return の partial constructor を含む)
は attribute 所有権を消費しますが、再分類しません。

古い粗い taxonomy だけを理解する consumer 向けに、
`SymbolKindCatalog.CompatibilityKindFamilies` は `typealias` と
`type_parameter` の両方を広い `type` family へ mapping します。永続化される
Expand Down
2 changes: 2 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ Candidate-ordered parallel-index recovery tests must prove that the fatal result
Extractor coverage is split by language or feature area with partial test classes, while shared helpers remain on the root `SymbolExtractorTests` / `ReferenceExtractorTests` parts.
YAML sequence-hierarchy fixtures must keep sequence items path-only, count empty/scalar/alias items in stable indexes, preserve anchor and block-scalar boundaries, assert logical qualified paths separately from nearest emitted symbol parents, and prove a normal full scan refreshes unchanged YAML rows stamped with the prior extractor contract.
C# declaration-boundary regressions should pair a direct extractor fixture with a real-index `symbols --exact-name` query. Keep invocation and parameter continuations beside valid multi-line methods, constructors, delegates, and local functions so both false-positive rejection and declaration ranges remain observable. Scope-continuation fixtures must also place unmatched delimiters in character/string literals and comments before later methods, then assert that the later methods remain definitions rather than unresolved declaration-shaped calls.
C# test-attribute ownership coverage pairs `SymbolExtractorCSharpTests` with `QueryCommandRunnerIssue5192Tests`. Keep multiline and same-line attribute lists, comments, qualified xUnit names, MSTest/NUnit forms, generic attribute type arguments containing test-like names, literal-contained brackets, direct and initializer-brace collection expressions, attributed fields/indexers/ordinary and partial constructors, ignored targets, member boundaries, and fail-closed budgets in the direct fixture; the persisted fixture must retain `test.method` through outline, symbols, inspect, unused, and `--exclude-tests` behavior while non-test methods remain visible (#5192, regression of #1961).
C# explicit-interface identity coverage pairs extractor assertions for methods, properties, events, and indexers with persisted exact qualified/unqualified queries, fold rewrite validation, inspect/outline checks, and LSP definition/reference scoping. Include multiple and inherited interfaces, generic arity, a same-named public member, and a qualified return type that must not be mistaken for an explicit-interface qualifier.
C# callable-containment fixtures should cover block-bodied test methods, local and nested local functions, named lambdas, expression-bodied members, and nested types together, asserting both symbol parents and call-reference containers. Local-function identity coverage additionally keeps pre/post-declaration calls, nested and sibling blocks, overloads, parameter/local delegate shadowing, method groups, identical enclosing names in unrelated types, incomplete ranges, persisted graph/query/inspect/impact behavior, and LSP definition/reference parity in one coordinated contract (#5188, extending #4840).
C# switch-expression returned-lambda coverage pairs a direct `ReferenceExtractorCSharpTests` regression with an `IndexCommandRunnerFullScanTests` `--rebuild` graph fixture. Keep expression/block, parenthesized, multiline, nested-switch, async, qualified/unqualified, and non-lambda arms together; assert raw call rows, enclosing containers, exact locations, callers/callees, complete graph readiness, and negative positional-pattern/enum controls including guarded, nested, and contextual-keyword-designation patterns with a following-line arrow (#5085).
Expand Down Expand Up @@ -1252,6 +1253,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
extractor のカバレッジは言語または機能領域ごとの partial test class に分割し、共有 helper は root 側の `SymbolExtractorTests` / `ReferenceExtractorTests` に残します。
YAML sequence hierarchy の fixture では、sequence item を path 専用のまま保ち、empty / scalar / alias item を安定した index に数え、anchor と block scalar の境界を維持し、論理 qualified path と最寄りの出力済み symbol parent を分けて検証し、旧 extractor contract が stamp された未変更 YAML row を通常の full scan が更新することも確認してください。
C# の declaration boundary に関する regression では、extractor を直接呼ぶ fixture と、実 index に対する `symbols --exact-name` query を組み合わせてください。呼び出し・parameter の continuation と、正当な複数行 method、constructor、delegate、local function を同居させ、false positive の拒否と宣言 range の両方を観測可能にします。スコープ継続用のテストでは、後続メソッドより前の文字・文字列リテラルとコメントに対応しない区切り記号も置き、後続メソッドが未解決の宣言形式呼び出しではなく定義のままになることも検証してください。
C# の test attribute 所有権 coverage は `SymbolExtractorCSharpTests` と `QueryCommandRunnerIssue5192Tests` を組み合わせます。直接 fixture では複数行 / 同一行の attribute list、comment、修飾 xUnit 名、MSTest / NUnit 形式、test 風の名前を含む generic attribute 型引数、literal 内の bracket、直接および initializer brace 内の collection expression、attribute 付き field / indexer / 通常 constructor / partial constructor、無視する target、member boundary、fail-closed budget を維持し、永続化 fixture では outline、symbols、inspect、unused、`--exclude-tests` の各動作で `test.method` が保たれつつ非 test method が表示されることを確認してください(#5192、#1961 の回帰)。
C# の明示的 interface identity coverage では、method、property、event、indexer の extractor assertion と、永続化後の修飾 / 非修飾の完全一致 query、fold rewrite 検証、inspect / outline、LSP の definition / reference scope を組み合わせます。複数および継承 interface、generic arity、同名 public member に加え、明示的 interface qualifier と誤認してはならない修飾 return type を含めてください。
C# generic outline 表示の coverage は、generic / 非 generic overload、extension / local / explicit-interface method、nested generic の tuple / nullable / array parameter type、constraint、overload を区別する modifier、修飾型 / 具体型名との衝突、escaped / Unicode identifier、attribute / 既定値 literal 内の区切り文字を、抽出と reader setup を共有する1つの `DbReaderTests` fixture に維持します。line 移動を検証する対の fixture は先頭改行以外を同一にし、canonical name / path が不変であることを assertion に含め、旧 index の `Name@line` fallback 用に不完全 signature を手動永続化した row も1件残してください(#4916)。
C# の位置 record に対する検索帰属 coverage は、extractor の座標 assertion、1つの indexed reader fixture、1つの CLI fixture を組み合わせます。record keyword と型名、attribute と component 型、base 引数、body member、同一行の通常 property、複数行 `record struct` component、正規化された verbatim identifier の列、言語未指定の exact grouping、multi-hit の focus 選択、focus の行・列出力、symbol grouping を共通契約に維持します。component 列を持たない旧 symbol では行ベースの fallback を維持してください。C# の座標維持のために comment padding を変更する場合、Java/Kotlin の record component comment が既存 signature を維持することも assertion してください(#5095)。
Expand Down
25 changes: 25 additions & 0 deletions changelog.d/unreleased/5192.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
category: fixed
issues:
- 5192
affected:
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.CSharpScanner.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.Contracts.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.DeclarationMetadata.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.ExtractionPhases.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.PatternEmission.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.PatternEmissionFlow.cs
- tests/CodeIndex.Tests/SymbolExtractorCSharpTests.cs
- tests/CodeIndex.Tests/QueryCommandRunnerIssue5192Tests.cs
- tests/CodeIndex.Tests/IndexCommandRunnerFullScanTests.cs
- DEVELOPER_GUIDE.md
- TESTING_GUIDE.md
---

## English

- **C# test methods keep their taxonomy across multiline attribute blocks (#5192, regression of #1961)** — `Fact`, `Theory`, MSTest, and NUnit markers now remain attached through multiline arguments, consecutive attribute lists, and intervening comments, while literals, generic attribute type arguments, direct or initializer-brace collection expressions, fields, indexers, constructors, ignored attribute targets, member boundaries, and bounded fail-closed inputs cannot spoof or leak `test.method` classification. The C# extractor contract advances so unchanged files in existing indexes are re-extracted.

## 日本語

- **複数行の attribute block でも C# test method の taxonomy を維持するようになりました (#5192、#1961 の回帰)** — `Fact`、`Theory`、MSTest、NUnit の marker は、複数行引数、連続する attribute list、途中の comment を越えて正しい method に関連付けられ、literal、generic attribute 型引数、直接または initializer brace 内の collection expression、field、indexer、constructor、無視対象の attribute target、member boundary、上限を超えて fail-closed となる入力が `test.method` 分類を偽装または後続宣言へ漏出することを防ぎます。C# extractor contract も更新し、既存 index の未変更ファイルを再抽出します。
10 changes: 8 additions & 2 deletions src/CodeIndex/Indexer/Symbols/SymbolExtractor.CSharpScanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -811,12 +811,13 @@ private static void NormalizeCSharpImplicitPartialConstructorReturnTypes(List<Sy
foreach (var symbol in symbols)
{
var signature = symbol.Signature?.TrimStart();
if (symbol.Kind == "function"
if (symbol.Kind is "function" or "test.method"
&& symbol.ReturnType == "void"
&& string.Equals(symbol.Name, symbol.ContainerName, StringComparison.Ordinal)
&& signature != null
&& CSharpPartialFunctionDeclarationSignatureRegex.IsMatch(signature))
{
symbol.Kind = "function";
symbol.ReturnType = null;
}
}
Expand Down Expand Up @@ -3916,12 +3917,15 @@ private static string[] BuildCSharpMatchLines(
bool applyCSharpRegexProbeOptimizations,
CSharpRegexProbeCounts? csharpRegexProbeCounts,
out int[]?[] collapsedToRaw,
out string[] scopeLines)
out string[] scopeLines,
out bool[] testMethodAttributedDeclarationLines)
{
var matchLines = new string[rawLines.Length];
collapsedToRaw = new int[]?[rawLines.Length];
scopeLines = new string[rawLines.Length];
testMethodAttributedDeclarationLines = new bool[rawLines.Length];
var csharpLexState = new CSharpLexState();
var testAttributeScanner = new CSharpTestAttributePrefixScanner();
var inLeadingAttributeBlock = false;
var attributeBracketDepth = 0;
var attributeParenDepth = 0;
Expand All @@ -3937,6 +3941,8 @@ private static string[] BuildCSharpMatchLines(
// masking が必要であり、汎用 structural masking だけでは全 C# literal を扱えない。
scopeLines[lineIndex] = BlankCSharpStringDelimitersForCrossLineScan(
lexedLine.SanitizedLine);
testMethodAttributedDeclarationLines[lineIndex] =
testAttributeScanner.ScanLine(scopeLines[lineIndex]);
matchLines[lineIndex] = CollapseCSharpGenericTypeWhitespace(
StripLeadingCSharpAttributeLists(
lexedLine.SanitizedLine,
Expand Down
6 changes: 5 additions & 1 deletion src/CodeIndex/Indexer/Symbols/SymbolExtractor.Contracts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ public static partial class SymbolExtractor
// lexical token spans, and unambiguous positional arity are persisted after version 15.
// バージョン 16 (#5189) は version 15 適用後の既存 index に対して C# constructor call を
// 再抽出し、canonical alias target、字句 token span、曖昧でない位置引数 arity を永続化する。
public const int CSharpContractVersion = 16;
// Version 17 (#5192) re-extracts C# symbols so test-method taxonomy from
// multiline attribute blocks is persisted for existing indexes.
// バージョン 17 (#5192) は既存 index の C# symbol を再抽出し、複数行の
// attribute block から得た test method taxonomy を永続化する。
public const int CSharpContractVersion = 17;
public const int DockerfileContractVersion = 2;
public const int MakefileContractVersion = 2;
public const int StyleAndXamlContractVersion = 2;
Expand Down
Loading
Loading