Skip to content

Commit 9215568

Browse files
Copilotstephentoubtarekgh
authored
Fix Options validation source generator to exclude instance name from error messages (#121030)
Successfully fixed the Options validation source generator to produce error messages that match standard DataAnnotations behavior. Updated all baseline files including those in both SourceGenerationTests and SourceGeneration.Unit.Tests directories. --------- Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: stephentoub <[email protected]> Co-authored-by: tarekgh <[email protected]>
1 parent 54689bc commit 9215568

14 files changed

+425
-543
lines changed

src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -653,12 +653,12 @@ private void GenValidationAttributesClasses()
653653
OutCloseBrace();
654654
}
655655

656-
private void GenModelSelfValidationIfNecessary(ValidatedModel modelToValidate, string modelName)
656+
private void GenModelSelfValidationIfNecessary(ValidatedModel modelToValidate)
657657
{
658658
if (modelToValidate.SelfValidates)
659659
{
660660
OutLn($"context.MemberName = \"Validate\";");
661-
OutLn($"context.DisplayName = string.IsNullOrEmpty(name) ? \"{modelName}.Validate\" : $\"{{name}}.Validate\";");
661+
OutLn($"context.DisplayName = string.IsNullOrEmpty(name) ? \"Validate\" : $\"{{name}}.Validate\";");
662662
OutLn($"(builder ??= new()).AddResults(((global::System.ComponentModel.DataAnnotations.IValidatableObject)options).Validate(context));");
663663
OutLn();
664664
}
@@ -693,8 +693,7 @@ private void GenModelValidationMethod(
693693
OutOpenBrace();
694694
OutLn($"global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null;");
695695
OutLn("#if NET10_0_OR_GREATER");
696-
OutLn($"string displayName = string.IsNullOrEmpty(name) ? \"{modelToValidate.SimpleName}.Validate\" : $\"{{name}}.Validate\";");
697-
OutLn($"var context = new {StaticValidationContextType}(options, displayName, null, null);");
696+
OutLn($"var context = new {StaticValidationContextType}(options, \"{modelToValidate.SimpleName}\", null, null);");
698697
OutLn("#else");
699698
OutLn($"var context = new {StaticValidationContextType}(options);");
700699
OutLn("#endif");
@@ -712,33 +711,33 @@ private void GenModelValidationMethod(
712711
{
713712
if (vm.ValidationAttributes.Count > 0)
714713
{
715-
GenMemberValidation(vm, modelToValidate.SimpleName, ref staticValidationAttributesDict, cleanListsBeforeUse);
714+
GenMemberValidation(vm, ref staticValidationAttributesDict, cleanListsBeforeUse);
716715
cleanListsBeforeUse = true;
717716
OutLn();
718717
}
719718

720719
if (vm.TransValidatorType is not null)
721720
{
722-
GenTransitiveValidation(vm, modelToValidate.SimpleName, ref staticValidatorsDict);
721+
GenTransitiveValidation(vm, ref staticValidatorsDict);
723722
OutLn();
724723
}
725724

726725
if (vm.EnumerationValidatorType is not null)
727726
{
728-
GenEnumerationValidation(vm, modelToValidate.SimpleName, ref staticValidatorsDict);
727+
GenEnumerationValidation(vm, ref staticValidatorsDict);
729728
OutLn();
730729
}
731730
}
732731

733-
GenModelSelfValidationIfNecessary(modelToValidate, modelToValidate.SimpleName);
732+
GenModelSelfValidationIfNecessary(modelToValidate);
734733
OutLn($"return builder is null ? global::Microsoft.Extensions.Options.ValidateOptionsResult.Success : builder.Build();");
735734
OutCloseBrace();
736735
}
737736

738-
private void GenMemberValidation(ValidatedMember vm, string modelName, ref Dictionary<string, StaticFieldInfo> staticValidationAttributesDict, bool cleanListsBeforeUse)
737+
private void GenMemberValidation(ValidatedMember vm, ref Dictionary<string, StaticFieldInfo> staticValidationAttributesDict, bool cleanListsBeforeUse)
739738
{
740739
OutLn($"context.MemberName = \"{vm.Name}\";");
741-
OutLn($"context.DisplayName = string.IsNullOrEmpty(name) ? \"{modelName}.{vm.Name}\" : $\"{{name}}.{vm.Name}\";");
740+
OutLn($"context.DisplayName = string.IsNullOrEmpty(name) ? \"{vm.Name}\" : $\"{{name}}.{vm.Name}\";");
742741

743742
if (cleanListsBeforeUse)
744743
{
@@ -818,7 +817,7 @@ private StaticFieldInfo GetOrAddStaticValidationAttribute(ref Dictionary<string,
818817
return staticValidationAttributeInstance;
819818
}
820819

821-
private void GenTransitiveValidation(ValidatedMember vm, string modelName, ref Dictionary<string, StaticFieldInfo> staticValidatorsDict)
820+
private void GenTransitiveValidation(ValidatedMember vm, ref Dictionary<string, StaticFieldInfo> staticValidatorsDict)
822821
{
823822
string callSequence;
824823
if (vm.TransValidateTypeIsSynthetic)
@@ -834,7 +833,7 @@ private void GenTransitiveValidation(ValidatedMember vm, string modelName, ref D
834833

835834
var valueAccess = (vm.IsNullable && vm.IsValueType) ? ".Value" : string.Empty;
836835

837-
var baseName = $"string.IsNullOrEmpty(name) ? \"{modelName}.{vm.Name}\" : $\"{{name}}.{vm.Name}\"";
836+
var baseName = $"string.IsNullOrEmpty(name) ? \"{vm.Name}\" : $\"{{name}}.{vm.Name}\"";
838837

839838
if (vm.IsNullable)
840839
{
@@ -849,7 +848,7 @@ private void GenTransitiveValidation(ValidatedMember vm, string modelName, ref D
849848
}
850849
}
851850

852-
private void GenEnumerationValidation(ValidatedMember vm, string modelName, ref Dictionary<string, StaticFieldInfo> staticValidatorsDict)
851+
private void GenEnumerationValidation(ValidatedMember vm, ref Dictionary<string, StaticFieldInfo> staticValidatorsDict)
853852
{
854853
var valueAccess = (vm.IsValueType && vm.IsNullable) ? ".Value" : string.Empty;
855854
var enumeratedValueAccess = (vm.EnumeratedIsNullable && vm.EnumeratedIsValueType) ? ".Value" : string.Empty;
@@ -880,15 +879,15 @@ private void GenEnumerationValidation(ValidatedMember vm, string modelName, ref
880879
{
881880
OutLn($"if (o is not null)");
882881
OutOpenBrace();
883-
var propertyName = $"string.IsNullOrEmpty(name) ? $\"{modelName}.{vm.Name}[{{count}}]\" : $\"{{name}}.{vm.Name}[{{count}}]\"";
882+
var propertyName = $"string.IsNullOrEmpty(name) ? $\"{vm.Name}[{{count}}]\" : $\"{{name}}.{vm.Name}[{{count}}]\"";
884883
OutLn($"(builder ??= new()).AddResult({callSequence}.Validate({propertyName}, o{enumeratedValueAccess}));");
885884
OutCloseBrace();
886885

887886
if (!vm.EnumeratedMayBeNull)
888887
{
889888
OutLn($"else");
890889
OutOpenBrace();
891-
var error = $"string.IsNullOrEmpty(name) ? $\"{modelName}.{vm.Name}[{{count}}] is null\" : $\"{{name}}.{vm.Name}[{{count}}] is null\"";
890+
var error = $"string.IsNullOrEmpty(name) ? $\"{vm.Name}[{{count}}] is null\" : $\"{{name}}.{vm.Name}[{{count}}] is null\"";
892891
OutLn($"(builder ??= new()).AddError({error});");
893892
OutCloseBrace();
894893
}
@@ -897,7 +896,7 @@ private void GenEnumerationValidation(ValidatedMember vm, string modelName, ref
897896
}
898897
else
899898
{
900-
var propertyName = $"string.IsNullOrEmpty(name) ? $\"{modelName}.{vm.Name}[{{count++}}] is null\" : $\"{{name}}.{vm.Name}[{{count++}}] is null\"";
899+
var propertyName = $"string.IsNullOrEmpty(name) ? $\"{vm.Name}[{{count++}}]\" : $\"{{name}}.{vm.Name}[{{count++}}]\"";
901900
OutLn($"(builder ??= new()).AddResult({callSequence}.Validate({propertyName}, o{enumeratedValueAccess}));");
902901
}
903902

src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/DataAnnotationAttributesWithParams.g.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,23 @@ partial class MyOptionsValidator
2121
{
2222
global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null;
2323
#if NET10_0_OR_GREATER
24-
string displayName = string.IsNullOrEmpty(name) ? "MyOptions.Validate" : $"{name}.Validate";
25-
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, displayName, null, null);
24+
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "MyOptions", null, null);
2625
#else
2726
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options);
2827
#endif
2928
var validationResults = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationResult>();
3029
var validationAttributes = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationAttribute>(1);
3130

3231
context.MemberName = "P1";
33-
context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.P1" : $"{name}.P1";
32+
context.DisplayName = string.IsNullOrEmpty(name) ? "P1" : $"{name}.P1";
3433
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1);
3534
if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.P1, context, validationResults, validationAttributes))
3635
{
3736
(builder ??= new()).AddResults(validationResults);
3837
}
3938

4039
context.MemberName = "P2";
41-
context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.P2" : $"{name}.P2";
40+
context.DisplayName = string.IsNullOrEmpty(name) ? "P2" : $"{name}.P2";
4241
validationResults.Clear();
4342
validationAttributes.Clear();
4443
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2);
@@ -48,7 +47,7 @@ partial class MyOptionsValidator
4847
}
4948

5049
context.MemberName = "P3";
51-
context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.P3" : $"{name}.P3";
50+
context.DisplayName = string.IsNullOrEmpty(name) ? "P3" : $"{name}.P3";
5251
validationResults.Clear();
5352
validationAttributes.Clear();
5453
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A3);
@@ -58,7 +57,7 @@ partial class MyOptionsValidator
5857
}
5958

6059
context.MemberName = "P4";
61-
context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.P4" : $"{name}.P4";
60+
context.DisplayName = string.IsNullOrEmpty(name) ? "P4" : $"{name}.P4";
6261
validationResults.Clear();
6362
validationAttributes.Clear();
6463
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A4);

src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netcore.g.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,23 @@ partial struct MyOptionsValidator
2121
{
2222
global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null;
2323
#if NET10_0_OR_GREATER
24-
string displayName = string.IsNullOrEmpty(name) ? "MyOptions.Validate" : $"{name}.Validate";
25-
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, displayName, null, null);
24+
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "MyOptions", null, null);
2625
#else
2726
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options);
2827
#endif
2928
var validationResults = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationResult>();
3029
var validationAttributes = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationAttribute>(1);
3130

3231
context.MemberName = "Val1";
33-
context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.Val1" : $"{name}.Val1";
32+
context.DisplayName = string.IsNullOrEmpty(name) ? "Val1" : $"{name}.Val1";
3433
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1);
3534
if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes))
3635
{
3736
(builder ??= new()).AddResults(validationResults);
3837
}
3938

4039
context.MemberName = "Val2";
41-
context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.Val2" : $"{name}.Val2";
40+
context.DisplayName = string.IsNullOrEmpty(name) ? "Val2" : $"{name}.Val2";
4241
validationResults.Clear();
4342
validationAttributes.Clear();
4443
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2);

src/libraries/Microsoft.Extensions.Options/tests/SourceGeneration.Unit.Tests/Baselines/EmitterWithCustomValidator.netfx.g.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,23 @@ partial struct MyOptionsValidator
1717
{
1818
global::Microsoft.Extensions.Options.ValidateOptionsResultBuilder? builder = null;
1919
#if NET10_0_OR_GREATER
20-
string displayName = string.IsNullOrEmpty(name) ? "MyOptions.Validate" : $"{name}.Validate";
21-
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, displayName, null, null);
20+
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options, "MyOptions", null, null);
2221
#else
2322
var context = new global::System.ComponentModel.DataAnnotations.ValidationContext(options);
2423
#endif
2524
var validationResults = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationResult>();
2625
var validationAttributes = new global::System.Collections.Generic.List<global::System.ComponentModel.DataAnnotations.ValidationAttribute>(1);
2726

2827
context.MemberName = "Val1";
29-
context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.Val1" : $"{name}.Val1";
28+
context.DisplayName = string.IsNullOrEmpty(name) ? "Val1" : $"{name}.Val1";
3029
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A1);
3130
if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.Val1, context, validationResults, validationAttributes))
3231
{
3332
(builder ??= new()).AddResults(validationResults);
3433
}
3534

3635
context.MemberName = "Val2";
37-
context.DisplayName = string.IsNullOrEmpty(name) ? "MyOptions.Val2" : $"{name}.Val2";
36+
context.DisplayName = string.IsNullOrEmpty(name) ? "Val2" : $"{name}.Val2";
3837
validationResults.Clear();
3938
validationAttributes.Clear();
4039
validationAttributes.Add(global::__OptionValidationStaticInstances.__Attributes.A2);

0 commit comments

Comments
 (0)