| File: Symbols\Attributes\MarshalPseudoCustomAttributeData.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Symbols; using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace Microsoft.CodeAnalysis { /// <summary> /// Information decoded from <see cref="MarshalAsAttribute"/>. /// </summary> internal sealed class MarshalPseudoCustomAttributeData : Cci.IMarshallingInformation { private UnmanagedType _marshalType; private int _marshalArrayElementType; // safe array: VarEnum; array: UnmanagedType private int _marshalArrayElementCount; // number of elements in an array, length of a string, or Unspecified private int _marshalParameterIndex; // index of parameter that specifies array size (short) or IID (int), or Unspecified private object _marshalTypeNameOrSymbol; // custom marshaller: string or ITypeSymbolInternal; safe array: element type symbol private string _marshalCookie; internal const int Invalid = -1; private const UnmanagedType InvalidUnmanagedType = (UnmanagedType)Invalid; private const Cci.VarEnum InvalidVariantType = (Cci.VarEnum)Invalid; internal const int MaxMarshalInteger = 0x1fffffff; #region Initialization public MarshalPseudoCustomAttributeData() { } internal void SetMarshalAsCustom(object typeSymbolOrName, string cookie) { _marshalType = Cci.Constants.UnmanagedType_CustomMarshaler; _marshalTypeNameOrSymbol = typeSymbolOrName; _marshalCookie = cookie; } internal void SetMarshalAsComInterface(UnmanagedType unmanagedType, int? parameterIndex) { Debug.Assert(parameterIndex == null || parameterIndex >= 0 && parameterIndex <= MaxMarshalInteger); _marshalType = unmanagedType; _marshalParameterIndex = parameterIndex ?? Invalid; } internal void SetMarshalAsArray(UnmanagedType? elementType, int? elementCount, short? parameterIndex) { Debug.Assert(elementCount == null || elementCount >= 0 && elementCount <= MaxMarshalInteger); Debug.Assert(parameterIndex == null || parameterIndex >= 0); _marshalType = UnmanagedType.LPArray; _marshalArrayElementType = (int)(elementType ?? (UnmanagedType)0x50); _marshalArrayElementCount = elementCount ?? Invalid; _marshalParameterIndex = parameterIndex ?? Invalid; } internal void SetMarshalAsFixedArray(UnmanagedType? elementType, int? elementCount) { Debug.Assert(elementCount == null || elementCount >= 0 && elementCount <= MaxMarshalInteger); Debug.Assert(elementType == null || elementType >= 0 && (int)elementType <= MaxMarshalInteger); _marshalType = UnmanagedType.ByValArray; _marshalArrayElementType = (int)(elementType ?? InvalidUnmanagedType); _marshalArrayElementCount = elementCount ?? Invalid; } internal void SetMarshalAsSafeArray(Cci.VarEnum? elementType, ITypeSymbolInternal elementTypeSymbol) { Debug.Assert(elementType == null || elementType >= 0 && (int)elementType <= MaxMarshalInteger); _marshalType = Cci.Constants.UnmanagedType_SafeArray; _marshalArrayElementType = (int)(elementType ?? InvalidVariantType); _marshalTypeNameOrSymbol = elementTypeSymbol; } internal void SetMarshalAsFixedString(int elementCount) { Debug.Assert(elementCount >= 0 && elementCount <= MaxMarshalInteger); _marshalType = UnmanagedType.ByValTStr; _marshalArrayElementCount = elementCount; } internal void SetMarshalAsSimpleType(UnmanagedType type) { Debug.Assert(type >= 0 && (int)type <= MaxMarshalInteger); _marshalType = type; } #endregion public UnmanagedType UnmanagedType { get { return _marshalType; } } int Cci.IMarshallingInformation.IidParameterIndex { get { Debug.Assert( _marshalType == UnmanagedType.Interface || _marshalType == UnmanagedType.IUnknown || _marshalType == Cci.Constants.UnmanagedType_IDispatch); return _marshalParameterIndex; } } object Cci.IMarshallingInformation.GetCustomMarshaller(EmitContext context) { Debug.Assert(_marshalType == Cci.Constants.UnmanagedType_CustomMarshaler); var typeSymbol = _marshalTypeNameOrSymbol as ITypeSymbolInternal; if (typeSymbol != null) { return ((CommonPEModuleBuilder)context.Module).Translate(typeSymbol, context.SyntaxNode, context.Diagnostics); } else { Debug.Assert(_marshalTypeNameOrSymbol == null || _marshalTypeNameOrSymbol is string); return _marshalTypeNameOrSymbol; } } string Cci.IMarshallingInformation.CustomMarshallerRuntimeArgument { get { Debug.Assert(_marshalType == Cci.Constants.UnmanagedType_CustomMarshaler); return _marshalCookie; } } int Cci.IMarshallingInformation.NumberOfElements { get { Debug.Assert(_marshalType == UnmanagedType.ByValTStr || _marshalType == UnmanagedType.LPArray || _marshalType == Cci.Constants.UnmanagedType_SafeArray || _marshalType == UnmanagedType.ByValArray); return _marshalArrayElementCount; } } short Cci.IMarshallingInformation.ParamIndex { get { Debug.Assert(_marshalType == UnmanagedType.LPArray && _marshalParameterIndex <= short.MaxValue); return (short)_marshalParameterIndex; } } UnmanagedType Cci.IMarshallingInformation.ElementType { get { Debug.Assert(_marshalType == UnmanagedType.LPArray || _marshalType == UnmanagedType.ByValArray); return (UnmanagedType)_marshalArrayElementType; } } Cci.VarEnum Cci.IMarshallingInformation.SafeArrayElementSubtype { get { Debug.Assert(_marshalType == Cci.Constants.UnmanagedType_SafeArray); return (Cci.VarEnum)_marshalArrayElementType; } } Cci.ITypeReference Cci.IMarshallingInformation.GetSafeArrayElementUserDefinedSubtype(EmitContext context) { Debug.Assert(_marshalType == Cci.Constants.UnmanagedType_SafeArray); if (_marshalTypeNameOrSymbol == null) { return null; } return ((CommonPEModuleBuilder)context.Module).Translate((ITypeSymbolInternal)_marshalTypeNameOrSymbol, context.SyntaxNode, context.Diagnostics); } /// <summary> /// Returns an instance of <see cref="MarshalPseudoCustomAttributeData"/> with all types replaced by types returned by specified translator. /// Returns this instance if it doesn't hold on any types. /// </summary> internal MarshalPseudoCustomAttributeData WithTranslatedTypes<TTypeSymbol, TArg>( Func<TTypeSymbol, TArg, TTypeSymbol> translator, TArg arg) where TTypeSymbol : ITypeSymbolInternal { if (_marshalType != Cci.Constants.UnmanagedType_SafeArray || _marshalTypeNameOrSymbol == null) { return this; } var translatedType = translator((TTypeSymbol)_marshalTypeNameOrSymbol, arg); if ((object)translatedType == (object)_marshalTypeNameOrSymbol) { return this; } var result = new MarshalPseudoCustomAttributeData(); result.SetMarshalAsSafeArray((Cci.VarEnum)_marshalArrayElementType, translatedType); return result; } // testing only internal ITypeSymbolInternal TryGetSafeArrayElementUserDefinedSubtype() { return _marshalTypeNameOrSymbol as ITypeSymbolInternal; } } }