@@ -20,47 +20,51 @@ private static void DetectMismatchedParameterOptionality(
2020 IInvocationOperation invocation ,
2121 IMethodSymbol methodSymbol )
2222 {
23+ if ( invocation . Arguments . Length < 2 )
24+ {
25+ return ;
26+ }
27+
2328 var value = invocation . Arguments [ 1 ] . Value ;
2429 if ( value . ConstantValue is not { HasValue : true } constant ||
2530 constant . Value is not string routeTemplate )
2631 {
2732 return ;
2833 }
2934
30- var parametersInArguments = methodSymbol . Parameters ;
31- var parametersInRoute = GetParametersFromRoute ( routeTemplate ) ;
32-
33- foreach ( var parameter in parametersInArguments )
35+ var allDeclarations = methodSymbol . GetAllMethodSymbolsOfPartialParts ( ) ;
36+ foreach ( var method in allDeclarations )
3437 {
35- var isOptional = parameter . IsOptional || parameter . NullableAnnotation != NullableAnnotation . NotAnnotated ;
36- var location = parameter . DeclaringSyntaxReferences . SingleOrDefault ( ) ? . GetSyntax ( ) . GetLocation ( ) ;
37- var paramName = parameter . Name ;
38- var parameterFound = parametersInRoute . TryGetValue ( paramName , out var routeParam ) ;
38+ var parametersInArguments = method . Parameters ;
39+ var enumerator = new RouteTokenEnumerator ( routeTemplate ) ;
3940
40- if ( ! isOptional && parameterFound && routeParam . IsOptional )
41+ while ( enumerator . MoveNext ( ) )
4142 {
42- context . ReportDiagnostic ( Diagnostic . Create (
43- DiagnosticDescriptors . DetectMismatchedParameterOptionality ,
44- location ,
45- paramName ) ) ;
43+ foreach ( var parameter in parametersInArguments )
44+ {
45+ var paramName = parameter . Name ;
46+ // If this is not the methpd parameter associated with the route
47+ // parameter then continue looking for it in the list
48+ if ( ! enumerator . CurrentName . Equals ( paramName . AsSpan ( ) , StringComparison . OrdinalIgnoreCase ) )
49+ {
50+ continue ;
51+ }
52+ var argumentIsOptional = parameter . IsOptional || parameter . NullableAnnotation != NullableAnnotation . NotAnnotated ;
53+ var location = parameter . DeclaringSyntaxReferences . SingleOrDefault ( ) ? . GetSyntax ( ) . GetLocation ( ) ;
54+ var routeParamIsOptional = enumerator . CurrentQualifiers . IndexOf ( '?' ) > - 1 ;
55+
56+ if ( ! argumentIsOptional && routeParamIsOptional )
57+ {
58+ context . ReportDiagnostic ( Diagnostic . Create (
59+ DiagnosticDescriptors . DetectMismatchedParameterOptionality ,
60+ location ,
61+ paramName ) ) ;
62+ }
63+ }
4664 }
4765 }
4866 }
4967
50- private static IDictionary < string , RouteParameter > GetParametersFromRoute ( string routeTemplate )
51- {
52- var enumerator = new RouteTokenEnumerator ( routeTemplate ) ;
53- Dictionary < string , RouteParameter > result = new ( StringComparer . OrdinalIgnoreCase ) ;
54- while ( enumerator . MoveNext ( ) )
55- {
56- var isOptional = enumerator . CurrentQualifiers . IndexOf ( '?' ) > - 1 ;
57- result . Add (
58- enumerator . CurrentName . ToString ( ) ,
59- new RouteParameter ( enumerator . CurrentName . ToString ( ) , isOptional ) ) ;
60- }
61- return result ;
62- }
63-
6468 internal ref struct RouteTokenEnumerator
6569 {
6670 private ReadOnlySpan < char > _routeTemplate ;
@@ -132,6 +136,4 @@ private static int IndexOf(ReadOnlySpan<char> span, int startIndex, char c)
132136
133137 return - 1 ;
134138 }
135-
136- internal record RouteParameter ( string Name , bool IsOptional ) ;
137139}
0 commit comments