Summary
The C# symbol extractor can silently stop emitting function symbols partway through a valid file while continuing to emit later classes, structs, enums, fields, and properties.
Two production files currently demonstrate the same cutoff pattern:
SymbolExtractor.CSharpScanner.cs emits no functions after line 443;
DbDebug.cs emits no functions after line 278.
This combines the original scanner-tail and missing-extension-method findings because ExecuteTrackedReader and TrackedRead are only two members of a much broader function-emission cutoff in DbDebug.cs. One extractor fix and regression matrix should cover both files.
Environment
origin/main: c642bc4c3dda4ef659df8e6b699e10f61da3c836
cdidx v1.44.3, locally built
- fresh repository index: 1,430 files, 52,258 symbols, 517,039 references
index_complete: true, reference_graph_complete: true, no extraction cap hits
- build: 0 warnings / 0 errors
- full net8.0 and net9.0 suites: 0 failures
Reproduction
dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll outline \
src/CodeIndex/Indexer/Symbols/SymbolExtractor.CSharpScanner.cs \
--kind function --outline-fields name,line,signature \
--db .cdidx/codeindex.db --json
dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll definition \
CanContinueScanningSameLineBraceBody --exact-name \
--path 'src/CodeIndex/Indexer/Symbols/SymbolExtractor.CSharpScanner.cs' \
--db .cdidx/codeindex.db --json
dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll outline \
src/CodeIndex/Database/DbDebug.cs --kind function \
--db .cdidx/codeindex.db --json
dotnet ./src/CodeIndex/bin/Debug/net8.0/cdidx.dll definition \
ExecuteTrackedReader --exact-name --strict-not-found \
--db .cdidx/codeindex.db
Actual behavior
SymbolExtractor.CSharpScanner.cs has 4,402 lines, but only eight function rows. The final one is FindCSharpBraceRange at lines 281-443. Valid class-level methods beginning with StripLeadingCSharpAttributeLists at line 445 and CanContinueScanningSameLineBraceBody at line 763 are absent. The latter declaration is visible in excerpt and its semantic token is marked as a method declaration, yet definition returns E018_QUERY_NOT_FOUND.
In DbDebug.cs, GetStatementOperation at lines 269-278 is the final emitted function. Later methods are missing, including:
WriteSlowQueryToStderr at line 280;
ExecuteTrackedReader at line 647;
TrackedRead at line 658;
QueryProfileEntry.AddElapsed at line 682;
QueryProfileEntry.MarkCompletedIfSlow at line 686.
The missing extension-method declaration is itself stored as an unresolved call-like reference, and its real calls remain name-only unresolved evidence.
Expected behavior
- Every valid method after the trigger remains independently extractable.
- One failed or skipped declaration candidate cannot poison the remainder of a file.
- Declarations are not emitted as unresolved self-like calls.
outline, definition, inspect, references, and graph commands agree on the restored identities.
- If bounded extraction genuinely cannot continue, the index reports a bounded diagnostic rather than silently claiming complete coverage.
Root-cause evidence
Relevant implementation areas include:
- C# method patterns in
src/CodeIndex/Indexer/Symbols/SymbolExtractor.Patterns.cs;
- multiline method-header construction and candidate advancement in
SymbolExtractor.CSharpScanner.cs;
BuildCSharpMatchLines and leading-attribute/lexical state handling;
- method/property header merging and bounded-regex failure handling.
The PR should first reduce each cutoff to a small fixture and establish the exact state transition. Increasing a regex timeout without explaining the persistent tail suppression is not sufficient.
Focused PR scope
One PR should:
- add minimal fixtures reproducing both cutoff shapes;
- repair the shared declaration-local state, loop advancement, or bounded-match failure;
- restore later method definitions with correct containers, ranges, and signatures;
- remove declaration-as-reference artifacts;
- restore identity-backed call/reference rows where conservative resolution is possible;
- add a diagnostic for any remaining unrecoverable bounded failure;
- add the required bilingual changelog fragment.
Non-goals
- Do not special-case these filenames or method names.
- Do not add a Roslyn dependency.
- Do not redesign graph fallback confidence in this PR; that is tracked separately.
- Do not broadly rewrite the C# extractor.
- Do not replace a visible omission with unbounded lookahead or catastrophic regex work.
Implementation cautions
- Reset only declaration-local state at proven member boundaries; preserve string, comment, attribute, and multiline-header state inside a valid construct.
- Preserve calls before local declarations, generics, tuple/nullable returns,
ref/out/this parameters, expression bodies, constructors, operators, and partial methods.
- Ensure timeout/failure diagnostics remain sanitized and bounded.
- Use semantic tokens as corroborating evidence, not as a second divergent method parser.
Required tests
- A long multiline method followed by several simple methods.
- A normal method followed by a second top-level class with methods.
- A static extension class with consecutive
this receiver methods.
- Block- and expression-bodied methods, constructors, operators, local functions, and properties after the trigger.
- Multiline generic, tuple, and nullable signatures.
- Strings, comments, collection expressions, ranges, indexers, and attributes near the boundary.
- An adversarial bounded-match failure that does not suppress later methods.
Assert complete outline/definition/inspect parity, correct ranges and containers, no declaration-as-unresolved-call rows, no new phantom functions, and no cap/timeout regression.
Acceptance criteria
CanContinueScanningSameLineBraceBody, ExecuteTrackedReader, TrackedRead, AddElapsed, and MarkCompletedIfSlow are indexed as functions.
- Functions after lines 443 and 278 in the two dogfood files are no longer absent.
- Later structural symbols remain unchanged.
- The index does not claim complete extraction after an unrecoverable silent cutoff.
- Full net8.0 and net9.0 suites pass.
Duplicate preflight
Open and closed issues were searched for the affected method names, C# scanner tail loss, function-emission cutoff, and extension-method extraction. No exact existing issue was found.
Summary
The C# symbol extractor can silently stop emitting
functionsymbols partway through a valid file while continuing to emit later classes, structs, enums, fields, and properties.Two production files currently demonstrate the same cutoff pattern:
SymbolExtractor.CSharpScanner.csemits no functions after line 443;DbDebug.csemits no functions after line 278.This combines the original scanner-tail and missing-extension-method findings because
ExecuteTrackedReaderandTrackedReadare only two members of a much broader function-emission cutoff inDbDebug.cs. One extractor fix and regression matrix should cover both files.Environment
origin/main:c642bc4c3dda4ef659df8e6b699e10f61da3c836cdidx v1.44.3, locally builtindex_complete: true,reference_graph_complete: true, no extraction cap hitsReproduction
Actual behavior
SymbolExtractor.CSharpScanner.cshas 4,402 lines, but only eight function rows. The final one isFindCSharpBraceRangeat lines 281-443. Valid class-level methods beginning withStripLeadingCSharpAttributeListsat line 445 andCanContinueScanningSameLineBraceBodyat line 763 are absent. The latter declaration is visible inexcerptand its semantic token is marked as a method declaration, yetdefinitionreturnsE018_QUERY_NOT_FOUND.In
DbDebug.cs,GetStatementOperationat lines 269-278 is the final emitted function. Later methods are missing, including:WriteSlowQueryToStderrat line 280;ExecuteTrackedReaderat line 647;TrackedReadat line 658;QueryProfileEntry.AddElapsedat line 682;QueryProfileEntry.MarkCompletedIfSlowat line 686.The missing extension-method declaration is itself stored as an unresolved call-like reference, and its real calls remain name-only unresolved evidence.
Expected behavior
outline,definition,inspect, references, and graph commands agree on the restored identities.Root-cause evidence
Relevant implementation areas include:
src/CodeIndex/Indexer/Symbols/SymbolExtractor.Patterns.cs;SymbolExtractor.CSharpScanner.cs;BuildCSharpMatchLinesand leading-attribute/lexical state handling;The PR should first reduce each cutoff to a small fixture and establish the exact state transition. Increasing a regex timeout without explaining the persistent tail suppression is not sufficient.
Focused PR scope
One PR should:
Non-goals
Implementation cautions
ref/out/thisparameters, expression bodies, constructors, operators, and partial methods.Required tests
thisreceiver methods.Assert complete outline/definition/inspect parity, correct ranges and containers, no declaration-as-unresolved-call rows, no new phantom functions, and no cap/timeout regression.
Acceptance criteria
CanContinueScanningSameLineBraceBody,ExecuteTrackedReader,TrackedRead,AddElapsed, andMarkCompletedIfSloware indexed as functions.Duplicate preflight
Open and closed issues were searched for the affected method names, C# scanner tail loss, function-emission cutoff, and extension-method extraction. No exact existing issue was found.