@@ -83,19 +83,6 @@ internal static string GetAccessibility(TypeDeclarationSyntax typeDeclaration)
8383 return outerTypes ;
8484 }
8585
86- /// <summary>
87- /// Gets the set of excluded property names from an attribute's constructor arguments.
88- /// </summary>
89- /// <param name="classDeclaration">The class declaration syntax.</param>
90- /// <param name="semanticModel">The semantic model.</param>
91- /// <param name="attributeFullName">The full name of the attribute (e.g., "GenerateToStringAttribute").</param>
92- /// <returns>A set of excluded property names.</returns>
93- internal static HashSet < string > GetExcludedProperties (
94- ClassDeclarationSyntax classDeclaration ,
95- SemanticModel semanticModel ,
96- string attributeFullName )
97- => GetExcludedProperties ( ( TypeDeclarationSyntax ) classDeclaration , semanticModel , attributeFullName ) ;
98-
9986 /// <summary>
10087 /// Gets the set of excluded property names from an attribute's constructor arguments on a type declaration.
10188 /// </summary>
@@ -146,6 +133,89 @@ internal static string StripAttributeSuffix(string attributeName)
146133 ? attributeName [ ..^ AttributeKeyword . Length ]
147134 : attributeName ;
148135
136+ /// <summary>
137+ /// Gets the value of a named argument from an attribute on a type declaration.
138+ /// Searches the attribute lists for an attribute matching <paramref name="attributeShortName"/> or
139+ /// <paramref name="attributeFullName"/>, then looks for a named argument with the given <paramref name="propertyName"/>.
140+ /// </summary>
141+ /// <typeparam name="T">The expected type of the argument value.</typeparam>
142+ /// <param name="typeDeclaration">The type declaration syntax.</param>
143+ /// <param name="semanticModel">The semantic model.</param>
144+ /// <param name="attributeShortName">The short name of the attribute.</param>
145+ /// <param name="attributeFullName">The full name of the attribute.</param>
146+ /// <param name="propertyName">The name of the named argument to extract.</param>
147+ /// <param name="defaultValue">The default value to return if the argument is not found.</param>
148+ /// <returns>The extracted value, or <paramref name="defaultValue"/> if not found.</returns>
149+ internal static T GetNamedArgumentValue < T > (
150+ TypeDeclarationSyntax typeDeclaration ,
151+ SemanticModel semanticModel ,
152+ string attributeShortName ,
153+ string attributeFullName ,
154+ string propertyName ,
155+ T defaultValue )
156+ {
157+ foreach ( AttributeListSyntax attributeList in typeDeclaration . AttributeLists )
158+ {
159+ foreach ( AttributeSyntax attribute in attributeList . Attributes )
160+ {
161+ string name = attribute . Name . ToString ( ) ;
162+
163+ if ( name != attributeShortName && name != attributeFullName )
164+ continue ;
165+
166+ if ( attribute . ArgumentList is null )
167+ return defaultValue ;
168+
169+ foreach ( AttributeArgumentSyntax arg in attribute . ArgumentList . Arguments )
170+ {
171+ if ( arg . NameEquals ? . Name . Identifier . Text != propertyName )
172+ continue ;
173+
174+ Optional < object ? > value = semanticModel . GetConstantValue ( arg . Expression ) ;
175+
176+ if ( value . HasValue && value . Value is T typedValue )
177+ return typedValue ;
178+
179+ break ;
180+ }
181+
182+ return defaultValue ;
183+ }
184+ }
185+
186+ return defaultValue ;
187+ }
188+
189+ /// <summary>
190+ /// Gets the value of a positional constructor argument from an attribute on a type symbol.
191+ /// Searches the attributes of <paramref name="typeSymbol"/> for one whose class name matches
192+ /// <paramref name="attributeFullName"/>, then returns the constructor argument at <paramref name="index"/>.
193+ /// </summary>
194+ /// <typeparam name="T">The expected type of the constructor argument value.</typeparam>
195+ /// <param name="typeSymbol">The type symbol to inspect.</param>
196+ /// <param name="attributeFullName">The simple type name of the attribute (e.g., "GenerateIniFileAttribute").</param>
197+ /// <param name="index">The zero-based index of the constructor argument.</param>
198+ /// <param name="defaultValue">The default value to return if the argument is not found.</param>
199+ /// <returns>The extracted value, or <paramref name="defaultValue"/> if not found.</returns>
200+ internal static T GetConstructorArgumentValue < T > (
201+ INamedTypeSymbol typeSymbol ,
202+ string attributeFullName ,
203+ int index ,
204+ T defaultValue )
205+ {
206+ foreach ( AttributeData attributeData in typeSymbol . GetAttributes ( ) )
207+ {
208+ if ( attributeData . AttributeClass ? . Name != attributeFullName )
209+ continue ;
210+
211+ return attributeData . ConstructorArguments . Length > index && attributeData . ConstructorArguments [ index ] . Value is T typedValue
212+ ? typedValue
213+ : defaultValue ;
214+ }
215+
216+ return defaultValue ;
217+ }
218+
149219 /// <summary>
150220 /// Returns the fully-qualified metadata name, the simple full name, and the short name
151221 /// (without the "Attribute" suffix) for the given attribute type.
@@ -185,7 +255,7 @@ internal static string EscapeVerbatimString(string value)
185255 /// <param name="context">The generator attribute syntax context.</param>
186256 /// <returns>A tuple of class declaration syntax and semantic model, or null if the target node is not a class declaration.</returns>
187257 internal static ( ClassDeclarationSyntax ClassSyntax , SemanticModel SemanticModel ) ? TransformClassSyntax ( GeneratorAttributeSyntaxContext context )
188- => context . TargetNode is not ClassDeclarationSyntax classSyntax ? null : ( ( ClassDeclarationSyntax ClassSyntax , SemanticModel SemanticModel ) ? ) ( classSyntax , context . SemanticModel ) ;
258+ => context . TargetNode is not ClassDeclarationSyntax classSyntax ? null : ( classSyntax , context . SemanticModel ) ;
189259
190260 /// <summary>
191261 /// Registers a class-based incremental source generator pipeline that filters for classes
0 commit comments