File: InteropAttributeData.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 Microsoft.CodeAnalysis;
 
namespace Microsoft.Interop
{
    /// <summary>
    /// Flags used to indicate members on source-generated interop attributes.
    /// </summary>
    [Flags]
    public enum InteropAttributeMember
    {
        None = 0,
        SetLastError = 1 << 0,
        StringMarshalling = 1 << 1,
        StringMarshallingCustomType = 1 << 2,
        All = ~None
    }
 
    /// <summary>
    /// Common data for all source-generated-interop trigger attributes.
    /// This type and derived types should not have any reference that would keep a compilation alive.
    /// </summary>
    public record InteropAttributeData
    {
        /// <summary>
        /// Value set by the user on the original declaration.
        /// </summary>
        public InteropAttributeMember IsUserDefined { get; init; }
        public bool SetLastError { get; init; }
        public StringMarshalling StringMarshalling { get; init; }
        public ManagedTypeInfo? StringMarshallingCustomType { get; init; }
    }
 
    /// <summary>
    /// Common data for all source-generated-interop trigger attributes that also includes a reference to the Roslyn symbol for StringMarshallingCustomType.
    /// See <seealso cref="InteropAttributeData"/> for a type that doesn't keep a compilation alive.
    /// </summary>
    public record InteropAttributeCompilationData
    {
        /// <summary>
        /// Value set by the user on the original declaration.
        /// </summary>
        public InteropAttributeMember IsUserDefined { get; init; }
        public bool SetLastError { get; init; }
        public StringMarshalling StringMarshalling { get; init; }
        public INamedTypeSymbol? StringMarshallingCustomType { get; init; }
    }
 
    public static class InteropAttributeDataExtensions
    {
        public static T WithValuesFromNamedArguments<T>(this T t, ImmutableDictionary<string, TypedConstant> namedArguments) where T : InteropAttributeCompilationData
        {
            InteropAttributeMember userDefinedValues = InteropAttributeMember.None;
            bool setLastError = false;
            StringMarshalling stringMarshalling = StringMarshalling.Custom;
            INamedTypeSymbol? stringMarshallingCustomType = null;
 
            if (namedArguments.TryGetValue(nameof(InteropAttributeCompilationData.SetLastError), out TypedConstant setLastErrorValue))
            {
                userDefinedValues |= InteropAttributeMember.SetLastError;
                if (setLastErrorValue.Value is not bool)
                {
                    return null;
                }
                setLastError = (bool)setLastErrorValue.Value!;
            }
            if (namedArguments.TryGetValue(nameof(InteropAttributeCompilationData.StringMarshalling), out TypedConstant stringMarshallingValue))
            {
                userDefinedValues |= InteropAttributeMember.StringMarshalling;
                // TypedConstant's Value property only contains primitive values.
                if (stringMarshallingValue.Value is not int)
                {
                    return null;
                }
                // A boxed primitive can be unboxed to an enum with the same underlying type.
                stringMarshalling = (StringMarshalling)stringMarshallingValue.Value!;
            }
            if (namedArguments.TryGetValue(nameof(InteropAttributeCompilationData.StringMarshallingCustomType), out TypedConstant stringMarshallingCustomTypeValue))
            {
                userDefinedValues |= InteropAttributeMember.StringMarshallingCustomType;
                if (stringMarshallingCustomTypeValue.Value is not INamedTypeSymbol)
                {
                    return null;
                }
                stringMarshallingCustomType = (INamedTypeSymbol)stringMarshallingCustomTypeValue.Value;
            }
            return t with
            {
                IsUserDefined = userDefinedValues,
                SetLastError = setLastError,
                StringMarshalling = stringMarshalling,
                StringMarshallingCustomType = stringMarshallingCustomType
            };
        }
    }
}