Skip to content

fix(csharp): recover conditional-directive parses and keep same-arity overload families reachable - #790

Merged
vitali87 merged 11 commits into
mainfrom
fix/csharp-serilog-dogfood
Jul 18, 2026
Merged

fix(csharp): recover conditional-directive parses and keep same-arity overload families reachable#790
vitali87 merged 11 commits into
mainfrom
fix/csharp-serilog-dogfood

Conversation

@vitali87

Copy link
Copy Markdown
Owner

What

Second-repo C# dead-code dogfood, on Serilog (follows the Polly campaign, #782 through #789): Serilog's report goes from 36 findings to ZERO across three root-cause fixes, with Polly and the retrieval eval as regression guards (Polly stays at its single verified true positive; eval numbers identical).

Root causes and fixes

  1. Conditional directives shatter parses into phantom declarations. Serilog's ILogger wraps default interface bodies in #if FEATURE_DEFAULT_INTERFACE; the grammar misparses each member into a property declaration NAMED after the directive condition, with only single-line inner ERROR nodes. Result: 12 phantom nodes named FEATURE_DEFAULT_INTERFACE, one named if, and every real ILogger member registered as a module-level Function. The C# path of the parse-recovery wrapper now retries with conditional-directive lines blanked whenever the tree has any error; the trigger is has_error plus an error-node count, never the line-span metric, which scores single-line errors as zero.
  2. Both-branch retention orphans alternative bodies. Keeping both branches of #if X bodyA #else bodyB #endif around an expression-bodied member leaves the second body orphaned at declaration position, misparsing into a bare phantom method (Polly's DelegatingComponent grew a parameterless ExecuteComponent under the first blanking). Blanking now keeps only the FIRST branch of each group, with nested groups inside a skipped branch staying skipped.
  3. Same-arity overload families starve. Serilog's JsonValueFormatter dispatches FormatExactNumericValue(value, output) through nine switch arms to nine same-ARITY overloads differing only by parameter type; bare-call resolution picked one and the other eight reported dead (also GetLevelMoniker, StructureValue.Render, and the whole PropertyValueConverter/PropertyBinder cascade behind them). A resolved bare call now also emits CALLS to its same-arity signature siblings across partial parts and bases, keeping the family reachable. This is reduction-invisible to the retrieval eval by construction, and the Roslyn oracle counts every switch arm anyway.

Validation

  • RED demonstrated in commit history for all three fixes.
  • Full suite green; all 163 C# tests pass.
  • Serilog dead-code: 36 -> 24 (parse recovery) -> 0 (family fan-out).
  • Polly dead-code: unchanged at 1, the verified PolicyBuilder true positive (the intermediate keep-both-branches state briefly introduced a phantom there, caught by the regression guard and fixed by keep-first-branch).
  • C# retrieval eval (full Polly, semantic oracle): tp 2914, fp 55, precision 0.9815 — identical before and after, as designed.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request improves C# parsing and call resolution by keeping same-arity overload families reachable during bare call resolution and recovering from parse errors caused by interleaved conditional directives by blanking them (retaining only the first branch). Feedback on these changes suggests removing an unused constant _CSHARP_DIRECTIVE_PREFIXES, simplifying a redundant boolean check in _blank_csharp_directives, and correcting a misleading comment regarding which branches are kept during preprocessor recovery.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread codebase_rag/parsers/cpp/preproc_recovery.py Outdated
Comment thread codebase_rag/parsers/cpp/preproc_recovery.py Outdated
Comment thread codebase_rag/parsers/cpp/preproc_recovery.py Outdated
@greptile-apps

greptile-apps Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR improves C# graph recovery for conditional directives and overload families. The main changes are:

  • C# conditional-directive parse recovery that blanks directive lines and keeps the first branch when it reduces parse errors.
  • Same-arity overload family CALLS fan-out for syntax-only bare-call resolution.
  • A semantic-fact guard that keeps Roslyn-resolved overload calls pinned to the exact compiler target.
  • Tests for directive-wrapped interface members, same-arity overload fan-out, and semantic-fact suppression.
  • Editable package version update in uv.lock.

Confidence Score: 5/5

Safe to merge with low risk.

The changes are narrowly scoped to C# parse recovery and call resolution. The semantic-fact guard preserves exact Roslyn overload targets. Focused tests cover the described failure cases.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex ran the requested verification for the pull request.
  • During validation, it was observed that local artifact references were not uploaded.

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
codebase_rag/parsers/call_processor.py Adds C# same-arity overload family CALLS fan-out for heuristic bare-call resolution while preserving semantic-fact exact targets.
codebase_rag/parsers/cpp/preproc_recovery.py Adds C# conditional-directive parse recovery that blanks directive lines and skipped branches only when retry reduces error nodes.
codebase_rag/parsers/csharp/type_inference.py Refactors C# type-inference helpers and exposes semantic-fact and same-arity family queries used by call processing.
codebase_rag/tests/test_csharp_calls.py Adds tests proving same-arity overload siblings all receive CALLS edges under syntax-only resolution.
codebase_rag/tests/test_csharp_preproc_split_body.py Adds tests for directive-wrapped default interface bodies avoiding phantom functions and preserving methods.
codebase_rag/tests/test_csharp_semantic_facts.py Adds tests that Roslyn semantic call facts suppress same-arity overload fan-out.
uv.lock Updates the editable package version from 0.0.373 to 0.0.374.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Parser as Tree-sitter parser
participant Recovery as preproc_recovery
participant Resolver as CSharpTypeInferenceEngine
participant Calls as CallProcessor

Parser->>Recovery: "parse C# source"
alt "parse has errors and source contains #if"
    Recovery->>Parser: retry with directives blanked, first branch kept
    Recovery-->>Parser: use retry only if error-node count shrinks
end
Calls->>Resolver: resolve_csharp_method_call(call)
alt semantic fact pinned call site
    Resolver-->>Calls: exact compiler target only
else heuristic bare-call target
    Calls->>Resolver: csharp_same_arity_family(target)
    Resolver-->>Calls: sibling overload QNs
    Calls->>Calls: emit CALLS to target family
end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Parser as Tree-sitter parser
participant Recovery as preproc_recovery
participant Resolver as CSharpTypeInferenceEngine
participant Calls as CallProcessor

Parser->>Recovery: "parse C# source"
alt "parse has errors and source contains #if"
    Recovery->>Parser: retry with directives blanked, first branch kept
    Recovery-->>Parser: use retry only if error-node count shrinks
end
Calls->>Resolver: resolve_csharp_method_call(call)
alt semantic fact pinned call site
    Resolver-->>Calls: exact compiler target only
else heuristic bare-call target
    Calls->>Resolver: csharp_same_arity_family(target)
    Resolver-->>Calls: sibling overload QNs
    Calls->>Calls: emit CALLS to target family
end
Loading

Reviews (5): Last reviewed commit: "Merge origin/main into fix/csharp-serilo..." | Re-trigger Greptile

@vitali87

Copy link
Copy Markdown
Owner Author

@greptile review

@vitali87

Copy link
Copy Markdown
Owner Author

@greptile review

Comment thread codebase_rag/parsers/call_processor.py Outdated
@vitali87

Copy link
Copy Markdown
Owner Author

@greptile review

@vitali87

Copy link
Copy Markdown
Owner Author

@greptile review

@sonarqubecloud

Copy link
Copy Markdown

@vitali87
vitali87 merged commit f1a9283 into main Jul 18, 2026
23 checks passed
@vitali87
vitali87 deleted the fix/csharp-serilog-dogfood branch July 18, 2026 14:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant