Skip to content

Commit 889fd26

Browse files
committed
Harden parameter resolution check
1 parent c345a1b commit 889fd26

7 files changed

+108
-46
lines changed

src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Emitters/ValidationsGenerator.Emitter.cs

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,14 +300,64 @@ private static string EmitParameterTypeChecks(ImmutableArray<ValidatableParamete
300300
{
301301
var sw = new StringWriter();
302302
var cw = new CodeWriter(sw, baseIndent: 3);
303-
foreach (var validatableParameter in validatableParameters)
303+
304+
// Group parameters by name to handle potential duplicates
305+
var parameterGroups = validatableParameters.GroupBy(p => p.Name).ToList();
306+
307+
foreach (var group in parameterGroups)
304308
{
305-
var parameterTypeName = validatableParameter.Type.ToDisplayString();
306-
cw.WriteLine($"if (parameterInfo.Name == \"{validatableParameter.Name}\" && parameterInfo.ParameterType == typeof({parameterTypeName}))");
307-
cw.StartBlock();
308-
cw.WriteLine($"return CreateParameterInfo{SanitizeTypeName(validatableParameter.Name)}();");
309-
cw.EndBlock();
309+
var name = group.Key;
310+
var parameters = group.ToList();
311+
312+
// If there's only one parameter with this name, use the simple check
313+
if (parameters.Count == 1)
314+
{
315+
var param = parameters[0];
316+
var parameterTypeName = param.Type.ToDisplayString();
317+
cw.WriteLine($"if (parameterInfo.Name == \"{param.Name}\" && parameterInfo.ParameterType == typeof({parameterTypeName}))");
318+
cw.StartBlock();
319+
cw.WriteLine($"return CreateParameterInfo_{SanitizeTypeName(param.OriginalType.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat))}_{SanitizeTypeName(param.Name)}_{param.Index}();");
320+
cw.EndBlock();
321+
}
322+
else
323+
{
324+
// For parameters with the same name, we need additional checks to distinguish them
325+
cw.WriteLine($"if (parameterInfo.Name == \"{name}\")");
326+
cw.StartBlock();
327+
328+
// Check parameter type first as it's faster
329+
for (var i = 0; i < parameters.Count; i++)
330+
{
331+
var param = parameters[i];
332+
var parameterTypeName = param.Type.ToDisplayString();
333+
334+
// For first item, use 'if', for others use 'else if'
335+
string ifStatement = i == 0 ? "if" : "else if";
336+
337+
cw.WriteLine($"{ifStatement} (parameterInfo.ParameterType == typeof({parameterTypeName}))");
338+
cw.StartBlock();
339+
340+
// Add position check if available
341+
if (param.Index >= 0)
342+
{
343+
cw.WriteLine($"if (parameterInfo.Position == {param.Index})");
344+
cw.StartBlock();
345+
}
346+
347+
cw.WriteLine($"return CreateParameterInfo_{SanitizeTypeName(param.OriginalType.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat))}_{SanitizeTypeName(param.Name)}_{param.Index}();");
348+
349+
if (param.Index >= 0)
350+
{
351+
cw.EndBlock();
352+
}
353+
354+
cw.EndBlock();
355+
}
356+
357+
cw.EndBlock();
358+
}
310359
}
360+
311361
return sw.ToString();
312362
}
313363

@@ -361,7 +411,7 @@ private static string EmitCreateParameterMethods(ImmutableArray<ValidatableParam
361411
foreach (var validatableParameter in validatableParameters)
362412
{
363413
var parameterTypeName = validatableParameter.Type.ToDisplayString();
364-
cw.WriteLine($@"private ValidatableParameterInfo CreateParameterInfo{SanitizeTypeName(validatableParameter.Name)}()");
414+
cw.WriteLine($@"private ValidatableParameterInfo CreateParameterInfo_{SanitizeTypeName(validatableParameter.OriginalType.ToDisplayString(SymbolDisplayFormat.CSharpShortErrorMessageFormat))}_{SanitizeTypeName(validatableParameter.Name)}_{validatableParameter.Index}()");
365415
cw.StartBlock();
366416
var validationAttributes = validatableParameter.Attributes.IsDefaultOrEmpty
367417
? "[]"

src/Http/Http.Extensions/test/ValidationsGenerator/ValidationsGenerator.Polymorphism.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ public async Task CanValidatePolymorphicTypes()
2424
2525
var app = builder.Build();
2626
27-
app.MapPost("/basic-polymorphism", (BaseType model1) => Results.Ok());
28-
app.MapPost("/validatable-polymorphism", (BaseValidatableType model2) => Results.Ok());
29-
app.MapPost("/polymorphism-container", (ContainerType model3) => Results.Ok());
27+
app.MapPost("/basic-polymorphism", (BaseType model) => Results.Ok());
28+
app.MapPost("/validatable-polymorphism", (BaseValidatableType model) => Results.Ok());
29+
app.MapPost("/polymorphism-container", (ContainerType model) => Results.Ok());
3030
3131
app.Run();
3232

src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateComplexTypes#ValidatableInfoResolver.g.verified.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public GeneratedValidatableTypeInfo(
108108
{
109109
if (parameterInfo.Name == "complexType" && parameterInfo.ParameterType == typeof(ComplexType))
110110
{
111-
return CreateParameterInfocomplexType();
111+
return CreateParameterInfo_ComplexType_complexType_0();
112112
}
113113

114114
return null;
@@ -252,7 +252,7 @@ private ValidatableTypeInfo CreateComplexType()
252252
implementsIValidatableObject: false);
253253
}
254254

255-
private ValidatableParameterInfo CreateParameterInfocomplexType()
255+
private ValidatableParameterInfo CreateParameterInfo_ComplexType_complexType_0()
256256
{
257257
return new GeneratedValidatableParameterInfo(
258258
name: "complexType",

src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateIValidatableObject#ValidatableInfoResolver.g.verified.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ public GeneratedValidatableTypeInfo(
108108
{
109109
if (parameterInfo.Name == "model" && parameterInfo.ParameterType == typeof(ComplexValidatableType))
110110
{
111-
return CreateParameterInfomodel();
111+
return CreateParameterInfo_ComplexValidatableType_model_0();
112112
}
113113

114114
return null;
@@ -202,7 +202,7 @@ private ValidatableTypeInfo CreateComplexValidatableType()
202202
implementsIValidatableObject: true);
203203
}
204204

205-
private ValidatableParameterInfo CreateParameterInfomodel()
205+
private ValidatableParameterInfo CreateParameterInfo_ComplexValidatableType_model_0()
206206
{
207207
return new GeneratedValidatableParameterInfo(
208208
name: "model",

src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateParameters#ValidatableInfoResolver.g.verified.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -96,30 +96,30 @@ public GeneratedValidatableTypeInfo(
9696
{
9797
if (parameterInfo.Name == "value1" && parameterInfo.ParameterType == typeof(int))
9898
{
99-
return CreateParameterInfovalue1();
99+
return CreateParameterInfo_int_value1_0();
100100
}
101101
if (parameterInfo.Name == "value2" && parameterInfo.ParameterType == typeof(int))
102102
{
103-
return CreateParameterInfovalue2();
103+
return CreateParameterInfo_int_value2_1();
104104
}
105105
if (parameterInfo.Name == "value3" && parameterInfo.ParameterType == typeof(string))
106106
{
107-
return CreateParameterInfovalue3();
107+
return CreateParameterInfo_string_value3_2();
108108
}
109109
if (parameterInfo.Name == "value4" && parameterInfo.ParameterType == typeof(int))
110110
{
111-
return CreateParameterInfovalue4();
111+
return CreateParameterInfo_int_value4_3();
112112
}
113113
if (parameterInfo.Name == "value5" && parameterInfo.ParameterType == typeof(int))
114114
{
115-
return CreateParameterInfovalue5();
115+
return CreateParameterInfo_int_value5_4();
116116
}
117117

118118
return null;
119119
}
120120

121121

122-
private ValidatableParameterInfo CreateParameterInfovalue1()
122+
private ValidatableParameterInfo CreateParameterInfo_int_value1_0()
123123
{
124124
return new GeneratedValidatableParameterInfo(
125125
name: "value1",
@@ -131,7 +131,7 @@ private ValidatableParameterInfo CreateParameterInfovalue1()
131131
validationAttributes: [ValidationAttributeCache.GetOrCreateValidationAttribute(typeof(global::System.ComponentModel.DataAnnotations.RangeAttribute), new string[] { "10", "100" }, new Dictionary<string, string>()) ?? throw new InvalidOperationException("Failed to create validation attribute global::System.ComponentModel.DataAnnotations.RangeAttribute")]
132132
);
133133
}
134-
private ValidatableParameterInfo CreateParameterInfovalue2()
134+
private ValidatableParameterInfo CreateParameterInfo_int_value2_1()
135135
{
136136
return new GeneratedValidatableParameterInfo(
137137
name: "value2",
@@ -143,7 +143,7 @@ private ValidatableParameterInfo CreateParameterInfovalue2()
143143
validationAttributes: [ValidationAttributeCache.GetOrCreateValidationAttribute(typeof(global::System.ComponentModel.DataAnnotations.RangeAttribute), new string[] { "10", "100" }, new Dictionary<string, string>()) ?? throw new InvalidOperationException("Failed to create validation attribute global::System.ComponentModel.DataAnnotations.RangeAttribute")]
144144
);
145145
}
146-
private ValidatableParameterInfo CreateParameterInfovalue3()
146+
private ValidatableParameterInfo CreateParameterInfo_string_value3_2()
147147
{
148148
return new GeneratedValidatableParameterInfo(
149149
name: "value3",
@@ -155,7 +155,7 @@ private ValidatableParameterInfo CreateParameterInfovalue3()
155155
validationAttributes: [ValidationAttributeCache.GetOrCreateValidationAttribute(typeof(global::System.ComponentModel.DataAnnotations.RequiredAttribute), Array.Empty<string>(), new Dictionary<string, string>()) ?? throw new InvalidOperationException("Failed to create validation attribute global::System.ComponentModel.DataAnnotations.RequiredAttribute")]
156156
);
157157
}
158-
private ValidatableParameterInfo CreateParameterInfovalue4()
158+
private ValidatableParameterInfo CreateParameterInfo_int_value4_3()
159159
{
160160
return new GeneratedValidatableParameterInfo(
161161
name: "value4",
@@ -167,7 +167,7 @@ private ValidatableParameterInfo CreateParameterInfovalue4()
167167
validationAttributes: [ValidationAttributeCache.GetOrCreateValidationAttribute(typeof(global::CustomValidationAttribute), Array.Empty<string>(), new Dictionary<string, string> { { "ErrorMessage", "Value must be an even number" } }) ?? throw new InvalidOperationException("Failed to create validation attribute global::CustomValidationAttribute")]
168168
);
169169
}
170-
private ValidatableParameterInfo CreateParameterInfovalue5()
170+
private ValidatableParameterInfo CreateParameterInfo_int_value5_4()
171171
{
172172
return new GeneratedValidatableParameterInfo(
173173
name: "value5",

src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidatePolymorphicTypes#ValidatableInfoResolver.g.verified.cs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,29 @@ public GeneratedValidatableTypeInfo(
114114

115115
public ValidatableParameterInfo? GetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo)
116116
{
117-
if (parameterInfo.Name == "model1" && parameterInfo.ParameterType == typeof(BaseType))
117+
if (parameterInfo.Name == "model")
118118
{
119-
return CreateParameterInfomodel1();
120-
}
121-
if (parameterInfo.Name == "model2" && parameterInfo.ParameterType == typeof(BaseValidatableType))
122-
{
123-
return CreateParameterInfomodel2();
124-
}
125-
if (parameterInfo.Name == "model3" && parameterInfo.ParameterType == typeof(ContainerType))
126-
{
127-
return CreateParameterInfomodel3();
119+
if (parameterInfo.ParameterType == typeof(BaseType))
120+
{
121+
if (parameterInfo.Position == 0)
122+
{
123+
return CreateParameterInfo_BaseType_model_0();
124+
}
125+
}
126+
else if (parameterInfo.ParameterType == typeof(BaseValidatableType))
127+
{
128+
if (parameterInfo.Position == 0)
129+
{
130+
return CreateParameterInfo_BaseValidatableType_model_0();
131+
}
132+
}
133+
else if (parameterInfo.ParameterType == typeof(ContainerType))
134+
{
135+
if (parameterInfo.Position == 0)
136+
{
137+
return CreateParameterInfo_ContainerType_model_0();
138+
}
139+
}
128140
}
129141

130142
return null;
@@ -247,35 +259,35 @@ private ValidatableTypeInfo CreateContainerType()
247259
implementsIValidatableObject: false);
248260
}
249261

250-
private ValidatableParameterInfo CreateParameterInfomodel1()
262+
private ValidatableParameterInfo CreateParameterInfo_BaseType_model_0()
251263
{
252264
return new GeneratedValidatableParameterInfo(
253-
name: "model1",
254-
displayName: "model1",
265+
name: "model",
266+
displayName: "model",
255267
isRequired: false,
256268
isNullable: false,
257269
hasValidatableType: true,
258270
isEnumerable: false,
259271
validationAttributes: []
260272
);
261273
}
262-
private ValidatableParameterInfo CreateParameterInfomodel2()
274+
private ValidatableParameterInfo CreateParameterInfo_BaseValidatableType_model_0()
263275
{
264276
return new GeneratedValidatableParameterInfo(
265-
name: "model2",
266-
displayName: "model2",
277+
name: "model",
278+
displayName: "model",
267279
isRequired: false,
268280
isNullable: false,
269281
hasValidatableType: true,
270282
isEnumerable: false,
271283
validationAttributes: []
272284
);
273285
}
274-
private ValidatableParameterInfo CreateParameterInfomodel3()
286+
private ValidatableParameterInfo CreateParameterInfo_ContainerType_model_0()
275287
{
276288
return new GeneratedValidatableParameterInfo(
277-
name: "model3",
278-
displayName: "model3",
289+
name: "model",
290+
displayName: "model",
279291
isRequired: false,
280292
isNullable: false,
281293
hasValidatableType: true,
@@ -289,7 +301,7 @@ private ValidatableParameterInfo CreateParameterInfomodel3()
289301
[System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.ValidationsGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42")]
290302
file static class GeneratedServiceCollectionExtensions
291303
{
292-
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "5ZkYKqNUHazJ7h8nBycbiYgBAABQcm9ncmFtLmNz")]
304+
[global::System.Runtime.CompilerServices.InterceptsLocationAttribute(1, "2dHhUDyiknXJLaQw/hXAKIgBAABQcm9ncmFtLmNz")]
293305
public static IServiceCollection AddValidation(this IServiceCollection services, Action<ValidationOptions>? configureOptions = null)
294306
{
295307
// Use non-extension method to avoid infinite recursion.

src/Http/Http.Extensions/test/ValidationsGenerator/snapshots/ValidationsGeneratorTests.CanValidateRecursiveTypes#ValidatableInfoResolver.g.verified.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public GeneratedValidatableTypeInfo(
100100
{
101101
if (parameterInfo.Name == "model" && parameterInfo.ParameterType == typeof(RecursiveType))
102102
{
103-
return CreateParameterInfomodel();
103+
return CreateParameterInfo_RecursiveType_model_0();
104104
}
105105

106106
return null;
@@ -135,7 +135,7 @@ private ValidatableTypeInfo CreateRecursiveType()
135135
implementsIValidatableObject: false);
136136
}
137137

138-
private ValidatableParameterInfo CreateParameterInfomodel()
138+
private ValidatableParameterInfo CreateParameterInfo_RecursiveType_model_0()
139139
{
140140
return new GeneratedValidatableParameterInfo(
141141
name: "model",

0 commit comments

Comments
 (0)