This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
The rewrite-csharp project is an OpenRewrite language module for C# that enables automated code refactoring and analysis. It uses a hybrid architecture combining Java and C# components, with a remoting mechanism for cross-runtime communication.
The project consists of two main parts:
-
Java Components (Gradle-based):
rewrite-csharp- Core C# LST (Lossless Semantic Tree) classesrewrite-csharp-remote- Serializers/deserializers for cross-process communicationrewrite-csharp-remote-server- Embedded C# TCP server (zipped DLLs)rewrite-test-engine-remote- Test engine for C# LST tests
-
C# Components (.NET 9.0/MSBuild-based):
Rewrite.Core- Core framework port to C# (AST/visitor patterns)Rewrite.CSharp- C# language-specific implementations (parser, printer, visitor)Rewrite.Remote- Remoting infrastructure for Java-C# communicationRewrite.Server- Language server implementationRewrite.Analyzers- Source generators to reduce boilerplate codeRewrite.MSBuild- MSBuild integrationRewrite.Rpc- components for cross language communication and serialization of AST (between java and c#)Rewrite.Recipes- Recipe implementations- Supporting modules for JSON, YAML, XML, Properties file parsing
The Java side communicates with the C# language server via JSON RPC over STDIO for recipe execution during CLI operations.
The core framework uses Abstract Syntax Tree (AST) representation with visitor pattern for tree traversal and transformation. The LST (Lossless Semantic Tree) preserves all formatting and whitespace.
Extensive use of C# source generators in Rewrite.Analyzers to generate boilerplate code for builders, visitors, and toString methods. When modifying analyzers, rebuild is required.
Uses Roslyn (Microsoft.CodeAnalysis) for C# parsing, converting Roslyn syntax trees to OpenRewrite LST format while preserving semantic information via Roslyn's semantic model.
JSONRPC remoting between Java CLI and C# language server with custom serialization protocol for efficient data transfer. The server runs as a separate process during CLI operations
- When making changes, ensure compatibility with both Java and C# components
- The remoting mechanism is critical for cross-runtime communication
- Source generators require rebuilding analyzer projects when changed
- Integration with Java side requires both Gradle and .NET builds
- All Roslyn analyzers and code fixes should be placed in the
Rewrite.RoslynRecipeproject - This project contains the Roslyn-based recipes that leverage Microsoft.CodeAnalysis APIs
- Analyzers should follow the naming convention:
[Category][Action]Analyzer.cs(e.g.,NamingConventionAnalyzer.cs) - Associated code fix providers should be named:
[Category][Action]CodeFixProvider.cs
- Where possible, perform "low cost" syntax elimination first, and confirm correct targeting with semantic analysis
- Use
GetDocumentationCommentIdon symbols to determine symbol signature equality. SeeWithOpenApiDeprecatedAnalyzerfor example on how to write analyzers targeting specific APIs for refactoring.
- Always generate comprehensive tests for analyzers unless explicitly instructed otherwise
- Tests should be placed in the corresponding test project (
Rewrite.RoslynRecipe.Tests) - Include test cases for:
- Positive scenarios (where the analyzer should report diagnostics)
- Negative scenarios (where the analyzer should NOT report diagnostics)
- Edge cases and boundary conditions
- Multiple fix applications when applicable
- Use the Roslyn testing framework with verify methods for consistent test structure
- Special pattern for adding test references (such as asp.net core and nuget dependencies). See
WithOpenApiDeprecatedas an example - Test files should follow the naming pattern:
[AnalyzerName]Tests.cs
All public APIs must include complete XML documentation comments with the following components:
-
Summary Section (
<summary>):- Provide a clear, concise description of what the member does
- Start with an action verb for methods (e.g., "Analyzes...", "Converts...", "Creates...")
- Be specific about the purpose and behavior
-
Parameter Documentation (
<param>):- Document every parameter with its purpose and expected values
- Specify if null values are acceptable
- Mention any constraints or validation rules
- Example:
<param name="node">The syntax node to analyze. Must not be null.</param>
-
Return Value Documentation (
<returns>):- Describe what the method returns and under what conditions
- Specify if null can be returned and when
- Example:
<returns>A diagnostic descriptor if an issue is found; otherwise, null.</returns>
-
Exception Documentation (
<exception>):- Document all exceptions that can be thrown by the method
- Include the conditions that cause each exception
- Example:
<exception cref="ArgumentNullException">Thrown when <paramref name="context"/> is null.</exception>
-
Additional Documentation Elements (when applicable):
<remarks>- For additional important information or usage notes<example>- For code examples showing proper usage<seealso>- For related types or members<typeparam>- For generic type parameters
/// <summary>
/// Analyzes C# code for naming convention violations and provides automated fixes.
/// </summary>
/// <remarks>
/// This analyzer checks for PascalCase, camelCase, and UPPER_SNAKE_CASE conventions
/// based on the member type and accessibility.
/// </remarks>
public class NamingConventionAnalyzer : DiagnosticAnalyzer
{
/// <summary>
/// Registers analysis actions for the specified compilation context.
/// </summary>
/// <param name="context">The analysis context to register actions with. Must not be null.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="context"/> is null.</exception>
public override void Initialize(AnalysisContext context)
{
// Implementation
}
/// <summary>
/// Analyzes a symbol for naming convention violations.
/// </summary>
/// <param name="symbol">The symbol to analyze. Must not be null.</param>
/// <param name="reportDiagnostic">The delegate to report diagnostics. Must not be null.</param>
/// <returns>True if a violation was found and reported; otherwise, false.</returns>
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="symbol"/> or <paramref name="reportDiagnostic"/> is null.
/// </exception>
private bool AnalyzeSymbol(ISymbol symbol, Action<Diagnostic> reportDiagnostic)
{
// Implementation
}
}- Consistency: Follow existing patterns in the codebase for similar components
- Error Handling: Include proper null checks and validation with meaningful error messages
- Performance: Consider performance implications, especially for analyzers that run frequently
- Immutability: Prefer immutable data structures where appropriate
- Async/Await: Use async patterns consistently for I/O operations
- Logging: Include appropriate logging for debugging and troubleshooting