private static void DecodeMarshalAsSafeArray(ref DecodeWellKnownAttributeArguments <TAttributeSyntax, TAttributeData, TAttributeLocation> arguments, CommonMessageProvider messageProvider) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); Cci.VarEnum? elementTypeVariant = null; ITypeSymbolInternal elementTypeSymbol = null; int symbolIndex = -1; bool hasErrors = false; int position = 1; foreach (var namedArg in arguments.Attribute.NamedArguments) { switch (namedArg.Key) { case "SafeArraySubType": elementTypeVariant = namedArg.Value.DecodeValue <Cci.VarEnum>(SpecialType.System_Enum); if (elementTypeVariant < 0 || (int)elementTypeVariant > MarshalPseudoCustomAttributeData.MaxMarshalInteger) { messageProvider.ReportInvalidNamedArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position, arguments.Attribute.AttributeClass, namedArg.Key); hasErrors = true; } break; case "SafeArrayUserDefinedSubType": elementTypeSymbol = namedArg.Value.DecodeValue <ITypeSymbolInternal>(SpecialType.None); symbolIndex = position; break; case "ArraySubType": case "SizeConst": case "SizeParamIndex": messageProvider.ReportParameterNotValidForType(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position); hasErrors = true; break; // other parameters ignored with no error } position++; } switch (elementTypeVariant) { case Cci.VarEnum.VT_DISPATCH: case Cci.VarEnum.VT_UNKNOWN: case Cci.VarEnum.VT_RECORD: // only these variants accept specification of user defined subtype break; default: if (elementTypeVariant != null && symbolIndex >= 0) { messageProvider.ReportParameterNotValidForType(arguments.Diagnostics, arguments.AttributeSyntaxOpt, symbolIndex); hasErrors = true; } else { // type ignored: elementTypeSymbol = null; } break; } if (!hasErrors) { arguments.GetOrCreateData <TWellKnownAttributeData>().GetOrCreateData().SetMarshalAsSafeArray(elementTypeVariant, elementTypeSymbol); } }
internal static void Decode(ref DecodeWellKnownAttributeArguments <TAttributeSyntax, TAttributeData, TAttributeLocation> arguments, AttributeTargets target, CommonMessageProvider messageProvider) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); UnmanagedType unmanagedType = DecodeMarshalAsType(arguments.Attribute); switch (unmanagedType) { case Cci.Constants.UnmanagedType_CustomMarshaler: DecodeMarshalAsCustom(ref arguments, messageProvider); break; case UnmanagedType.Interface: case Cci.Constants.UnmanagedType_IDispatch: case UnmanagedType.IUnknown: DecodeMarshalAsComInterface(ref arguments, unmanagedType, messageProvider); break; case UnmanagedType.LPArray: DecodeMarshalAsArray(ref arguments, messageProvider, isFixed: false); break; case UnmanagedType.ByValArray: if (target != AttributeTargets.Field) { messageProvider.ReportMarshalUnmanagedTypeOnlyValidForFields(arguments.Diagnostics, arguments.AttributeSyntaxOpt, 0, "ByValArray", arguments.Attribute); } else { DecodeMarshalAsArray(ref arguments, messageProvider, isFixed: true); } break; case Cci.Constants.UnmanagedType_SafeArray: DecodeMarshalAsSafeArray(ref arguments, messageProvider); break; case UnmanagedType.ByValTStr: if (target != AttributeTargets.Field) { messageProvider.ReportMarshalUnmanagedTypeOnlyValidForFields(arguments.Diagnostics, arguments.AttributeSyntaxOpt, 0, "ByValTStr", arguments.Attribute); } else { DecodeMarshalAsFixedString(ref arguments, messageProvider); } break; case Cci.Constants.UnmanagedType_VBByRefStr: if (target == AttributeTargets.Field) { messageProvider.ReportMarshalUnmanagedTypeNotValidForFields(arguments.Diagnostics, arguments.AttributeSyntaxOpt, 0, "VBByRefStr", arguments.Attribute); } else { // named parameters ignored with no error arguments.GetOrCreateData <TWellKnownAttributeData>().GetOrCreateData().SetMarshalAsSimpleType(unmanagedType); } break; default: if ((int)unmanagedType < 0 || (int)unmanagedType > MarshalPseudoCustomAttributeData.MaxMarshalInteger) { // Dev10 reports CS0647: "Error emitting attribute ..." messageProvider.ReportInvalidAttributeArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, 0, arguments.Attribute); } else { // named parameters ignored with no error arguments.GetOrCreateData <TWellKnownAttributeData>().GetOrCreateData().SetMarshalAsSimpleType(unmanagedType); } break; } }
private static void DecodeMarshalAsArray(ref DecodeWellKnownAttributeArguments <TAttributeSyntax, TAttributeData, TAttributeLocation> arguments, CommonMessageProvider messageProvider, bool isFixed) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); UnmanagedType?elementType = null; int? elementCount = isFixed ? 1 : (int?)null; short? parameterIndex = null; bool hasErrors = false; int position = 1; foreach (var namedArg in arguments.Attribute.NamedArguments) { switch (namedArg.Key) { // array: case "ArraySubType": elementType = namedArg.Value.DecodeValue <UnmanagedType>(SpecialType.System_Enum); // for some reason, Dev10 metadata writer disallows CustomMarshaler type as an element type of non-fixed arrays if (!isFixed && elementType == Cci.Constants.UnmanagedType_CustomMarshaler || (int)elementType < 0 || (int)elementType > MarshalPseudoCustomAttributeData.MaxMarshalInteger) { messageProvider.ReportInvalidNamedArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position, arguments.Attribute.AttributeClass, namedArg.Key); hasErrors = true; } break; case "SizeConst": elementCount = namedArg.Value.DecodeValue <int>(SpecialType.System_Int32); if (elementCount < 0 || elementCount > MarshalPseudoCustomAttributeData.MaxMarshalInteger) { messageProvider.ReportInvalidNamedArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position, arguments.Attribute.AttributeClass, namedArg.Key); hasErrors = true; } break; case "SizeParamIndex": if (isFixed) { goto case "SafeArraySubType"; } parameterIndex = namedArg.Value.DecodeValue <short>(SpecialType.System_Int16); if (parameterIndex < 0) { messageProvider.ReportInvalidNamedArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position, arguments.Attribute.AttributeClass, namedArg.Key); hasErrors = true; } break; case "SafeArraySubType": messageProvider.ReportParameterNotValidForType(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position); hasErrors = true; break; // other parameters ignored with no error } position++; } if (!hasErrors) { var data = arguments.GetOrCreateData <TWellKnownAttributeData>().GetOrCreateData(); if (isFixed) { data.SetMarshalAsFixedArray(elementType, elementCount); } else { data.SetMarshalAsArray(elementType, elementCount, parameterIndex); } } }
internal static void DecodeStructLayoutAttribute <TTypeWellKnownAttributeData, TAttributeSyntaxNode, TAttributeData, TAttributeLocation>( ref DecodeWellKnownAttributeArguments <TAttributeSyntaxNode, TAttributeData, TAttributeLocation> arguments, CharSet defaultCharSet, int defaultAutoLayoutSize, CommonMessageProvider messageProvider) where TTypeWellKnownAttributeData : CommonTypeWellKnownAttributeData, new() where TAttributeSyntaxNode : SyntaxNode where TAttributeData : AttributeData { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); TAttributeData attribute = arguments.Attribute; CharSet charSet = (defaultCharSet != Cci.Constants.CharSet_None) ? defaultCharSet : CharSet.Ansi; int? size = null; int? alignment = null; bool hasErrors = false; LayoutKind kind = attribute.CommonConstructorArguments[0].DecodeValue <LayoutKind>(Microsoft.CodeAnalysis.SpecialType.System_Enum); switch (kind) { case LayoutKind.Auto: case LayoutKind.Explicit: case LayoutKind.Sequential: break; default: messageProvider.ReportInvalidAttributeArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, 0, attribute); hasErrors = true; break; } int position = 1; foreach (KeyValuePair <string, TypedConstant> namedArg in attribute.CommonNamedArguments) { switch (namedArg.Key) { case "CharSet": charSet = namedArg.Value.DecodeValue <CharSet>(SpecialType.System_Enum); switch (charSet) { case Cci.Constants.CharSet_None: charSet = CharSet.Ansi; break; case CharSet.Ansi: case Cci.Constants.CharSet_Auto: case CharSet.Unicode: break; default: messageProvider.ReportInvalidNamedArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position, attribute.AttributeClass, namedArg.Key); hasErrors = true; break; } break; case "Pack": alignment = namedArg.Value.DecodeValue <int>(SpecialType.System_Int32); // only powers of 2 less or equal to 128 are allowed: if (alignment > 128 || (alignment & (alignment - 1)) != 0) { messageProvider.ReportInvalidNamedArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position, attribute.AttributeClass, namedArg.Key); hasErrors = true; } break; case "Size": size = namedArg.Value.DecodeValue <int>(Microsoft.CodeAnalysis.SpecialType.System_Int32); if (size < 0) { messageProvider.ReportInvalidNamedArgument(arguments.Diagnostics, arguments.AttributeSyntaxOpt, position, attribute.AttributeClass, namedArg.Key); hasErrors = true; } break; } position++; } if (!hasErrors) { if (kind == LayoutKind.Auto && size == null && alignment != null) { // If size is unspecified // C# emits size=0 // VB emits size=1 if the type is a struct, auto-layout and has alignment specified; 0 otherwise size = defaultAutoLayoutSize; } arguments.GetOrCreateData <TTypeWellKnownAttributeData>().SetStructLayout(new TypeLayout(kind, size ?? 0, (byte)(alignment ?? 0)), charSet); } }