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
2 changes: 2 additions & 0 deletions TESTING_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Use `docs/test-doc-maintenance-plan.md` before moving oversized suites or adding
Console writer synchronization coverage yields between character writes instead of sleeping per character; use enough whole-line iterations to expose interleaving without adding wall-clock delay.
- `SymbolExtractor*Tests.cs` and `ReferenceExtractor*Tests.cs`
Extractor coverage is split by language or feature area with partial test classes, while shared helpers remain on the root `SymbolExtractorTests` / `ReferenceExtractorTests` parts.
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.
Repository-metadata coverage lives in `SymbolExtractorRepositoryMetadataTests.cs` and `ReferenceExtractorRepositoryMetadataTests.cs`; keep TOML, JSON Lines, ignore/attributes, EditorConfig, `.rules`, and application-manifest capability assertions coordinated with conservative local-path and malformed-record controls.
Capability-regression fixtures that require an unsupported language use the explicit `text` placeholder or an ambiguity bucket; do not use a recognized repository-metadata format as the unsupported control.
When moving repeated extractor scenarios out of a giant suite, keep the new partial file grouped by a readable domain such as language, build-file format, or protocol surface, and prefer small semantic assertion helpers over repeated raw substring or predicate assertions.
Expand Down Expand Up @@ -968,6 +969,7 @@ dotnet test --filter "FullyQualifiedName~GitHelperTests"
console writer synchronization coverageは文字writeごとのsleepではなくyieldを使い、wall-clock delayを追加せずinterleavingを露出できる十分なwhole-line iterationを維持してください。
- `SymbolExtractor*Tests.cs` と `ReferenceExtractor*Tests.cs`
extractor のカバレッジは言語または機能領域ごとの partial test class に分割し、共有 helper は root 側の `SymbolExtractorTests` / `ReferenceExtractorTests` に残します。
C# の declaration boundary に関する regression では、extractor を直接呼ぶ fixture と、実 index に対する `symbols --exact-name` query を組み合わせてください。呼び出し・parameter の continuation と、正当な複数行 method、constructor、delegate、local function を同居させ、false positive の拒否と宣言 range の両方を観測可能にします。
repository metadata の coverage は `SymbolExtractorRepositoryMetadataTests.cs` と `ReferenceExtractorRepositoryMetadataTests.cs` に置きます。TOML、JSON Lines、ignore / attributes、EditorConfig、`.rules`、application manifest の capability assertion を、保守的な local-path 抽出と malformed-record control に同期させてください。
未対応言語を必要とする capability regression fixture には明示的な `text` placeholder または ambiguity bucket を使い、認識済み repository metadata 形式を未対応 control に使わないでください。
巨大 suite から繰り返しの extractor シナリオを切り出す場合は、言語、build-file 形式、protocol surface など読みやすい領域ごとの partial file にまとめ、raw substring や predicate assertion の繰り返しより小さな semantic assertion helper を優先してください。
Expand Down
21 changes: 21 additions & 0 deletions changelog.d/unreleased/4831.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
category: fixed
issues:
- 4831
affected:
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.ExtractCore.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.ExtractionPhases.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.LexicalScopes.cs
- src/CodeIndex/Indexer/Symbols/SymbolExtractor.Contracts.cs
- tests/CodeIndex.Tests/SymbolExtractorIssue4831Tests.cs
- tests/CodeIndex.Tests/QueryCommandRunnerIssue4831Tests.cs
- TESTING_GUIDE.md
---

## English

- **C# declaration scanning now rejects expression and parameter continuations (#4831)** — The method and constructor scanner now checks a column-aware declaration-start scope before emitting symbols, so multi-line LINQ or fluent-call arguments no longer create duplicate function definitions and `out` / `params` parameter continuations no longer become functions. Block-lambda statement baselines preserve valid nested local functions, while reconciled conditional-compilation branch-end snapshots and ignored preprocessor payloads keep real methods visible across `#if` alternatives, disabled incomplete text, and arbitrary `#region` text. The C# extractor contract version invalidates stale rows, and focused extractor plus real-index exact-name tests prevent the continuation regressions previously covered by #496 and #4413 from returning.

## 日本語

- **C# の宣言走査で式と parameter の continuation を拒否するようにしました (#4831)** — method / constructor scanner は symbol を出力する前に列位置を考慮した declaration-start scope を確認するため、複数行の LINQ・fluent call 引数から重複 function 定義が生成されず、`out` / `params` の parameter continuation も function になりません。block lambda では statement baseline を設定して正当な入れ子 local function を維持し、conditional compilation では branch end ごとの snapshot を共通状態へreconcileし、preprocessor payload を無視することで、`#if` の代替分岐、無効化された未完了text、任意の `#region` text をまたいでも本物の method を維持します。C# extractor contract version で古い row を stale と判定し、extractor の focused test と実 index の exact-name test により #496 / #4413 で扱った continuation regression の再発を防ぎます。
2 changes: 1 addition & 1 deletion src/CodeIndex/Indexer/Symbols/SymbolExtractor.Contracts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public static partial class SymbolExtractor
public const int DefaultContractVersion = 1;
public const int ExpandedLanguageContractVersion = 2;
public const int PythonContractVersion = 2;
public const int CSharpContractVersion = 6;
public const int CSharpContractVersion = 7;
public const int DockerfileContractVersion = 2;
public const int MakefileContractVersion = 2;
public const int StyleAndXamlContractVersion = 2;
Expand Down
23 changes: 23 additions & 0 deletions src/CodeIndex/Indexer/Symbols/SymbolExtractor.ExtractCore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ private static List<SymbolRecord> ExtractCore(
var getPrivateScopeColumns = scanInputs.GetPrivateScopeColumns;
Func<CSharpTypeBodyScope> GetCSharpInsideTypeBody = scanInputs.GetCSharpInsideTypeBody;
Func<CSharpCallableParameterScope> GetCSharpCallableParameterScope = scanInputs.GetCSharpCallableParameterScope;
Func<CSharpDeclarationStartScope> GetCSharpDeclarationStartScope = scanInputs.GetCSharpDeclarationStartScope;
var getCSharpSwitchExpressionLines = scanInputs.GetCSharpSwitchExpressionLines;
var getCssQualifiedRuleAncestors = scanInputs.GetCssQualifiedRuleAncestors;
var initialSymbolCapacity = EstimateSymbolListInitialCapacity(lines.Length);
Expand Down Expand Up @@ -465,6 +466,28 @@ private static List<SymbolRecord> ExtractCore(
continue;
}

if (lang == "csharp"
&& pattern.Kind == "function"
&& pattern.BodyStyle == BodyStyle.Brace
&& !GetCSharpDeclarationStartScope().CanStartDeclarationAt(i, csharpGateRawStartColumn))
{
// Method and constructor patterns are intentionally broad enough to
// recognize multi-line declarations. Do not let that merger begin from
// an invocation argument or callable-parameter continuation, even when
// a later declaration brace makes the combined text look method-shaped.
// The scope is column-aware so a real same-line sibling remains eligible.
// メソッドとコンストラクタのパターンは複数行宣言を認識するため意図的に
// 広い。後続の宣言 brace によって結合テキストがメソッド形に見えても、
// 呼び出し引数や callable parameter の継続位置から開始してはならない。
// 列単位の scope により、同一行の後続にある本物の sibling は維持する。
// Fixes #4831; prevents regressions covered by #496 and #4413.
lineOffset = FindNextSameLineBraceStatementStart(
matchLine,
absoluteStartColumn + Math.Max(1, match.Length),
lang);
continue;
}

if (lang == "csharp"
&& pattern.Kind == "function"
&& HasCSharpTokenBeforeIndex(matchLine, "when", absoluteStartColumn + match.Groups["name"].Index))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ private sealed class PatternScanInputs
private JavaScriptScopePrivacyFlags[][]? _privateScopeColumns;
private CSharpTypeBodyScope? _csharpInsideTypeBody;
private CSharpCallableParameterScope? _csharpCallableParameterScope;
private CSharpDeclarationStartScope? _csharpDeclarationStartScope;
private bool[]? _csharpSwitchExpressionLines;
private bool _csharpSwitchExpressionLinesInitialized;
private bool[]? _cssQualifiedRuleAncestors;
Expand Down Expand Up @@ -119,6 +120,11 @@ public CSharpCallableParameterScope GetCSharpCallableParameterScope() =>
StructuralLines,
GetCSharpInsideTypeBody());

public CSharpDeclarationStartScope GetCSharpDeclarationStartScope() =>
_csharpDeclarationStartScope ??= BuildCSharpDeclarationStartScope(
StructuralLines,
GetCSharpInsideTypeBody());

private CSharpLexState[] BuildCSharpLineStartStates() =>
_csharpLineStartStates ??= SymbolExtractor.BuildCSharpLineStartStates(_lines);

Expand Down
Loading
Loading