Skip to content

Commit

Permalink
Avoid generating internal static classes with constant names in Optio…
Browse files Browse the repository at this point in the history
…ns Source gen (#89148)
  • Loading branch information
tarekgh authored Jul 19, 2023
1 parent de1a93a commit d051a84
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 95 deletions.
42 changes: 32 additions & 10 deletions src/libraries/Microsoft.Extensions.Options/gen/Emitter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Microsoft.Extensions.Options.Generators
{
Expand All @@ -13,17 +15,37 @@ namespace Microsoft.Extensions.Options.Generators
/// </summary>
internal sealed class Emitter : EmitterBase
{
private const string StaticValidationAttributeHolderClassName = "__Attributes";
private const string StaticValidatorHolderClassName = "__Validators";
private const string StaticFieldHolderClassesNamespace = "__OptionValidationStaticInstances";
private const string StaticValidationAttributeHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{StaticValidationAttributeHolderClassName}";
private const string StaticValidatorHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{StaticValidatorHolderClassName}";
private const string StaticListType = "global::System.Collections.Generic.List";
private const string StaticValidationResultType = "global::System.ComponentModel.DataAnnotations.ValidationResult";
private const string StaticValidationAttributeType = "global::System.ComponentModel.DataAnnotations.ValidationAttribute";

private string _staticValidationAttributeHolderClassName = "__Attributes";
private string _staticValidatorHolderClassName = "__Validators";
private string _staticValidationAttributeHolderClassFQN;
private string _staticValidatorHolderClassFQN;
private string _modifier;

private sealed record StaticFieldInfo(string FieldTypeFQN, int FieldOrder, string FieldName, IList<string> InstantiationLines);

public Emitter(Compilation compilation, bool emitPreamble = true) : base(emitPreamble)
{
if (((CSharpCompilation)compilation).LanguageVersion >= Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp11)
{
_modifier = "file";
}
else
{
_modifier = "internal";
string suffix = $"_{new Random().Next():X8}";
_staticValidationAttributeHolderClassName += suffix;
_staticValidatorHolderClassName += suffix;
}

_staticValidationAttributeHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{_staticValidationAttributeHolderClassName}";
_staticValidatorHolderClassFQN = $"global::{StaticFieldHolderClassesNamespace}.{_staticValidatorHolderClassName}";
}

public string Emit(
IEnumerable<ValidatorType> validatorTypes,
CancellationToken cancellationToken)
Expand All @@ -37,8 +59,8 @@ public string Emit(
GenValidatorType(vt, ref staticValidationAttributesDict, ref staticValidatorsDict);
}

GenStaticClassWithStaticReadonlyFields(staticValidationAttributesDict.Values, StaticFieldHolderClassesNamespace, StaticValidationAttributeHolderClassName);
GenStaticClassWithStaticReadonlyFields(staticValidatorsDict.Values, StaticFieldHolderClassesNamespace, StaticValidatorHolderClassName);
GenStaticClassWithStaticReadonlyFields(staticValidationAttributesDict.Values, StaticFieldHolderClassesNamespace, _staticValidationAttributeHolderClassName);
GenStaticClassWithStaticReadonlyFields(staticValidatorsDict.Values, StaticFieldHolderClassesNamespace, _staticValidatorHolderClassName);

return Capture();
}
Expand Down Expand Up @@ -95,7 +117,7 @@ private void GenStaticClassWithStaticReadonlyFields(IEnumerable<StaticFieldInfo>
OutOpenBrace();

OutGeneratedCodeAttribute();
OutLn($"internal static class {className}");
OutLn($"{_modifier} static class {className}");
OutOpenBrace();

var staticValidationAttributes = staticFields
Expand Down Expand Up @@ -214,7 +236,7 @@ private void GenMemberValidation(ValidatedMember vm, ref Dictionary<string, Stat
foreach (var attr in vm.ValidationAttributes)
{
var staticValidationAttributeInstance = GetOrAddStaticValidationAttribute(ref staticValidationAttributesDict, attr);
OutLn($"validationAttributes.Add({StaticValidationAttributeHolderClassFQN}.{staticValidationAttributeInstance.FieldName});");
OutLn($"validationAttributes.Add({_staticValidationAttributeHolderClassFQN}.{staticValidationAttributeInstance.FieldName});");
}

OutLn($"if (!global::System.ComponentModel.DataAnnotations.Validator.TryValidateValue(options.{vm.Name}!, context, validationResults, validationAttributes))");
Expand Down Expand Up @@ -294,7 +316,7 @@ private void GenTransitiveValidation(ValidatedMember vm, ref Dictionary<string,
{
var staticValidatorInstance = GetOrAddStaticValidator(ref staticValidatorsDict, vm.TransValidatorType!);

callSequence = $"{StaticValidatorHolderClassFQN}.{staticValidatorInstance.FieldName}";
callSequence = $"{_staticValidatorHolderClassFQN}.{staticValidatorInstance.FieldName}";
}

var valueAccess = (vm.IsNullable && vm.IsValueType) ? ".Value" : string.Empty;
Expand Down Expand Up @@ -325,7 +347,7 @@ private void GenEnumerationValidation(ValidatedMember vm, ref Dictionary<string,
{
var staticValidatorInstance = GetOrAddStaticValidator(ref staticValidatorsDict, vm.EnumerationValidatorType!);

callSequence = $"{StaticValidatorHolderClassFQN}.{staticValidatorInstance.FieldName}";
callSequence = $"{_staticValidatorHolderClassFQN}.{staticValidatorInstance.FieldName}";
}

if (vm.IsNullable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ private static void HandleAnnotatedTypes(Compilation compilation, ImmutableArray
var validatorTypes = parser.GetValidatorTypes(types);
if (validatorTypes.Count > 0)
{
var emitter = new Emitter();
var emitter = new Emitter(compilation);
var result = emitter.Emit(validatorTypes, context.CancellationToken);

context.AddSource("Validators.g.cs", SourceText.From(result, Encoding.UTF8));
Expand Down
Loading

0 comments on commit d051a84

Please sign in to comment.