File: Marshalling\ByValueMarshalKindSupportDescriptor.cs
Web Access
Project: src\src\libraries\System.Runtime.InteropServices\gen\Microsoft.Interop.SourceGeneration\Microsoft.Interop.SourceGeneration.csproj (Microsoft.Interop.SourceGeneration)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Immutable;
using System.Diagnostics;
 
namespace Microsoft.Interop
{
    public record struct ByValueMarshalKindSupportInfo(ByValueMarshalKindSupport Support, string? details)
    {
        public ByValueMarshalKindSupport GetSupport(TypePositionInfo info, out GeneratorDiagnostic? diagnostic)
        {
            diagnostic = Support switch
            {
                ByValueMarshalKindSupport.Supported => null,
                ByValueMarshalKindSupport.NotRecommended =>
                    new GeneratorDiagnostic.NotRecommended(info)
                    {
                        Details = details
                    },
                ByValueMarshalKindSupport.Unnecessary =>
                    new GeneratorDiagnostic.UnnecessaryData(
                           info,
                           ImmutableArray.Create(info.ByValueMarshalAttributeLocations.OutLocation))
                    {
                        UnnecessaryDataName = SR.InOutAttributes,
                        UnnecessaryDataDetails = details
                    },
                ByValueMarshalKindSupport.NotSupported =>
                    new GeneratorDiagnostic.NotSupported(info)
                    {
                        NotSupportedDetails = details
                    },
                _ => throw new UnreachableException()
            };
            return Support;
        }
    }
 
    /// <summary>
    /// Provides an implementation of <see cref="IUnboundMarshallingGenerator.SupportsByValueMarshalKind(ByValueContentsMarshalKind, TypePositionInfo, out GeneratorDiagnostic?)"/> through <see cref="GetSupport(ByValueContentsMarshalKind, TypePositionInfo, out GeneratorDiagnostic?)"/>
    /// </summary>
    public record ByValueMarshalKindSupportDescriptor(
        ByValueMarshalKindSupportInfo DefaultSupport,
        ByValueMarshalKindSupportInfo InSupport,
        ByValueMarshalKindSupportInfo OutSupport,
        ByValueMarshalKindSupportInfo InOutSupport)
    {
        /// <summary>
        /// A default <see cref="ByValueMarshalKindSupportDescriptor"/> for by value parameters. [In] is allowed, but unnecessary. Out is not allowed.
        /// </summary>
        public static readonly ByValueMarshalKindSupportDescriptor Default = new ByValueMarshalKindSupportDescriptor(
            DefaultSupport: new(ByValueMarshalKindSupport.Supported, null),
            InSupport: new(ByValueMarshalKindSupport.NotSupported, SR.InAttributeNotSupportedOnByValueParameters),
            OutSupport: new(ByValueMarshalKindSupport.NotSupported, SR.OutAttributeNotSupportedOnByValueParameters),
            InOutSupport: new(ByValueMarshalKindSupport.NotSupported, SR.InOutAttributeNotSupportedOnByValueParameters));
 
        /// <summary>
        /// A default <see cref="ByValueMarshalKindSupportDescriptor"/> for by value array parameters. Default is allowed, but Not Recommended. [In], [Out], and [In, Out] are allowed
        /// </summary>
        public static readonly ByValueMarshalKindSupportDescriptor ArrayParameter = new ByValueMarshalKindSupportDescriptor(
            DefaultSupport: new(ByValueMarshalKindSupport.NotRecommended, SR.PreferExplicitInOutAttributesOnArrays),
            InSupport: new(ByValueMarshalKindSupport.Supported, null),
            OutSupport: new(ByValueMarshalKindSupport.Supported, null),
            InOutSupport: new(ByValueMarshalKindSupport.Supported, null));
 
        /// <summary>
        /// Returns the support for the ByValueContentsMarshalKind, and if it is not <see cref="ByValueMarshalKindSupport.Supported"/>, diagnostic is not null
        /// </summary>
        public ByValueMarshalKindSupport GetSupport(ByValueContentsMarshalKind marshalKind, TypePositionInfo info, out GeneratorDiagnostic? diagnostic)
        {
            if (info.IsByRef)
            {
                // ByRef with ByValue attributes is not allowed
                if (marshalKind != ByValueContentsMarshalKind.Default)
                {
                    diagnostic = new GeneratorDiagnostic.NotSupported(info)
                    {
                        NotSupportedDetails = SR.InOutAttributeByRefNotSupported
                    };
                    return ByValueMarshalKindSupport.NotSupported;
                }
                // ByRef with no ByValue attributes is supported
                diagnostic = null;
                return ByValueMarshalKindSupport.Supported;
            }
            // Return can never have In or Out attributes, so can assume valid ByValue attributes
            if (info.ManagedIndex < 0)
            {
                Debug.Assert(marshalKind is ByValueContentsMarshalKind.Default);
                diagnostic = null;
                return ByValueMarshalKindSupport.Supported;
            }
 
            return marshalKind switch
            {
                ByValueContentsMarshalKind.Default => DefaultSupport.GetSupport(info, out diagnostic),
                ByValueContentsMarshalKind.In => InSupport.GetSupport(info, out diagnostic),
                ByValueContentsMarshalKind.Out => OutSupport.GetSupport(info, out diagnostic),
                ByValueContentsMarshalKind.InOut => InOutSupport.GetSupport(info, out diagnostic),
                _ => throw new UnreachableException()
            };
        }
    }
}