Skip to content

Commit bac0c95

Browse files
committed
Harden nullability and index checks in generator
1 parent cda8a39 commit bac0c95

9 files changed

+42
-32
lines changed

src/Http/Http.Abstractions/src/Validation/TypeExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public static bool TryGetRequiredAttribute(this ValidationAttribute[] attributes
8888
/// Gets all types that the specified type implements or inherits from, including itself.
8989
/// </summary>
9090
/// <param name="type">The type to analyze.</param>
91-
/// <returns>A collection containing the type itself, all implemented interfaces, and all base types.</returns>
91+
/// <returns>A collection containing all implemented interfaces and all base types of the given type.</returns>
9292
public static IEnumerable<Type> GetAllImplementedTypes([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] this Type type)
9393
{
9494
ArgumentNullException.ThrowIfNull(type);

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ _ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute)
163163
}
164164
else if (type == typeof(global::System.ComponentModel.DataAnnotations.StringLengthAttribute))
165165
{
166-
if (args[0] is int maxLength)
166+
if (args.Length > 0 && args[0] is int maxLength)
167167
{
168168
attribute = new global::System.ComponentModel.DataAnnotations.StringLengthAttribute(maxLength);
169169
}
@@ -327,9 +327,8 @@ private static string EmitValidationAttributeForCreate(ValidationAttribute attr)
327327
foreach (var arg in attr.Arguments)
328328
{
329329
// Handle different types of arguments
330-
if (arg.StartsWith("\"", StringComparison.OrdinalIgnoreCase) && arg.EndsWith("\"", StringComparison.OrdinalIgnoreCase))
330+
if (arg.StartsWith("\"", StringComparison.OrdinalIgnoreCase) && arg.EndsWith("\"", StringComparison.OrdinalIgnoreCase) && arg.Length >= 2)
331331
{
332-
// String literal - remove quotes and pass as object
333332
var stringValue = arg.Substring(1, arg.Length - 2).Replace("\\\"", "\"");
334333
processedArgs.Add($"\"{stringValue}\"");
335334
}

src/Http/Http.Extensions/gen/Microsoft.AspNetCore.Http.ValidationsGenerator/Extensions/ITypeSymbolExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ public static bool ImplementsValidationAttribute(this ITypeSymbol typeSymbol, IN
3535

3636
public static ITypeSymbol UnwrapType(this ITypeSymbol type, INamedTypeSymbol enumerable)
3737
{
38-
if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T)
38+
if (type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T &&
39+
type is INamedTypeSymbol { TypeArguments.Length: 1 })
3940
{
4041
// Extract the T from a Nullable<T>
4142
type = ((INamedTypeSymbol)type).TypeArguments[0];

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//HintName: ValidatableInfoResolver.g.cs
2+
#nullable enable annotations
23
//------------------------------------------------------------------------------
34
// <auto-generated>
45
// This code was generated by a tool.
@@ -52,7 +53,7 @@ public GeneratedValidatableTypeInfo(
5253
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.ValidationsGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42")]
5354
file class GeneratedValidatableInfoResolver : global::Microsoft.AspNetCore.Http.Validation.IValidatableInfoResolver
5455
{
55-
public bool TryGetValidatableTypeInfo(global::System.Type type, out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo validatableInfo)
56+
public bool TryGetValidatableTypeInfo(global::System.Type type, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo? validatableInfo)
5657
{
5758
validatableInfo = null;
5859
if (type == typeof(global::SubType))
@@ -75,7 +76,7 @@ public bool TryGetValidatableTypeInfo(global::System.Type type, out global::Micr
7576
}
7677

7778
// No-ops, rely on runtime code for ParameterInfo-based resolution
78-
public bool TryGetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo, out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo validatableInfo)
79+
public bool TryGetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo? validatableInfo)
7980
{
8081
validatableInfo = null;
8182
return false;
@@ -227,7 +228,7 @@ private sealed record CacheKey(global::System.Type AttributeType, object[] Argum
227228
var type = k.AttributeType;
228229
var args = k.Arguments;
229230

230-
global::System.ComponentModel.DataAnnotations.ValidationAttribute attribute;
231+
global::System.ComponentModel.DataAnnotations.ValidationAttribute? attribute;
231232

232233
if (args.Length == 0)
233234
{
@@ -239,7 +240,8 @@ private sealed record CacheKey(global::System.Type AttributeType, object[] Argum
239240
global::System.Type t when t == typeof(global::System.ComponentModel.DataAnnotations.UrlAttribute) => new global::System.ComponentModel.DataAnnotations.UrlAttribute(),
240241
global::System.Type t when t == typeof(global::System.ComponentModel.DataAnnotations.CreditCardAttribute) => new global::System.ComponentModel.DataAnnotations.CreditCardAttribute(),
241242
_ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute).IsAssignableFrom(type) =>
242-
(global::System.ComponentModel.DataAnnotations.ValidationAttribute)global::System.Activator.CreateInstance(type)!
243+
(global::System.ComponentModel.DataAnnotations.ValidationAttribute)global::System.Activator.CreateInstance(type)!,
244+
_ => throw new global::System.ArgumentException($"Unsupported validation attribute type: {type.FullName}")
243245
};
244246
}
245247
else if (type == typeof(global::System.ComponentModel.DataAnnotations.CustomValidationAttribute) && args.Length == 2)
@@ -257,7 +259,7 @@ _ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute)
257259
}
258260
else if (type == typeof(global::System.ComponentModel.DataAnnotations.StringLengthAttribute))
259261
{
260-
if (args[0] is int maxLength)
262+
if (args.Length > 0 && args[0] is int maxLength)
261263
{
262264
attribute = new global::System.ComponentModel.DataAnnotations.StringLengthAttribute(maxLength);
263265
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//HintName: ValidatableInfoResolver.g.cs
2+
#nullable enable annotations
23
//------------------------------------------------------------------------------
34
// <auto-generated>
45
// This code was generated by a tool.
@@ -52,7 +53,7 @@ public GeneratedValidatableTypeInfo(
5253
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.ValidationsGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42")]
5354
file class GeneratedValidatableInfoResolver : global::Microsoft.AspNetCore.Http.Validation.IValidatableInfoResolver
5455
{
55-
public bool TryGetValidatableTypeInfo(global::System.Type type, out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo validatableInfo)
56+
public bool TryGetValidatableTypeInfo(global::System.Type type, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo? validatableInfo)
5657
{
5758
validatableInfo = null;
5859
if (type == typeof(global::SubType))
@@ -75,7 +76,7 @@ public bool TryGetValidatableTypeInfo(global::System.Type type, out global::Micr
7576
}
7677

7778
// No-ops, rely on runtime code for ParameterInfo-based resolution
78-
public bool TryGetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo, out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo validatableInfo)
79+
public bool TryGetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo? validatableInfo)
7980
{
8081
validatableInfo = null;
8182
return false;
@@ -185,7 +186,7 @@ private sealed record CacheKey(global::System.Type AttributeType, object[] Argum
185186
var type = k.AttributeType;
186187
var args = k.Arguments;
187188

188-
global::System.ComponentModel.DataAnnotations.ValidationAttribute attribute;
189+
global::System.ComponentModel.DataAnnotations.ValidationAttribute? attribute;
189190

190191
if (args.Length == 0)
191192
{
@@ -197,7 +198,8 @@ private sealed record CacheKey(global::System.Type AttributeType, object[] Argum
197198
global::System.Type t when t == typeof(global::System.ComponentModel.DataAnnotations.UrlAttribute) => new global::System.ComponentModel.DataAnnotations.UrlAttribute(),
198199
global::System.Type t when t == typeof(global::System.ComponentModel.DataAnnotations.CreditCardAttribute) => new global::System.ComponentModel.DataAnnotations.CreditCardAttribute(),
199200
_ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute).IsAssignableFrom(type) =>
200-
(global::System.ComponentModel.DataAnnotations.ValidationAttribute)global::System.Activator.CreateInstance(type)!
201+
(global::System.ComponentModel.DataAnnotations.ValidationAttribute)global::System.Activator.CreateInstance(type)!,
202+
_ => throw new global::System.ArgumentException($"Unsupported validation attribute type: {type.FullName}")
201203
};
202204
}
203205
else if (type == typeof(global::System.ComponentModel.DataAnnotations.CustomValidationAttribute) && args.Length == 2)
@@ -215,7 +217,7 @@ _ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute)
215217
}
216218
else if (type == typeof(global::System.ComponentModel.DataAnnotations.StringLengthAttribute))
217219
{
218-
if (args[0] is int maxLength)
220+
if (args.Length > 0 && args[0] is int maxLength)
219221
{
220222
attribute = new global::System.ComponentModel.DataAnnotations.StringLengthAttribute(maxLength);
221223
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//HintName: ValidatableInfoResolver.g.cs
2+
#nullable enable annotations
23
//------------------------------------------------------------------------------
34
// <auto-generated>
45
// This code was generated by a tool.
@@ -52,15 +53,15 @@ public GeneratedValidatableTypeInfo(
5253
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.ValidationsGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42")]
5354
file class GeneratedValidatableInfoResolver : global::Microsoft.AspNetCore.Http.Validation.IValidatableInfoResolver
5455
{
55-
public bool TryGetValidatableTypeInfo(global::System.Type type, out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo validatableInfo)
56+
public bool TryGetValidatableTypeInfo(global::System.Type type, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo? validatableInfo)
5657
{
5758
validatableInfo = null;
5859

5960
return false;
6061
}
6162

6263
// No-ops, rely on runtime code for ParameterInfo-based resolution
63-
public bool TryGetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo, out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo validatableInfo)
64+
public bool TryGetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo? validatableInfo)
6465
{
6566
validatableInfo = null;
6667
return false;
@@ -104,7 +105,7 @@ private sealed record CacheKey(global::System.Type AttributeType, object[] Argum
104105
var type = k.AttributeType;
105106
var args = k.Arguments;
106107

107-
global::System.ComponentModel.DataAnnotations.ValidationAttribute attribute;
108+
global::System.ComponentModel.DataAnnotations.ValidationAttribute? attribute;
108109

109110
if (args.Length == 0)
110111
{
@@ -116,7 +117,8 @@ private sealed record CacheKey(global::System.Type AttributeType, object[] Argum
116117
global::System.Type t when t == typeof(global::System.ComponentModel.DataAnnotations.UrlAttribute) => new global::System.ComponentModel.DataAnnotations.UrlAttribute(),
117118
global::System.Type t when t == typeof(global::System.ComponentModel.DataAnnotations.CreditCardAttribute) => new global::System.ComponentModel.DataAnnotations.CreditCardAttribute(),
118119
_ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute).IsAssignableFrom(type) =>
119-
(global::System.ComponentModel.DataAnnotations.ValidationAttribute)global::System.Activator.CreateInstance(type)!
120+
(global::System.ComponentModel.DataAnnotations.ValidationAttribute)global::System.Activator.CreateInstance(type)!,
121+
_ => throw new global::System.ArgumentException($"Unsupported validation attribute type: {type.FullName}")
120122
};
121123
}
122124
else if (type == typeof(global::System.ComponentModel.DataAnnotations.CustomValidationAttribute) && args.Length == 2)
@@ -134,7 +136,7 @@ _ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute)
134136
}
135137
else if (type == typeof(global::System.ComponentModel.DataAnnotations.StringLengthAttribute))
136138
{
137-
if (args[0] is int maxLength)
139+
if (args.Length > 0 && args[0] is int maxLength)
138140
{
139141
attribute = new global::System.ComponentModel.DataAnnotations.StringLengthAttribute(maxLength);
140142
}

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

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//HintName: ValidatableInfoResolver.g.cs
2+
#nullable enable annotations
23
//------------------------------------------------------------------------------
34
// <auto-generated>
45
// This code was generated by a tool.
@@ -52,7 +53,7 @@ public GeneratedValidatableTypeInfo(
5253
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.Http.ValidationsGenerator, Version=42.42.42.42, Culture=neutral, PublicKeyToken=adb9793829ddae60", "42.42.42.42")]
5354
file class GeneratedValidatableInfoResolver : global::Microsoft.AspNetCore.Http.Validation.IValidatableInfoResolver
5455
{
55-
public bool TryGetValidatableTypeInfo(global::System.Type type, out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo validatableInfo)
56+
public bool TryGetValidatableTypeInfo(global::System.Type type, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo? validatableInfo)
5657
{
5758
validatableInfo = null;
5859
if (type == typeof(global::DerivedType))
@@ -85,7 +86,7 @@ public bool TryGetValidatableTypeInfo(global::System.Type type, out global::Micr
8586
}
8687

8788
// No-ops, rely on runtime code for ParameterInfo-based resolution
88-
public bool TryGetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo, out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo validatableInfo)
89+
public bool TryGetValidatableParameterInfo(global::System.Reflection.ParameterInfo parameterInfo, [global::System.Diagnostics.CodeAnalysis.NotNullWhen(true)] out global::Microsoft.AspNetCore.Http.Validation.IValidatableInfo? validatableInfo)
8990
{
9091
validatableInfo = null;
9192
return false;
@@ -218,7 +219,7 @@ private sealed record CacheKey(global::System.Type AttributeType, object[] Argum
218219
var type = k.AttributeType;
219220
var args = k.Arguments;
220221

221-
global::System.ComponentModel.DataAnnotations.ValidationAttribute attribute;
222+
global::System.ComponentModel.DataAnnotations.ValidationAttribute? attribute;
222223

223224
if (args.Length == 0)
224225
{
@@ -230,7 +231,8 @@ private sealed record CacheKey(global::System.Type AttributeType, object[] Argum
230231
global::System.Type t when t == typeof(global::System.ComponentModel.DataAnnotations.UrlAttribute) => new global::System.ComponentModel.DataAnnotations.UrlAttribute(),
231232
global::System.Type t when t == typeof(global::System.ComponentModel.DataAnnotations.CreditCardAttribute) => new global::System.ComponentModel.DataAnnotations.CreditCardAttribute(),
232233
_ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute).IsAssignableFrom(type) =>
233-
(global::System.ComponentModel.DataAnnotations.ValidationAttribute)global::System.Activator.CreateInstance(type)!
234+
(global::System.ComponentModel.DataAnnotations.ValidationAttribute)global::System.Activator.CreateInstance(type)!,
235+
_ => throw new global::System.ArgumentException($"Unsupported validation attribute type: {type.FullName}")
234236
};
235237
}
236238
else if (type == typeof(global::System.ComponentModel.DataAnnotations.CustomValidationAttribute) && args.Length == 2)
@@ -248,7 +250,7 @@ _ when typeof(global::System.ComponentModel.DataAnnotations.ValidationAttribute)
248250
}
249251
else if (type == typeof(global::System.ComponentModel.DataAnnotations.StringLengthAttribute))
250252
{
251-
if (args[0] is int maxLength)
253+
if (args.Length > 0 && args[0] is int maxLength)
252254
{
253255
attribute = new global::System.ComponentModel.DataAnnotations.StringLengthAttribute(maxLength);
254256
}

0 commit comments

Comments
 (0)