@@ -111,7 +111,7 @@ private static void AnalyzeSymbol(
111
111
112
112
private static void AnalyzeAttribute ( SymbolAnalysisContext context , AttributeData attribute , IMethodSymbol methodSymbol )
113
113
{
114
- if ( attribute . ApplicationSyntaxReference ? . GetSyntax ( ) is not { } syntax )
114
+ if ( attribute . ApplicationSyntaxReference ? . GetSyntax ( ) is not { } dataRowSyntax )
115
115
{
116
116
return ;
117
117
}
@@ -126,21 +126,19 @@ private static void AnalyzeAttribute(SymbolAnalysisContext context, AttributeDat
126
126
// constructor argument.
127
127
if ( methodSymbol . Parameters . Length == 0 )
128
128
{
129
- context . ReportDiagnostic ( syntax . CreateDiagnostic (
129
+ context . ReportDiagnostic ( dataRowSyntax . CreateDiagnostic (
130
130
ArgumentCountMismatchRule ,
131
131
attribute . ConstructorArguments . Length ,
132
132
methodSymbol . Parameters . Length ) ) ;
133
133
return ;
134
134
}
135
135
136
136
// Possible count mismatch depending on whether last method parameter is an array or not.
137
- IParameterSymbol lastMethodParameter = methodSymbol . Parameters . Last ( ) ;
138
- bool lastMethodParameterIsArray = lastMethodParameter . Type . Kind == SymbolKind . ArrayType ;
139
137
if ( attribute . ConstructorArguments . Length == 0 )
140
138
{
141
- if ( ! lastMethodParameterIsArray )
139
+ if ( methodSymbol . Parameters [ ^ 1 ] . Type . Kind != SymbolKind . ArrayType )
142
140
{
143
- context . ReportDiagnostic ( syntax . CreateDiagnostic (
141
+ context . ReportDiagnostic ( dataRowSyntax . CreateDiagnostic (
144
142
ArgumentCountMismatchRule ,
145
143
attribute . ConstructorArguments . Length ,
146
144
methodSymbol . Parameters . Length ) ) ;
@@ -160,7 +158,7 @@ private static void AnalyzeAttribute(SymbolAnalysisContext context, AttributeDat
160
158
161
159
if ( IsArgumentCountMismatch ( constructorArguments . Length , methodSymbol . Parameters ) )
162
160
{
163
- context . ReportDiagnostic ( syntax . CreateDiagnostic (
161
+ context . ReportDiagnostic ( dataRowSyntax . CreateDiagnostic (
164
162
ArgumentCountMismatchRule ,
165
163
constructorArguments . Length ,
166
164
methodSymbol . Parameters . Length ) ) ;
@@ -169,34 +167,54 @@ private static void AnalyzeAttribute(SymbolAnalysisContext context, AttributeDat
169
167
170
168
// Check constructor argument types match method parameter types.
171
169
List < ( int ConstructorArgumentIndex , int MethodParameterIndex ) > typeMismatchIndices = new ( ) ;
172
- for ( int i = 0 ; i < constructorArguments . Length ; ++ i )
170
+ for ( int currentArgumentIndex = 0 ; currentArgumentIndex < constructorArguments . Length ; currentArgumentIndex ++ )
173
171
{
174
172
// Null is considered as default for non-nullable types.
175
- if ( constructorArguments [ i ] . IsNull )
173
+ if ( constructorArguments [ currentArgumentIndex ] . IsNull )
176
174
{
177
175
continue ;
178
176
}
179
177
180
- ITypeSymbol ? argumentType = constructorArguments [ i ] . Type ;
181
- ITypeSymbol paramType = ( lastMethodParameterIsArray && i >= methodSymbol . Parameters . Length - 1 )
182
- ? ( ( IArrayTypeSymbol ) lastMethodParameter . Type ) . ElementType
183
- : methodSymbol . Parameters [ i ] . Type ;
178
+ ITypeSymbol ? argumentType = constructorArguments [ currentArgumentIndex ] . Type ;
179
+ ITypeSymbol paramType = GetParameterType ( methodSymbol , currentArgumentIndex , constructorArguments . Length ) ;
184
180
185
181
if ( argumentType is not null && ! argumentType . IsAssignableTo ( paramType , context . Compilation ) )
186
182
{
187
- typeMismatchIndices . Add ( ( i , Math . Min ( i , methodSymbol . Parameters . Length - 1 ) ) ) ;
183
+ typeMismatchIndices . Add ( ( currentArgumentIndex , Math . Min ( currentArgumentIndex , methodSymbol . Parameters . Length - 1 ) ) ) ;
188
184
}
189
185
}
190
186
191
187
// Report diagnostics if there's any type mismatch.
192
188
if ( typeMismatchIndices . Count > 0 )
193
189
{
194
- context . ReportDiagnostic ( syntax . CreateDiagnostic (
190
+ context . ReportDiagnostic ( dataRowSyntax . CreateDiagnostic (
195
191
ArgumentTypeMismatchRule ,
196
192
string . Join ( ", " , typeMismatchIndices ) ) ) ;
197
193
}
198
194
}
199
195
196
+ private static ITypeSymbol GetParameterType ( IMethodSymbol methodSymbol , int currentArgumentIndex , int argumentsCount )
197
+ {
198
+ if ( currentArgumentIndex >= methodSymbol . Parameters . Length - 1 )
199
+ {
200
+ IParameterSymbol lastParameter = methodSymbol . Parameters [ ^ 1 ] ;
201
+
202
+ // When last parameter is params, we want to check that the extra arguments match the type of the array
203
+ if ( lastParameter . IsParams )
204
+ {
205
+ return ( ( IArrayTypeSymbol ) lastParameter . Type ) . ElementType ;
206
+ }
207
+
208
+ // When only parameter is array and we have more than one argument, we want to check the array type
209
+ if ( argumentsCount > 1 && methodSymbol . Parameters . Length == 1 && lastParameter . Type . Kind == SymbolKind . ArrayType )
210
+ {
211
+ return ( ( IArrayTypeSymbol ) lastParameter . Type ) . ElementType ;
212
+ }
213
+ }
214
+
215
+ return methodSymbol . Parameters [ currentArgumentIndex ] . Type ;
216
+ }
217
+
200
218
private static bool IsArgumentCountMismatch ( int constructorArgumentsLength , ImmutableArray < IParameterSymbol > methodParameters )
201
219
{
202
220
int optionalParametersCount = methodParameters . Count ( x => x . HasExplicitDefaultValue ) ;
0 commit comments