forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix Options extending System types cases in Options source generator (d…
- Loading branch information
Showing
4 changed files
with
606 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
278 changes: 278 additions & 0 deletions
278
.../tests/SourceGeneration.Unit.Tests/Baselines/OptionsExtendingSystemClassTest.netcore.g.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,278 @@ | ||
|
||
// <auto-generated/> | ||
#nullable enable | ||
#pragma warning disable CS1591 // Compensate for https://github.com/dotnet/roslyn/issues/54103 | ||
namespace Test | ||
{ | ||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] | ||
internal sealed partial class __EndPointsOptionsValidator__ | ||
{ | ||
/// <summary> | ||
/// Validates a specific named options instance (or all when <paramref name="name"/> is <see langword="null" />). | ||
/// </summary> | ||
/// <param name="name">The name of the options instance being validated.</param> | ||
/// <param name="options">The options instance.</param> | ||
/// <returns>Validation result.</returns> | ||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] | ||
[System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", | ||
Justification = "The created ValidationContext object is used in a way that never call reflection")] | ||
public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Test.EndPointsOptions options) | ||
{ | ||
global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; | ||
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); | ||
var validationResults = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationResult>(); | ||
var validationAttributes = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationAttribute>(2); | ||
|
||
context.MemberName = "Host"; | ||
context.DisplayName = string.IsNullOrEmpty(name) ? "EndPointsOptions.Host" : $"{name}.Host"; | ||
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); | ||
if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Host, context, validationResults, validationAttributes)) | ||
{ | ||
(builder ??= new()).AddResults(validationResults); | ||
} | ||
|
||
context.MemberName = "Port"; | ||
context.DisplayName = string.IsNullOrEmpty(name) ? "EndPointsOptions.Port" : $"{name}.Port"; | ||
validationResults.Clear(); | ||
validationAttributes.Clear(); | ||
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); | ||
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2); | ||
if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Port, context, validationResults, validationAttributes)) | ||
{ | ||
(builder ??= new()).AddResults(validationResults); | ||
} | ||
|
||
return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); | ||
} | ||
} | ||
} | ||
namespace Test | ||
{ | ||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] | ||
internal sealed partial class __RedisClientOptionsValidator__ | ||
{ | ||
/// <summary> | ||
/// Validates a specific named options instance (or all when <paramref name="name"/> is <see langword="null" />). | ||
/// </summary> | ||
/// <param name="name">The name of the options instance being validated.</param> | ||
/// <param name="options">The options instance.</param> | ||
/// <returns>Validation result.</returns> | ||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] | ||
[System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", | ||
Justification = "The created ValidationContext object is used in a way that never call reflection")] | ||
public static global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Test.RedisClientOptions options) | ||
{ | ||
global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; | ||
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); | ||
var validationResults = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationResult>(); | ||
var validationAttributes = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationAttribute>(1); | ||
|
||
context.MemberName = "EndPoints"; | ||
context.DisplayName = string.IsNullOrEmpty(name) ? "RedisClientOptions.EndPoints" : $"{name}.EndPoints"; | ||
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); | ||
if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.EndPoints, context, validationResults, validationAttributes)) | ||
{ | ||
(builder ??= new()).AddResults(validationResults); | ||
} | ||
|
||
if (options.EndPoints is not null) | ||
{ | ||
var count = 0; | ||
foreach (var o in options.EndPoints) | ||
{ | ||
if (o is not null) | ||
{ | ||
(builder ??= new()).AddResult(global::Test.__EndPointsOptionsValidator__.Validate(string.IsNullOrEmpty(name) ? $"RedisClientOptions.EndPoints[{count}]" : $"{name}.EndPoints[{count}]", o)); | ||
} | ||
else | ||
{ | ||
(builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"RedisClientOptions.EndPoints[{count}] is null" : $"{name}.EndPoints[{count}] is null"); | ||
} | ||
count++; | ||
} | ||
} | ||
|
||
return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); | ||
} | ||
} | ||
} | ||
namespace Test | ||
{ | ||
partial class RedisNamedClientOptions | ||
{ | ||
/// <summary> | ||
/// Validates a specific named options instance (or all when <paramref name="name"/> is <see langword="null" />). | ||
/// </summary> | ||
/// <param name="name">The name of the options instance being validated.</param> | ||
/// <param name="options">The options instance.</param> | ||
/// <returns>Validation result.</returns> | ||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] | ||
[System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessage("Trimming", "IL2026:RequiresUnreferencedCode", | ||
Justification = "The created ValidationContext object is used in a way that never call reflection")] | ||
public global::Microsoft.Extensions.Options.ValidateOptionsResult Validate(string? name, global::Test.RedisNamedClientOptions options) | ||
{ | ||
global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null; | ||
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options); | ||
var validationResults = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationResult>(); | ||
var validationAttributes = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationAttribute>(1); | ||
|
||
context.MemberName = "RedisClientOptionsList"; | ||
context.DisplayName = string.IsNullOrEmpty(name) ? "RedisNamedClientOptions.RedisClientOptionsList" : $"{name}.RedisClientOptionsList"; | ||
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1); | ||
if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.RedisClientOptionsList, context, validationResults, validationAttributes)) | ||
{ | ||
(builder ??= new()).AddResults(validationResults); | ||
} | ||
|
||
if (options.RedisClientOptionsList is not null) | ||
{ | ||
var count = 0; | ||
foreach (var o in options.RedisClientOptionsList) | ||
{ | ||
if (o is not null) | ||
{ | ||
(builder ??= new()).AddResult(global::Test.__RedisClientOptionsValidator__.Validate(string.IsNullOrEmpty(name) ? $"RedisNamedClientOptions.RedisClientOptionsList[{count}]" : $"{name}.RedisClientOptionsList[{count}]", o)); | ||
} | ||
else | ||
{ | ||
(builder ??= new()).AddError(string.IsNullOrEmpty(name) ? $"RedisNamedClientOptions.RedisClientOptionsList[{count}] is null" : $"{name}.RedisClientOptionsList[{count}] is null"); | ||
} | ||
count++; | ||
} | ||
} | ||
|
||
return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build(); | ||
} | ||
} | ||
} | ||
namespace __OptionValidationStaticInstances | ||
{ | ||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] | ||
file static class __Attributes | ||
{ | ||
internal static readonly global::System.ComponentModel.DataAnnotations.RequiredAttribute A1 = new global::System.ComponentModel.DataAnnotations.RequiredAttribute(); | ||
|
||
internal static readonly __OptionValidationGeneratedAttributes.__SourceGen__RangeAttribute A2 = new __OptionValidationGeneratedAttributes.__SourceGen__RangeAttribute( | ||
(int)1024, | ||
(int)65535); | ||
} | ||
} | ||
namespace __OptionValidationStaticInstances | ||
{ | ||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] | ||
file static class __Validators | ||
{ | ||
} | ||
} | ||
namespace __OptionValidationGeneratedAttributes | ||
{ | ||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.Extensions.Options.SourceGeneration", "42.42.42.42")] | ||
[global::System.AttributeUsage(global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Parameter, AllowMultiple = false)] | ||
file class __SourceGen__RangeAttribute : global::System.ComponentModel.DataAnnotations.ValidationAttribute | ||
{ | ||
public __SourceGen__RangeAttribute(int minimum, int maximum) : base() | ||
{ | ||
Minimum = minimum; | ||
Maximum = maximum; | ||
OperandType = typeof(int); | ||
} | ||
public __SourceGen__RangeAttribute(double minimum, double maximum) : base() | ||
{ | ||
Minimum = minimum; | ||
Maximum = maximum; | ||
OperandType = typeof(double); | ||
} | ||
public __SourceGen__RangeAttribute(global::System.Type type, string minimum, string maximum) : base() | ||
{ | ||
OperandType = type; | ||
NeedToConvertMinMax = true; | ||
Minimum = minimum; | ||
Maximum = maximum; | ||
} | ||
public object Minimum { get; private set; } | ||
public object Maximum { get; private set; } | ||
public bool MinimumIsExclusive { get; set; } | ||
public bool MaximumIsExclusive { get; set; } | ||
public global::System.Type OperandType { get; } | ||
public bool ParseLimitsInInvariantCulture { get; set; } | ||
public bool ConvertValueInInvariantCulture { get; set; } | ||
public override string FormatErrorMessage(string name) => | ||
string.Format(global::System.Globalization.CultureInfo.CurrentCulture, GetValidationErrorMessage(), name, Minimum, Maximum); | ||
private bool NeedToConvertMinMax { get; } | ||
private bool Initialized { get; set; } | ||
private const string c_minMaxError = "The minimum and maximum values must be set to valid values."; | ||
|
||
public override bool IsValid(object? value) | ||
{ | ||
if (!Initialized) | ||
{ | ||
if (Minimum is null || Maximum is null) | ||
{ | ||
throw new global::System.InvalidOperationException(c_minMaxError); | ||
} | ||
if (NeedToConvertMinMax) | ||
{ | ||
System.Globalization.CultureInfo culture = ParseLimitsInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; | ||
Minimum = ConvertValue(Minimum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); | ||
Maximum = ConvertValue(Maximum, culture) ?? throw new global::System.InvalidOperationException(c_minMaxError); | ||
} | ||
int cmp = ((global::System.IComparable)Minimum).CompareTo((global::System.IComparable)Maximum); | ||
if (cmp > 0) | ||
{ | ||
throw new global::System.InvalidOperationException("The maximum value '{Maximum}' must be greater than or equal to the minimum value '{Minimum}'."); | ||
} | ||
else if (cmp == 0 && (MinimumIsExclusive || MaximumIsExclusive)) | ||
{ | ||
throw new global::System.InvalidOperationException("Cannot use exclusive bounds when the maximum value is equal to the minimum value."); | ||
} | ||
Initialized = true; | ||
} | ||
|
||
if (value is null or string { Length: 0 }) | ||
{ | ||
return true; | ||
} | ||
|
||
System.Globalization.CultureInfo formatProvider = ConvertValueInInvariantCulture ? global::System.Globalization.CultureInfo.InvariantCulture : global::System.Globalization.CultureInfo.CurrentCulture; | ||
object? convertedValue; | ||
|
||
try | ||
{ | ||
convertedValue = ConvertValue(value, formatProvider); | ||
} | ||
catch (global::System.Exception e) when (e is global::System.FormatException or global::System.InvalidCastException or global::System.NotSupportedException) | ||
{ | ||
return false; | ||
} | ||
|
||
var min = (global::System.IComparable)Minimum; | ||
var max = (global::System.IComparable)Maximum; | ||
|
||
return | ||
(MinimumIsExclusive ? min.CompareTo(convertedValue) < 0 : min.CompareTo(convertedValue) <= 0) && | ||
(MaximumIsExclusive ? max.CompareTo(convertedValue) > 0 : max.CompareTo(convertedValue) >= 0); | ||
} | ||
private string GetValidationErrorMessage() | ||
{ | ||
return (MinimumIsExclusive, MaximumIsExclusive) switch | ||
{ | ||
(false, false) => "The field {0} must be between {1} and {2}.", | ||
(true, false) => "The field {0} must be between {1} exclusive and {2}.", | ||
(false, true) => "The field {0} must be between {1} and {2} exclusive.", | ||
(true, true) => "The field {0} must be between {1} exclusive and {2} exclusive.", | ||
}; | ||
} | ||
private object? ConvertValue(object? value, System.Globalization.CultureInfo formatProvider) | ||
{ | ||
if (value is string stringValue) | ||
{ | ||
value = global::System.Convert.ChangeType(stringValue, OperandType, formatProvider); | ||
} | ||
else | ||
{ | ||
value = global::System.Convert.ChangeType(value, OperandType, formatProvider); | ||
} | ||
return value; | ||
} | ||
} | ||
} |
Oops, something went wrong.