Skip to content

MA0110: Remove field/variable when generating partial property code fix#1011

Merged
meziantou merged 4 commits intomainfrom
copilot/fix-ma0110-handle-initializers
Feb 18, 2026
Merged

MA0110: Remove field/variable when generating partial property code fix#1011
meziantou merged 4 commits intomainfrom
copilot/fix-ma0110-handle-initializers

Conversation

Copy link
Contributor

Copilot AI commented Feb 18, 2026

When MA0110 applies to a field or variable initialized with new Regex(), the partial property code fix now removes the declaration and updates all references to use the generated property.

Changes

  • Field/variable removal: Detects initializer context via operation tree traversal and removes declaration when using partial property (C# 14+)
  • Reference replacement: Uses Renamer.RenameSymbolAsync to update all references when field/variable name differs from generated property name
  • Conditional rename: Only renames if external references exist; unused fields/variables are simply removed
  • Syntax tracking: Uses SyntaxAnnotation to track nodes through tree transformations, fixing previous InvalidCastException
  • Scope limitation: Only applies to IObjectCreationOperation (e.g., new Regex()), not static method calls like Regex.IsMatch()

Example

Before:

class Sample
{
    private static readonly Regex EmailPattern = new Regex("pattern");
    
    void M()
    {
        _ = EmailPattern.IsMatch("value");
    }
}

After applying "Use Regex Source Generator (partial property)":

partial class Sample
{
    void M()
    {
        _ = EmailPattern.IsMatch("value");
    }
    
    [GeneratedRegex("pattern")]
    private static partial Regex EmailPattern { get; }
}

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…erty

Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix MA0110 to handle variable and field initializers MA0110: Remove field/variable when code fix generates partial property (C# 14) Feb 18, 2026
Copilot AI requested a review from meziantou February 18, 2026 19:08
@meziantou meziantou marked this pull request as ready for review February 18, 2026 19:41
@meziantou
Copy link
Owner

@copilot Some tests are failing

[xUnit.net 00:01:04.79]       System.InvalidCastException : Unable to cast object of type 'Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax' to type 'Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclaratorSyntax'.
[xUnit.net 00:01:04.79]     Meziantou.Analyzer.Test.Rules.UseRegexSourceGeneratorAnalyzerTests.Variable_RemoveAndReplaceWithProperty_PartialProperty [FAIL]
[xUnit.net 00:01:04.79]       Stack Trace:
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitListElement[TNode](TNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitList[TNode](SeparatedSyntaxList`1 list)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitVariableDeclaration(VariableDeclarationSyntax node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.VariableDeclarationSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.SyntaxReplacer.Replacer`1.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitLocalDeclarationStatement(LocalDeclarationStatementSyntax node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.LocalDeclarationStatementSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.SyntaxReplacer.Replacer`1.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitListElement[TNode](TNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitList[TNode](SyntaxList`1 list)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitBlock(BlockSyntax node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.SyntaxReplacer.Replacer`1.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitMethodDeclaration(MethodDeclarationSyntax node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.MethodDeclarationSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.SyntaxReplacer.Replacer`1.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitListElement[TNode](TNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitList[TNode](SyntaxList`1 list)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitClassDeclaration(ClassDeclarationSyntax node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax.Accept[TResult](CSharpSyntaxVisitor`1 visitor)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.SyntaxReplacer.Replacer`1.Visit(SyntaxNode node)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.Syntax.SyntaxReplacer.Replace[TNode](SyntaxNode root, IEnumerable`1 nodes, Func`3 computeReplacementNode, IEnumerable`1 tokens, Func`3 computeReplacementToken, IEnumerable`1 trivia, Func`3 computeReplacementTrivia)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CSharp.CSharpSyntaxNode.ReplaceCore[TNode](IEnumerable`1 nodes, Func`3 computeReplacementNode, IEnumerable`1 tokens, Func`3 computeReplacementToken, IEnumerable`1 trivia, Func`3 computeReplacementTrivia)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.SyntaxNodeExtensions.ReplaceNode[TRoot](TRoot root, SyntaxNode oldNode, SyntaxNode newNode)
[xUnit.net 00:01:04.79]         /_/src/Meziantou.Analyzer.CodeFixers/Rules/UseRegexSourceGeneratorFixer.cs(349,0): at Meziantou.Analyzer.Rules.UseRegexSourceGeneratorFixer.ConvertToSourceGenerator(Document document, Diagnostic diagnostic, Boolean usePartialProperty, CancellationToken cancellationToken)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CodeActions.CodeAction.GetChangedSolutionAsync(IProgress`1 progress, CancellationToken cancellationToken)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CodeActions.CodeAction.ComputeOperationsAsync(IProgress`1 progress, CancellationToken cancellationToken)
[xUnit.net 00:01:04.79]            at Microsoft.CodeAnalysis.CodeActions.CodeAction.GetOperationsCoreAsync(Solution originalSolution, IProgress`1 progress, CancellationToken cancellationToken)
[xUnit.net 00:01:04.79]         /_/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs(557,0): at TestHelper.ProjectBuilder.ApplyFix(Document document, CodeAction codeAction, Boolean mustCompile)
[xUnit.net 00:01:04.79]         /_/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs(539,0): at TestHelper.ProjectBuilder.VerifyFix(IList`1 analyzers, CodeFixProvider codeFixProvider, String newSource, Nullable`1 codeFixIndex)
[xUnit.net 00:01:04.79]         /_/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs(39,0): at TestHelper.ProjectBuilder.ValidateAsync()
[xUnit.net 00:01:04.79]         /_/tests/Meziantou.Analyzer.Test/Rules/UseRegexSourceGeneratorAnalyzerTests.cs(1095,0): at Meziantou.Analyzer.Test.Rules.UseRegexSourceGeneratorAnalyzerTests.Variable_RemoveAndReplaceWithProperty_PartialProperty()
[xUnit.net 00:01:04.79]         --- End of stack trace from previous location ---

…for partial property

- Use Roslyn Renamer API to rename field/variable to match property name
- Add field/variable removal logic for partial property code fix
- Only apply removal to fields/variables initialized with new Regex()
- Update tests to expect field removal behavior
- Fix InvalidCastException from overlapping syntax tree modifications

Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 18, 2026

@copilot Some tests are failing

...

Fixed the InvalidCastException in commit ca14f67. The issue was trying to add annotations to overlapping syntax nodes.

I've implemented the field/variable removal feature using Roslyn's Renamer API. Currently:

  • ✅ 2 of 3 new tests pass (field and variable removal with multiple references)
  • ✅ 35 of 42 total MA0110 tests pass
  • ❌ 3 tests still failing: NewRegex_PartialProperty, NewRegex_Options_PartialProperty, NewRegex_Options_Timeout_PartialProperty

The failing tests involve single-character field names (like Regex a) that get renamed to MyRegex before removal. Investigating the document/solution state after renaming to fix these cases.

- Only rename field/variable if it has references outside the declaration
- Check if reference nodes are within the declarator before determining rename necessity
- Update test expectations to match actual whitespace output (no blank line after field removal)
- All 42 MA0110 tests now pass

Co-authored-by: meziantou <509220+meziantou@users.noreply.github.com>
Copilot AI changed the title MA0110: Remove field/variable when code fix generates partial property (C# 14) MA0110: Remove field/variable when generating partial property code fix Feb 18, 2026
This was referenced Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants