13
13
using Microsoft . CodeAnalysis . CodeActions ;
14
14
using Microsoft . CodeAnalysis . CodeFixes ;
15
15
using Microsoft . CodeAnalysis . CSharp . Syntax ;
16
+ using Microsoft . CodeAnalysis . Editing ;
16
17
using Microsoft . CodeAnalysis . Text ;
17
18
using static CommunityToolkit . Mvvm . SourceGenerators . Diagnostics . DiagnosticDescriptors ;
18
19
using static Microsoft . CodeAnalysis . CSharp . SyntaxFactory ;
@@ -63,7 +64,7 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
63
64
context . RegisterCodeFix (
64
65
CodeAction . Create (
65
66
title : "Inherit from ObservableObject" ,
66
- createChangedDocument : token => UpdateReference ( context . Document , classDeclaration , attributeTypeName , token ) ,
67
+ createChangedDocument : token => UpdateReference ( context . Document , root , classDeclaration , attributeTypeName ) ,
67
68
equivalenceKey : "Inherit from ObservableObject" ) ,
68
69
diagnostic ) ;
69
70
@@ -76,21 +77,16 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
76
77
/// Applies the code fix to a target class declaration and returns an updated document.
77
78
/// </summary>
78
79
/// <param name="document">The original document being fixed.</param>
80
+ /// <param name="root">The original tree root belonging to the current document.</param>
79
81
/// <param name="classDeclaration">The <see cref="ClassDeclarationSyntax"/> to update.</param>
80
82
/// <param name="attributeTypeName">The name of the attribute that should be removed.</param>
81
- /// <param name="cancellationToken">The cancellation token for the operation.</param>
82
83
/// <returns>An updated document with the applied code fix, and <paramref name="classDeclaration"/> inheriting from <c>ObservableObject</c>.</returns>
83
- private static async Task < Document > UpdateReference ( Document document , ClassDeclarationSyntax classDeclaration , string attributeTypeName , CancellationToken cancellationToken )
84
+ private static Task < Document > UpdateReference ( Document document , SyntaxNode root , ClassDeclarationSyntax classDeclaration , string attributeTypeName )
84
85
{
85
86
// Insert ObservableObject always in first position in the base list. The type might have
86
87
// some interfaces in the base list, so we just copy them back after ObservableObject.
87
- ClassDeclarationSyntax updatedClassDeclaration =
88
- classDeclaration . WithBaseList ( BaseList ( SingletonSeparatedList (
89
- ( BaseTypeSyntax ) SimpleBaseType ( IdentifierName ( "ObservableObject" ) ) ) )
90
- . AddTypes ( classDeclaration . BaseList ? . Types . ToArray ( ) ?? Array . Empty < BaseTypeSyntax > ( ) ) ) ;
91
-
92
- AttributeListSyntax ? targetAttributeList = null ;
93
- AttributeSyntax ? targetAttribute = null ;
88
+ SyntaxGenerator generator = SyntaxGenerator . GetGenerator ( document ) ;
89
+ ClassDeclarationSyntax updatedClassDeclaration = ( ClassDeclarationSyntax ) generator . AddBaseType ( classDeclaration , IdentifierName ( "ObservableObject" ) ) ;
94
90
95
91
// Find the attribute list and attribute to remove
96
92
foreach ( AttributeListSyntax attributeList in updatedClassDeclaration . AttributeLists )
@@ -101,35 +97,13 @@ private static async Task<Document> UpdateReference(Document document, ClassDecl
101
97
( identifierName == attributeTypeName || ( identifierName + "Attribute" ) == attributeTypeName ) )
102
98
{
103
99
// We found the attribute to remove and the list to update
104
- targetAttributeList = attributeList ;
105
- targetAttribute = attribute ;
100
+ updatedClassDeclaration = ( ClassDeclarationSyntax ) generator . RemoveNode ( updatedClassDeclaration , attribute ) ;
106
101
107
102
break ;
108
103
}
109
104
}
110
105
}
111
106
112
- // If we found an attribute to remove, do that
113
- if ( targetAttribute is not null )
114
- {
115
- // If the target list has more than one attribute, keep it and just remove the target one
116
- if ( targetAttributeList ! . Attributes . Count > 1 )
117
- {
118
- updatedClassDeclaration =
119
- updatedClassDeclaration . ReplaceNode (
120
- targetAttributeList ,
121
- targetAttributeList . RemoveNode ( targetAttribute , SyntaxRemoveOptions . KeepNoTrivia ) ! ) ;
122
- }
123
- else
124
- {
125
- // Otherwise, remove the entire attribute list
126
- updatedClassDeclaration = updatedClassDeclaration . RemoveNode ( targetAttributeList , SyntaxRemoveOptions . KeepExteriorTrivia ) ! ;
127
- }
128
- }
129
-
130
- SyntaxNode originalRoot = await classDeclaration . SyntaxTree . GetRootAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
131
- SyntaxTree updatedTree = originalRoot . ReplaceNode ( classDeclaration , updatedClassDeclaration ) . SyntaxTree ;
132
-
133
- return document . WithSyntaxRoot ( await updatedTree . GetRootAsync ( cancellationToken ) . ConfigureAwait ( false ) ) ;
107
+ return Task . FromResult ( document . WithSyntaxRoot ( root . ReplaceNode ( classDeclaration , updatedClassDeclaration ) ) ) ;
134
108
}
135
109
}
0 commit comments