Skip to content

Commit e0ea426

Browse files
Merge pull request #69523 from CyrusNajmabadi/forkingFixer
Move 'use object expression' fixer over to helper base class
2 parents e433924 + 6155bf3 commit e0ea426

1 file changed

Lines changed: 29 additions & 69 deletions

File tree

src/Analyzers/Core/CodeFixes/UseObjectInitializer/AbstractUseObjectInitializerCodeFixProvider.cs

Lines changed: 29 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
using System;
6-
using System.Collections.Generic;
75
using System.Collections.Immutable;
8-
using System.Linq;
96
using System.Threading;
107
using System.Threading.Tasks;
118
using Microsoft.CodeAnalysis.CodeActions;
@@ -27,7 +24,7 @@ internal abstract class AbstractUseObjectInitializerCodeFixProvider<
2724
TMemberAccessExpressionSyntax,
2825
TAssignmentStatementSyntax,
2926
TVariableDeclaratorSyntax>
30-
: SyntaxEditorBasedCodeFixProvider
27+
: ForkingSyntaxEditorBasedCodeFixProvider<TObjectCreationExpressionSyntax>
3128
where TSyntaxKind : struct
3229
where TExpressionSyntax : SyntaxNode
3330
where TStatementSyntax : SyntaxNode
@@ -36,83 +33,46 @@ internal abstract class AbstractUseObjectInitializerCodeFixProvider<
3633
where TAssignmentStatementSyntax : TStatementSyntax
3734
where TVariableDeclaratorSyntax : SyntaxNode
3835
{
39-
public override ImmutableArray<string> FixableDiagnosticIds
40-
=> ImmutableArray.Create(IDEDiagnosticIds.UseObjectInitializerDiagnosticId);
41-
42-
protected override bool IncludeDiagnosticDuringFixAll(Diagnostic diagnostic)
43-
=> !diagnostic.Descriptor.ImmutableCustomTags().Contains(WellKnownDiagnosticTags.Unnecessary);
44-
45-
public override Task RegisterCodeFixesAsync(CodeFixContext context)
36+
protected AbstractUseObjectInitializerCodeFixProvider()
37+
: base(AnalyzersResources.Object_initialization_can_be_simplified,
38+
nameof(AnalyzersResources.Object_initialization_can_be_simplified))
4639
{
47-
RegisterCodeFix(context, AnalyzersResources.Object_initialization_can_be_simplified, nameof(AnalyzersResources.Object_initialization_can_be_simplified));
48-
return Task.CompletedTask;
4940
}
5041

51-
protected override async Task FixAllAsync(
52-
Document document, ImmutableArray<Diagnostic> diagnostics,
53-
SyntaxEditor editor, CodeActionOptionsProvider fallbackOptions, CancellationToken cancellationToken)
54-
{
55-
// Fix-All for this feature is somewhat complicated. As Object-Initializers
56-
// could be arbitrarily nested, we have to make sure that any edits we make
57-
// to one Object-Initializer are seen by any higher ones. In order to do this
58-
// we actually process each object-creation-node, one at a time, rewriting
59-
// the tree for each node. In order to do this effectively, we use the '.TrackNodes'
60-
// feature to keep track of all the object creation nodes as we make edits to
61-
// the tree. If we didn't do this, then we wouldn't be able to find the
62-
// second object-creation-node after we make the edit for the first one.
63-
var syntaxFacts = document.GetLanguageService<ISyntaxFactsService>();
64-
65-
var originalRoot = editor.OriginalRoot;
66-
var originalObjectCreationNodes = new Stack<TObjectCreationExpressionSyntax>();
67-
foreach (var diagnostic in diagnostics)
68-
{
69-
var objectCreation = (TObjectCreationExpressionSyntax)originalRoot.FindNode(
70-
diagnostic.AdditionalLocations[0].SourceSpan, getInnermostNodeForTie: true);
71-
originalObjectCreationNodes.Push(objectCreation);
72-
}
42+
protected abstract TStatementSyntax GetNewStatement(
43+
TStatementSyntax statement, TObjectCreationExpressionSyntax objectCreation,
44+
ImmutableArray<Match<TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>> matches);
7345

74-
// We're going to be continually editing this tree. Track all the nodes we
75-
// care about so we can find them across each edit.
76-
document = document.WithSyntaxRoot(originalRoot.TrackNodes(originalObjectCreationNodes));
46+
public override ImmutableArray<string> FixableDiagnosticIds
47+
=> ImmutableArray.Create(IDEDiagnosticIds.UseObjectInitializerDiagnosticId);
7748

49+
protected override async Task FixAsync(
50+
Document document,
51+
SyntaxEditor editor,
52+
CodeActionOptionsProvider fallbackOptions,
53+
TObjectCreationExpressionSyntax objectCreation,
54+
ImmutableDictionary<string, string?> properties,
55+
CancellationToken cancellationToken)
56+
{
57+
var syntaxFacts = document.GetRequiredLanguageService<ISyntaxFactsService>();
7858
var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
7959
var currentRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
8060

81-
while (originalObjectCreationNodes.Count > 0)
82-
{
83-
var originalObjectCreation = originalObjectCreationNodes.Pop();
84-
var objectCreation = currentRoot.GetCurrentNodes(originalObjectCreation).Single();
85-
86-
var matches = UseNamedMemberInitializerAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>.Analyze(
87-
semanticModel, syntaxFacts, objectCreation, cancellationToken);
88-
89-
if (matches.IsDefaultOrEmpty)
90-
continue;
91-
92-
var statement = objectCreation.FirstAncestorOrSelf<TStatementSyntax>();
93-
Contract.ThrowIfNull(statement);
61+
var matches = UseNamedMemberInitializerAnalyzer<TExpressionSyntax, TStatementSyntax, TObjectCreationExpressionSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax, TVariableDeclaratorSyntax>.Analyze(
62+
semanticModel, syntaxFacts, objectCreation, cancellationToken);
9463

95-
var newStatement = GetNewStatement(statement, objectCreation, matches)
96-
.WithAdditionalAnnotations(Formatter.Annotation);
64+
if (matches.IsDefaultOrEmpty)
65+
return;
9766

98-
var subEditor = new SyntaxEditor(currentRoot, document.Project.Solution.Services);
67+
var statement = objectCreation.FirstAncestorOrSelf<TStatementSyntax>();
68+
Contract.ThrowIfNull(statement);
9969

100-
subEditor.ReplaceNode(statement, newStatement);
101-
foreach (var match in matches)
102-
{
103-
subEditor.RemoveNode(match.Statement, SyntaxRemoveOptions.KeepUnbalancedDirectives);
104-
}
70+
var newStatement = GetNewStatement(statement, objectCreation, matches)
71+
.WithAdditionalAnnotations(Formatter.Annotation);
10572

106-
document = document.WithSyntaxRoot(subEditor.GetChangedRoot());
107-
semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
108-
currentRoot = await document.GetRequiredSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
109-
}
110-
111-
editor.ReplaceNode(editor.OriginalRoot, currentRoot);
73+
editor.ReplaceNode(statement, newStatement);
74+
foreach (var match in matches)
75+
editor.RemoveNode(match.Statement, SyntaxRemoveOptions.KeepUnbalancedDirectives);
11276
}
113-
114-
protected abstract TStatementSyntax GetNewStatement(
115-
TStatementSyntax statement, TObjectCreationExpressionSyntax objectCreation,
116-
ImmutableArray<Match<TExpressionSyntax, TStatementSyntax, TMemberAccessExpressionSyntax, TAssignmentStatementSyntax>> matches);
11777
}
11878
}

0 commit comments

Comments
 (0)