Repository: dotnet/aspnetcore
File: src/Validation/gen/Parsers/ValidationsGenerator.TypesParser.cs (C#)

Code before:

        // Extract the validatable types discovered in the JsonDerivedTypeAttributes of this type and add them to the top-level list.
        var derivedTypes = typeSymbol.GetJsonDerivedTypes(wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_Text_Json_Serialization_JsonDerivedTypeAttribute));
        var hasValidatableDerivedTypes = false;
        foreach (var derivedType in derivedTypes ?? [])
        {
            hasValidatableDerivedTypes |= TryExtractValidatableType(derivedType, wellKnownTypes, ref validatableTypes, ref visitedTypes);
        }

        // No validatable members or derived types found, so we don't need to add this type.
        if (members.IsDefaultOrEmpty && !hasValidatableBaseType && !hasValidatableDerivedTypes)
        {
            return false;
        }

        // Add the type itself as a validatable type itself.
        validatableTypes.Add(new ValidatableType(
            Type: typeSymbol,
            Members: members));

        return true;
    }

    private static bool IsEqualityContract(IPropertySymbol prop) =>
        prop.Name == "EqualityContract"
        && prop.Type.ToDisplayString() == "System.Type"
        && prop.DeclaredAccessibility == Accessibility.Protected;

    internal ImmutableArray<ValidatableProperty> ExtractValidatableMembers(ITypeSymbol typeSymbol, WellKnownTypes wellKnownTypes, ref HashSet<ValidatableType> validatableTypes, ref List<ITypeSymbol> visitedTypes)
    {
        var members = new List<ValidatableProperty>();
        var resolvedRecordProperty = new List<IPropertySymbol>();

        // Special handling for record types to extract properties from
        // the primary constructor.
        if (typeSymbol is INamedTypeSymbol { IsRecord: true } namedType)
        {
            // Find the primary constructor for the record, account
            // for members that are in base types to account for
            // record inheritance scenarios
            var primaryConstructor = namedType.Constructors
                .FirstOrDefault(c => c.Parameters.Length > 0 && c.Parameters.All(p =>
                    namedType.FindPropertyIncludingBaseTypes(p.Name) != null));

            if (primaryConstructor != null)
            {
                // Process all parameters in constructor order to maintain parameter ordering
                foreach (var parameter in primaryConstructor.Parameters)
                {
                    // Find the corresponding property in this type, we ignore
                    // base types here since that will be handled by the inheritance

Review comment (suggestion):
Add System.Type to https://github.com/dotnet/aspnetcore/blob/main/src/Shared/RoslynUtils/WellKnownTypeData.cs then use WellKnownTypes to do the type comparison here.

Code after:

        // Extract the validatable types discovered in the JsonDerivedTypeAttributes of this type and add them to the top-level list.
        var derivedTypes = typeSymbol.GetJsonDerivedTypes(wellKnownTypes.Get(WellKnownTypeData.WellKnownType.System_Text_Json_Serialization_JsonDerivedTypeAttribute));
        var hasValidatableDerivedTypes = false;
        foreach (var derivedType in derivedTypes ?? [])
        {
            hasValidatableDerivedTypes |= TryExtractValidatableType(derivedType, wellKnownTypes, ref validatableTypes, ref visitedTypes);
        }

        // No validatable members or derived types found, so we don't need to add this type.
        if (members.IsDefaultOrEmpty && !hasValidatableBaseType && !hasValidatableDerivedTypes)
        {
            return false;
        }

        // Add the type itself as a validatable type itself.
        validatableTypes.Add(new ValidatableType(
            Type: typeSymbol,
            Members: members));

        return true;
    }

    internal ImmutableArray<ValidatableProperty> ExtractValidatableMembers(ITypeSymbol typeSymbol, WellKnownTypes wellKnownTypes, ref HashSet<ValidatableType> validatableTypes, ref List<ITypeSymbol> visitedTypes)
    {
        var members = new List<ValidatableProperty>();
        var resolvedRecordProperty = new List<IPropertySymbol>();

        // Special handling for record types to extract properties from
        // the primary constructor.
        if (typeSymbol is INamedTypeSymbol { IsRecord: true } namedType)
        {
            // Find the primary constructor for the record, account
            // for members that are in base types to account for
            // record inheritance scenarios
            var primaryConstructor = namedType.Constructors
                .FirstOrDefault(c => c.Parameters.Length > 0 && c.Parameters.All(p =>
                    namedType.FindPropertyIncludingBaseTypes(p.Name) != null));

            if (primaryConstructor != null)
            {
                // Process all parameters in constructor order to maintain parameter ordering
                foreach (var parameter in primaryConstructor.Parameters)
                {
                    // Find the corresponding property in this type, we ignore
                    // base types here since that will be handled by the inheritance
                    // checks in the default ValidatableTypeInfo implementation.
                    var correspondingProperty = typeSymbol.GetMembers()
                        .OfType<IPropertySymbol>()
                        .FirstOrDefault(p => string.Equals(p.Name, parameter.Name, System.StringComparison.OrdinalIgnoreCase));