1+ // <auto-generated>
2+ // This file is part of the Datacute.IncrementalGeneratorExtensions package.
3+ // It is included as a source file and should not be modified.
4+ // </auto-generated>
5+
6+ #if ! DATACUTE_EXCLUDE_ATTRIBUTECONTEXTANDDATA && ! DATACUTE_EXCLUDE_TYPECONTEXT
7+ using System ;
8+ using System . Collections . Immutable ;
9+ using System . Threading ;
10+ using Microsoft . CodeAnalysis ;
11+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
12+
13+ namespace Datacute . IncrementalGeneratorExtensions
14+ {
15+ /// <summary>
16+ /// Represents the context and data of an attribute in a source generator.
17+ /// </summary>
18+ /// <typeparam name="T">The type of the attribute data, which must implement <see cref="IEquatable{T}"/>.</typeparam>
19+ public readonly struct AttributeContextAndData < T > : IEquatable < AttributeContextAndData < T > >
20+ where T : IEquatable < T >
21+ {
22+ /// <summary>
23+ /// Indicates whether the containing namespace is the global namespace.
24+ /// </summary>
25+ public readonly bool ContainingNamespaceIsGlobalNamespace ;
26+ /// <summary>
27+ /// The display string of the containing namespace.
28+ /// </summary>
29+ public readonly string ContainingNamespaceDisplayString ;
30+ /// <summary>
31+ /// The context of the type to which the attribute is applied.
32+ /// </summary>
33+ public readonly TypeContext Context ;
34+ /// <summary>
35+ /// A collection of contexts for the containing types of the attribute's target symbol.
36+ /// </summary>
37+ public readonly EquatableImmutableArray < TypeContext > ContainingTypes ;
38+
39+ /// <summary>
40+ /// The display string of the attribute's target symbol, formatted as Namespace.ClassName.
41+ /// </summary>
42+ /// <remarks>
43+ /// This string is useful for generating a hint name for the attribute, as it provides a
44+ /// fully qualified name that includes the namespace and class name.
45+ /// </remarks>
46+ public readonly string DisplayString ;
47+
48+ /// <summary>
49+ /// Indicates whether the attribute's target symbol has any containing types.
50+ /// </summary>
51+ public bool HasContainingTypes => ContainingTypes . Length > 0 ;
52+
53+ /// <summary>
54+ /// The data associated with the attribute, which is typically collected from the attribute's syntax context.
55+ /// </summary>
56+ public readonly T AttributeData ;
57+
58+ /// <summary>
59+ /// Initializes a new instance of the <see cref="AttributeContextAndData{T}"/> struct.
60+ /// </summary>
61+ /// <param name="generatorAttributeSyntaxContext">The context of the attribute syntax, which includes information about the target symbol and the attribute itself.</param>
62+ /// <param name="attributeData">The data associated with the attribute, typically collected from the attribute's syntax context.</param>
63+ public AttributeContextAndData ( in GeneratorAttributeSyntaxContext generatorAttributeSyntaxContext , in T attributeData )
64+ {
65+ AttributeData = attributeData ;
66+
67+ // No diagnostic tracing here - this triggers for each matching attribute, every time you type.
68+ // the time taken within this method is about 1% of the time the source generator takes
69+ // to process the attribute.
70+
71+ var attributeTargetSymbol = ( ITypeSymbol ) generatorAttributeSyntaxContext . TargetSymbol ;
72+
73+ ContainingNamespaceIsGlobalNamespace = attributeTargetSymbol . ContainingNamespace . IsGlobalNamespace ;
74+ ContainingNamespaceDisplayString = attributeTargetSymbol . ContainingNamespace . ToDisplayString ( ) ;
75+
76+ EquatableImmutableArray < string > typeParameterNames ;
77+ if ( generatorAttributeSyntaxContext . TargetSymbol is INamedTypeSymbol namedTypeTargetSymbol )
78+ {
79+ ImmutableArray < ITypeParameterSymbol > typeParameters = namedTypeTargetSymbol . TypeParameters ;
80+ typeParameterNames = typeParameters . Length > 0
81+ ? typeParameters . ToEquatableImmutableArray ( tp => tp . Name )
82+ : EquatableImmutableArray < string > . Empty ;
83+ }
84+ else
85+ {
86+ typeParameterNames = EquatableImmutableArray < string > . Empty ;
87+ }
88+
89+ Context = new TypeContext (
90+ attributeTargetSymbol . Name ,
91+ attributeTargetSymbol . IsStatic ,
92+ attributeTargetSymbol . DeclaredAccessibility ,
93+ TypeContext . GetRecordStructOrClass ( attributeTargetSymbol ) ,
94+ typeParameterNames ) ;
95+
96+ DisplayString = attributeTargetSymbol . ToDisplayString ( ) ;
97+
98+ // Parse parent classes from symbol's containing types
99+ var parentClassCount = 0 ;
100+ var containingType = attributeTargetSymbol . ContainingType ;
101+ // Count the number of parent classes
102+ while ( containingType != null )
103+ {
104+ parentClassCount ++ ;
105+ containingType = containingType . ContainingType ;
106+ }
107+
108+ if ( parentClassCount > 0 )
109+ {
110+ containingType = attributeTargetSymbol . ContainingType ;
111+ var containingTypesImmutableArrayBuilder = ImmutableArray . CreateBuilder < TypeContext > ( parentClassCount ) ;
112+ for ( var i = 0 ; i < parentClassCount ; i ++ )
113+ {
114+ var typeParameters = containingType . TypeParameters ;
115+ var containingTypeTypeParameterNames = typeParameters . Length > 0
116+ ? typeParameters . ToEquatableImmutableArray ( tp => tp . Name )
117+ : EquatableImmutableArray < string > . Empty ;
118+
119+ containingTypesImmutableArrayBuilder . Insert ( 0 , new TypeContext (
120+ containingType . Name ,
121+ containingType . IsStatic ,
122+ containingType . DeclaredAccessibility ,
123+ TypeContext . GetRecordStructOrClass ( containingType ) ,
124+ containingTypeTypeParameterNames ) ) ;
125+ containingType = containingType . ContainingType ;
126+ }
127+
128+ ContainingTypes = containingTypesImmutableArrayBuilder . MoveToImmutable ( ) . ToEquatableImmutableArray ( ) ;
129+ }
130+ else
131+ {
132+ ContainingTypes = EquatableImmutableArray < TypeContext > . Empty ;
133+ }
134+ }
135+
136+ /// <inheritdoc />
137+ public bool Equals ( AttributeContextAndData < T > other )
138+ {
139+ return ContainingNamespaceIsGlobalNamespace == other . ContainingNamespaceIsGlobalNamespace && ContainingNamespaceDisplayString == other . ContainingNamespaceDisplayString && Context . Equals ( other . Context ) && Equals ( ContainingTypes , other . ContainingTypes ) && DisplayString == other . DisplayString && AttributeData . Equals ( other . AttributeData ) ;
140+ }
141+
142+ /// <inheritdoc />
143+ public override bool Equals ( object obj )
144+ {
145+ return obj is AttributeContextAndData < T > other && Equals ( other ) ;
146+ }
147+
148+ /// <inheritdoc />
149+ public override int GetHashCode ( )
150+ {
151+ unchecked
152+ {
153+ var hashCode = ContainingNamespaceIsGlobalNamespace . GetHashCode ( ) ;
154+ hashCode = ( hashCode * 397 ) ^ ( ContainingNamespaceDisplayString != null ? ContainingNamespaceDisplayString . GetHashCode ( ) : 0 ) ;
155+ hashCode = ( hashCode * 397 ) ^ Context . GetHashCode ( ) ;
156+ hashCode = ( hashCode * 397 ) ^ ( ContainingTypes != null ? ContainingTypes . GetHashCode ( ) : 0 ) ;
157+ hashCode = ( hashCode * 397 ) ^ ( DisplayString != null ? DisplayString . GetHashCode ( ) : 0 ) ;
158+ hashCode = ( hashCode * 397 ) ^ ( AttributeData != null ? AttributeData . GetHashCode ( ) : 0 ) ;
159+ return hashCode ;
160+ }
161+ }
162+
163+ /// <summary>
164+ /// Predicate to determine if the syntax node is a type declaration syntax.
165+ /// </summary>
166+ /// <param name="syntaxNode">The syntax node to check.</param>
167+ /// <param name="token">The cancellation token to observe for cancellation requests.</param>
168+ /// <returns> True if the syntax node is a type declaration syntax, otherwise false.</returns>
169+ /// <example>
170+ /// <code lang="csharp">
171+ /// context.SyntaxProvider
172+ /// .ForAttributeWithMetadataName(
173+ /// "YourFullyQualifiedMetadataName",
174+ /// predicate: AttributeContextAndData<YourAttributeDataType>.Predicate,
175+ /// transform: (syntaxContext, token) =>
176+ /// AttributeContextAndData<YourAttributeDataType>.Transform(syntaxContext, yourAttributeDataCollector, token))
177+ /// .WithTrackingName(GeneratorStage.ForAttributeWithMetadataName);
178+ /// </code>
179+ /// </example>
180+ /// <seealso cref="AttributeContextAndDataExtensions.SelectAttributeContexts{T}"/>
181+ public static bool Predicate ( SyntaxNode syntaxNode , CancellationToken token )
182+ {
183+ #if ! DATACUTE_EXCLUDE_GENERATORSTAGE && ! DATACUTE_EXCLUDE_LIGHTWEIGHTTRACE
184+ LightweightTrace . IncrementCount ( GeneratorStage . ForAttributeWithMetadataNamePredicate ) ;
185+ #if ! DATACUTE_EXCLUDE_LIGHTWEIGHTTRACEEXTENSIONS
186+ token . ThrowIfCancellationRequested ( GeneratorStage . ForAttributeWithMetadataNamePredicate ) ;
187+ #else
188+ token . ThrowIfCancellationRequested ( ) ;
189+ #endif
190+ #endif
191+ return syntaxNode is TypeDeclarationSyntax ;
192+ }
193+
194+ /// <summary>
195+ /// Transforms the <see cref="GeneratorAttributeSyntaxContext"/> into an <see cref="AttributeContextAndData{T}"/> instance.
196+ /// </summary>
197+ /// <param name="generatorAttributeSyntaxContext">The context of the attribute syntax, which includes information about the target symbol and the attribute itself.</param>
198+ /// <param name="attributeDataCollector">A function that collects the attribute data from the <see cref="GeneratorAttributeSyntaxContext"/>.</param>
199+ /// <param name="token">The cancellation token to observe for cancellation requests.</param>
200+ /// <returns>An instance of <see cref="AttributeContextAndData{T}"/> containing the attribute context and data.</returns>
201+ /// <example>
202+ /// <code lang="csharp">
203+ /// context.SyntaxProvider
204+ /// .ForAttributeWithMetadataName(
205+ /// "YourFullyQualifiedMetadataName",
206+ /// predicate: AttributeContextAndData<YourAttributeDataType>.Predicate,
207+ /// transform: (syntaxContext, token) =>
208+ /// AttributeContextAndData<YourAttributeDataType>.Transform(syntaxContext, yourAttributeDataCollector, token))
209+ /// .WithTrackingName(GeneratorStage.ForAttributeWithMetadataName);
210+ /// </code>
211+ /// </example>
212+ /// <seealso cref="AttributeContextAndDataExtensions.SelectAttributeContexts{T}"/>
213+ public static AttributeContextAndData < T > Transform ( GeneratorAttributeSyntaxContext generatorAttributeSyntaxContext , Func < GeneratorAttributeSyntaxContext , T > attributeDataCollector , CancellationToken token )
214+ {
215+ #if ! DATACUTE_EXCLUDE_GENERATORSTAGE && ! DATACUTE_EXCLUDE_LIGHTWEIGHTTRACE
216+ LightweightTrace . IncrementCount ( GeneratorStage . ForAttributeWithMetadataNameTransform ) ;
217+ #if ! DATACUTE_EXCLUDE_LIGHTWEIGHTTRACEEXTENSIONS
218+ token . ThrowIfCancellationRequested ( GeneratorStage . ForAttributeWithMetadataNameTransform ) ;
219+ #else
220+ token . ThrowIfCancellationRequested ( ) ;
221+ #endif
222+ #endif
223+ T attributeData = attributeDataCollector ( generatorAttributeSyntaxContext ) ;
224+ var attributeContextAndData = new AttributeContextAndData < T > ( generatorAttributeSyntaxContext , attributeData ) ;
225+ return attributeContextAndData ;
226+ }
227+ }
228+ }
229+ #endif
0 commit comments