@@ -82,6 +82,35 @@ internal MemoryOutputDiffGenerator(
82
82
_endOfLineTrivia = Environment . NewLine == "\r \n " ? SyntaxFactory . CarriageReturnLineFeed : SyntaxFactory . LineFeed ;
83
83
}
84
84
85
+ private async Task < ( SyntaxNode rootNode , SemanticModel model ) > GetAssemblyRootNodeAndModelAsync ( IAssemblySymbolLoader loader , IAssemblySymbol assemblySymbol )
86
+ {
87
+ CSharpAssemblyDocumentGeneratorOptions options = new ( loader , _symbolFilter , _attributeSymbolFilter )
88
+ {
89
+ HideImplicitDefaultConstructors = _hideImplicitDefaultConstructors ,
90
+ ShouldFormat = true ,
91
+ ShouldReduce = false ,
92
+ MetadataReferences = loader . MetadataReferences ,
93
+ DiagnosticOptions = _diagnosticOptions ,
94
+ SyntaxRewriters = [
95
+ new TypeDeclarationCSharpSyntaxRewriter ( _addPartialModifier ) , // This must be visited BEFORE GlobalPrefixRemover as it depends on the 'global::' prefix to be found
96
+ GlobalPrefixRemover . Singleton , // And then call this ASAP afterwards so there are fewer identifiers to visit
97
+ PrimitiveSimplificationRewriter . Singleton ,
98
+ RemoveBodyCSharpSyntaxRewriter . Singleton ,
99
+ AttributeNameSuffixRemover . Singleton ,
100
+ SingleLineStatementCSharpSyntaxRewriter . Singleton ,
101
+ ] ,
102
+ AdditionalAnnotations = [ Formatter . Annotation ] // Formatter is needed to fix some spacing
103
+ } ;
104
+
105
+ CSharpAssemblyDocumentGenerator docGenerator = new ( _log , options ) ;
106
+
107
+ Document document = await docGenerator . GetDocumentForAssemblyAsync ( assemblySymbol ) . ConfigureAwait ( false ) ; // Super hot and resource-intensive path
108
+ SyntaxNode root = await document . GetSyntaxRootAsync ( ) . ConfigureAwait ( false ) ?? throw new InvalidOperationException ( string . Format ( Resources . RootNodeNotFound , assemblySymbol . Name ) ) ;
109
+ SemanticModel model = await document . GetSemanticModelAsync ( ) . ConfigureAwait ( false ) ?? throw new InvalidOperationException ( string . Format ( Resources . SemanticModelNotFound , assemblySymbol . Name ) ) ;
110
+
111
+ return ( root , model ) ;
112
+ }
113
+
85
114
/// <inheritdoc/>
86
115
public IReadOnlyDictionary < string , string > Results => _results . AsReadOnly ( ) ;
87
116
@@ -174,35 +203,6 @@ public async Task RunAsync()
174
203
swRun . Stop ( ) ;
175
204
}
176
205
177
- private async Task < ( SyntaxNode rootNode , SemanticModel model ) > GetAssemblyRootNodeAndModelAsync ( IAssemblySymbolLoader loader , IAssemblySymbol assemblySymbol )
178
- {
179
- CSharpAssemblyDocumentGeneratorOptions options = new ( loader , _symbolFilter , _attributeSymbolFilter )
180
- {
181
- HideImplicitDefaultConstructors = _hideImplicitDefaultConstructors ,
182
- ShouldFormat = false ,
183
- ShouldReduce = false ,
184
- MetadataReferences = loader . MetadataReferences ,
185
- DiagnosticOptions = _diagnosticOptions ,
186
- SyntaxRewriters = [
187
- new TypeDeclarationCSharpSyntaxRewriter ( _addPartialModifier ) , // This must be visited BEFORE GlobalPrefixRemover as it depends on the 'global::' prefix to be found
188
- GlobalPrefixRemover . Singleton , // And then call this ASAP afterwards so there are fewer identifiers to visit
189
- PrimitiveSimplificationRewriter . Singleton ,
190
- RemoveBodyCSharpSyntaxRewriter . Singleton ,
191
- AttributeNameSuffixRemover . Singleton ,
192
- SingleLineStatementCSharpSyntaxRewriter . Singleton ,
193
- ] ,
194
- AdditionalAnnotations = [ Formatter . Annotation ] // Formatter is needed to fix some spacing
195
- } ;
196
-
197
- CSharpAssemblyDocumentGenerator docGenerator = new ( _log , options ) ;
198
-
199
- Document document = await docGenerator . GetDocumentForAssemblyAsync ( assemblySymbol ) . ConfigureAwait ( false ) ; // Super hot and resource-intensive path
200
- SyntaxNode root = await document . GetSyntaxRootAsync ( ) . ConfigureAwait ( false ) ?? throw new InvalidOperationException ( string . Format ( Resources . RootNodeNotFound , assemblySymbol . Name ) ) ;
201
- SemanticModel model = await document . GetSemanticModelAsync ( ) . ConfigureAwait ( false ) ?? throw new InvalidOperationException ( string . Format ( Resources . SemanticModelNotFound , assemblySymbol . Name ) ) ;
202
-
203
- return ( root , model ) ;
204
- }
205
-
206
206
private static string GetFinalAssemblyDiff ( string assemblyName , string diffText )
207
207
{
208
208
StringBuilder sbAssembly = new ( ) ;
@@ -319,7 +319,15 @@ private static ConcurrentDictionary<string, MemberDeclarationSyntax> CollectChil
319
319
320
320
ConcurrentDictionary < string , MemberDeclarationSyntax > dictionary = [ ] ;
321
321
322
- if ( parentNode is BaseNamespaceDeclarationSyntax )
322
+ if ( parentNode is RecordDeclarationSyntax record && record . Members . Any ( ) )
323
+ {
324
+ foreach ( MemberDeclarationSyntax memberNode in record . ChildNodes ( ) . Where ( n => n is MemberDeclarationSyntax m && IsPublicOrProtectedOrDestructor ( m ) ) . Cast < MemberDeclarationSyntax > ( ) )
325
+ {
326
+ // Note that these could also be nested types
327
+ dictionary . TryAdd ( GetDocId ( memberNode , model ) , memberNode ) ;
328
+ }
329
+ }
330
+ else if ( parentNode is BaseNamespaceDeclarationSyntax )
323
331
{
324
332
foreach ( BaseTypeDeclarationSyntax typeNode in parentNode . ChildNodes ( ) . Where ( n => n is BaseTypeDeclarationSyntax t && IsPublicOrProtectedOrDestructor ( t ) ) . Cast < BaseTypeDeclarationSyntax > ( ) )
325
333
{
@@ -555,7 +563,7 @@ private string GetCodeWrappedByParent(string diffedChildrenCode, SyntaxNode pare
555
563
private static SyntaxNode GetChildlessNode ( MemberDeclarationSyntax node )
556
564
{
557
565
SyntaxNode childlessNode = node . RemoveNodes ( node . ChildNodes ( ) . Where (
558
- c => c is MemberDeclarationSyntax or BaseTypeDeclarationSyntax or DelegateDeclarationSyntax ) , SyntaxRemoveOptions . KeepNoTrivia ) ! ;
566
+ c => c is MemberDeclarationSyntax or BaseTypeDeclarationSyntax or DelegateDeclarationSyntax ) , SyntaxRemoveOptions . KeepNoTrivia ) ! ;
559
567
560
568
return childlessNode . WithLeadingTrivia ( node . GetLeadingTrivia ( ) ) ;
561
569
}
@@ -568,6 +576,7 @@ private string GetDeclarationAndOpeningBraceCode(SyntaxNode childlessNode, Synta
568
576
569
577
SyntaxNode unclosedNode = childlessNode switch
570
578
{
579
+ RecordDeclarationSyntax recordDecl => recordDecl . OpenBraceToken . IsMissing ? recordDecl : recordDecl . WithCloseBraceToken ( _missingCloseBrace ) ,
571
580
BaseTypeDeclarationSyntax typeDecl => typeDecl . WithOpenBraceToken ( openBrace )
572
581
. WithCloseBraceToken ( _missingCloseBrace ) ,
573
582
@@ -584,6 +593,7 @@ private string GetClosingBraceCode(SyntaxNode childlessNode, SyntaxTriviaList le
584
593
{
585
594
SyntaxToken closeBrace = childlessNode switch
586
595
{
596
+ RecordDeclarationSyntax recordDecl => recordDecl . CloseBraceToken . IsMissing ? _missingCloseBrace : recordDecl . CloseBraceToken ,
587
597
BaseTypeDeclarationSyntax typeDecl => typeDecl . CloseBraceToken ,
588
598
NamespaceDeclarationSyntax nsDecl => nsDecl . CloseBraceToken ,
589
599
_ => throw new InvalidOperationException ( string . Format ( Resources . UnexpectedNodeType , childlessNode . Kind ( ) ) )
0 commit comments