1111using Microsoft . CodeAnalysis ;
1212using Microsoft . CodeAnalysis . CSharp ;
1313using Microsoft . CodeAnalysis . CSharp . Syntax ;
14- using static CommunityToolkit . Mvvm . SourceGenerators . Diagnostics . DiagnosticDescriptors ;
1514
1615namespace CommunityToolkit . Mvvm . SourceGenerators ;
1716
@@ -70,46 +69,40 @@ private protected TransitiveMembersGenerator(string attributeType, IEqualityComp
7069 /// <inheritdoc/>
7170 public void Initialize ( IncrementalGeneratorInitializationContext context )
7271 {
73- // Get all class declarations
74- IncrementalValuesProvider < INamedTypeSymbol > typeSymbols =
72+ // Gather all generation info, and any diagnostics
73+ IncrementalValuesProvider < Result < ( HierarchyInfo Hierarchy , bool IsSealed , TInfo ? Info ) > > generationInfoWithErrors =
7574 context . SyntaxProvider
7675 . CreateSyntaxProvider (
7776 static ( node , _ ) => node is ClassDeclarationSyntax { AttributeLists . Count : > 0 } ,
78- static ( context , _ ) =>
77+ ( context , token ) =>
7978 {
8079 if ( ! context . SemanticModel . Compilation . HasLanguageVersionAtLeastEqualTo ( LanguageVersion . CSharp8 ) )
8180 {
8281 return default ;
8382 }
8483
85- return ( INamedTypeSymbol ) context . SemanticModel . GetDeclaredSymbol ( context . Node ) ! ;
86- } )
87- . Where ( static item => item is not null ) ! ;
84+ INamedTypeSymbol typeSymbol = ( INamedTypeSymbol ) context . SemanticModel . GetDeclaredSymbol ( context . Node , token ) ! ;
8885
89- // Filter the types with the target attribute
90- IncrementalValuesProvider < ( INamedTypeSymbol Symbol , AttributeData AttributeData ) > typeSymbolsWithAttributeData =
91- typeSymbols
92- . Select ( ( item , _ ) => (
93- Symbol : item ,
94- Attribute : item . GetAttributes ( ) . FirstOrDefault ( a => a . AttributeClass ? . HasFullyQualifiedName ( this . attributeType ) == true ) ) )
95- . Where ( static item => item . Attribute is not null ) ! ;
86+ // Filter the types with the target attribute
87+ if ( ! typeSymbol . TryGetAttributeWithFullyQualifiedName ( this . attributeType , out AttributeData ? attributeData ) )
88+ {
89+ return default ;
90+ }
9691
97- // Transform the input data
98- IncrementalValuesProvider < ( INamedTypeSymbol Symbol , TInfo Info ) > typeSymbolsWithInfo = GetInfo ( context , typeSymbolsWithAttributeData ) ;
92+ // Gather all generation info, and any diagnostics
93+ TInfo ? info = ValidateTargetTypeAndGetInfo ( typeSymbol , attributeData , context . SemanticModel . Compilation , out ImmutableArray < Diagnostic > diagnostics ) ;
9994
100- // Gather all generation info, and any diagnostics
101- IncrementalValuesProvider < Result < ( HierarchyInfo Hierarchy , bool IsSealed , TInfo Info ) > > generationInfoWithErrors =
102- typeSymbolsWithInfo . Select ( ( item , _ ) =>
103- {
104- if ( ValidateTargetType ( item . Symbol , item . Info , out ImmutableArray < Diagnostic > diagnostics ) )
105- {
106- return new Result < ( HierarchyInfo , bool , TInfo ) > (
107- ( HierarchyInfo . From ( item . Symbol ) , item . Symbol . IsSealed , item . Info ) ,
108- ImmutableArray < Diagnostic > . Empty ) ;
109- }
95+ // If there are any diagnostics, there's no need to compute the hierarchy info at all, just return them
96+ if ( diagnostics . Length > 0 )
97+ {
98+ return new Result < ( HierarchyInfo , bool , TInfo ? ) > ( default , diagnostics ) ;
99+ }
100+
101+ HierarchyInfo hierarchy = HierarchyInfo . From ( typeSymbol ) ;
110102
111- return new Result < ( HierarchyInfo , bool , TInfo ) > ( default , diagnostics ) ;
112- } ) ;
103+ return new Result < ( HierarchyInfo , bool , TInfo ? ) > ( ( hierarchy , typeSymbol . IsSealed , info ) , diagnostics ) ;
104+ } )
105+ . Where ( static item => item is not null ) ! ;
113106
114107 // Emit the diagnostic, if needed
115108 context . ReportDiagnostics ( generationInfoWithErrors . Select ( static ( item , _ ) => item . Errors ) ) ;
@@ -118,7 +111,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
118111 IncrementalValuesProvider < ( HierarchyInfo Hierarchy , bool IsSealed , TInfo Info ) > generationInfo =
119112 generationInfoWithErrors
120113 . Where ( static item => item . Errors . IsEmpty )
121- . Select ( static ( item , _ ) => item . Value )
114+ . Select ( static ( item , _ ) => item . Value ) !
122115 . WithComparers ( HierarchyInfo . Comparer . Default , EqualityComparer < bool > . Default , this . comparer ) ;
123116
124117 // Generate the required members
@@ -133,23 +126,15 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
133126 }
134127
135128 /// <summary>
136- /// Gathers info from a source <see cref="IncrementalValuesProvider{TValues}"/> input .
129+ /// Validates the target type being processes, gets the info if possible and produces all necessary diagnostics .
137130 /// </summary>
138- /// <param name="context">The <see cref="IncrementalGeneratorInitializationContext"/> instance in use.</param>
139- /// <param name="source">The source <see cref="IncrementalValuesProvider{TValues}"/> input.</param>
140- /// <returns>A transformed <see cref="IncrementalValuesProvider{TValues}"/> instance with the gathered data.</returns>
141- protected abstract IncrementalValuesProvider < ( INamedTypeSymbol Symbol , TInfo Info ) > GetInfo (
142- IncrementalGeneratorInitializationContext context ,
143- IncrementalValuesProvider < ( INamedTypeSymbol Symbol , AttributeData AttributeData ) > source ) ;
144-
145- /// <summary>
146- /// Validates a target type being processed.
147- /// </summary>
148- /// <param name="typeSymbol">The <see cref="INamedTypeSymbol"/> instance for the target type.</param>
149- /// <param name="info">The <typeparamref name="TInfo"/> instance with the current processing info.</param>
150- /// <param name="diagnostics">The resulting diagnostics from the processing operation.</param>
151- /// <returns>Whether or not the target type is valid and can be processed normally.</returns>
152- protected abstract bool ValidateTargetType ( INamedTypeSymbol typeSymbol , TInfo info , out ImmutableArray < Diagnostic > diagnostics ) ;
131+ /// <param name="typeSymbol">The <see cref="INamedTypeSymbol"/> instance currently being processed.</param>
132+ /// <param name="attributeData">The <see cref="AttributeData"/> instance for the attribute used over <paramref name="typeSymbol"/>.</param>
133+ /// <param name="compilation">The compilation that <paramref name="typeSymbol"/> belongs to.</param>
134+ /// <param name="diagnostics">The resulting diagnostics, if any.</param>
135+ /// <returns>The extracted info for the current type, if possible.</returns>
136+ /// <remarks>If <paramref name="diagnostics"/> is empty, the returned info will always be ignored and no sources will be produced.</remarks>
137+ protected abstract TInfo ? ValidateTargetTypeAndGetInfo ( INamedTypeSymbol typeSymbol , AttributeData attributeData , Compilation compilation , out ImmutableArray < Diagnostic > diagnostics ) ;
153138
154139 /// <summary>
155140 /// Filters the <see cref="MemberDeclarationSyntax"/> nodes to generate from the input parsed tree.
0 commit comments