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 ;
75using System . Collections . Immutable ;
8- using System . Linq ;
96using System . Threading ;
107using System . Threading . Tasks ;
118using 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