internal DynamicFlagsCustomTypeInfo SubstituteDynamicFlags(Type type, DynamicFlagsCustomTypeInfo originalDynamicFlags) { if (_typeDefinition == null) { return originalDynamicFlags; } var substitutedFlags = ArrayBuilder<bool>.GetInstance(); int f = 0; foreach (Type curr in new TypeWalker(type)) { if (curr.IsGenericParameter && curr.DeclaringType.Equals(_typeDefinition)) { AppendFlagsFor(curr, substitutedFlags); } else { substitutedFlags.Add(originalDynamicFlags[f]); } f++; } var result = DynamicFlagsCustomTypeInfo.Create(substitutedFlags); substitutedFlags.Free(); return result; }
protected override void AppendGenericTypeArgumentList( StringBuilder builder, Type[] typeArguments, int typeArgumentOffset, DynamicFlagsCustomTypeInfo dynamicFlags, ref int index, int arity, bool escapeKeywordIdentifiers, out bool sawInvalidIdentifier) { sawInvalidIdentifier = false; builder.Append('<'); for (int i = 0; i < arity; i++) { if (i > 0) { builder.Append(", "); } Type typeArgument = typeArguments[typeArgumentOffset + i]; bool sawSingleInvalidIdentifier; AppendQualifiedTypeName(builder, typeArgument, dynamicFlags, ref index, escapeKeywordIdentifiers, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; } builder.Append('>'); }
/// <summary> /// Append the qualified name (i.e. including containing types and namespaces) of a named, /// pointer, or array type to <paramref name="builder"/>. /// </summary> /// <remarks> /// Keyword strings are appended for primitive types (e.g. "int" for "System.Int32"). /// Question mark syntax is used for <see cref="Nullable{T}"/>. /// No special handling is required for anonymous types - they are expected to be /// emitted with <see cref="DebuggerDisplayAttribute.Type"/> set to "<Anonymous Type>. /// This is fortunate, since we don't have a good way to recognize them in metadata. /// Does not call itself (directly). /// </remarks> protected void AppendQualifiedTypeName( StringBuilder builder, Type type, DynamicFlagsCustomTypeInfo dynamicFlags, ref int index, bool escapeKeywordIdentifiers, out bool sawInvalidIdentifier) { Type originalType = type; // Can have an array of pointers, but not a pointer to an array, so consume these first. // We'll reconstruct this information later from originalType. while (type.IsArray) { index++; type = type.GetElementType(); } int pointerCount = 0; while (type.IsPointer) { var elementType = type.GetElementType(); if (elementType == null) { // Null for function pointers. break; } index++; pointerCount++; type = elementType; } int nullableCount = 0; Type typeArg; while ((typeArg = type.GetNullableTypeArgument()) != null) { index++; nullableCount++; type = typeArg; } Debug.Assert(nullableCount < 2, "Benign: someone is nesting nullables."); Debug.Assert(pointerCount == 0 || nullableCount == 0, "Benign: pointer to nullable?"); int oldLength = builder.Length; AppendQualifiedTypeNameInternal(builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers, out sawInvalidIdentifier); string name = builder.ToString(oldLength, builder.Length - oldLength); builder.Append('?', nullableCount); builder.Append('*', pointerCount); type = originalType; while (type.IsArray) { AppendRankSpecifier(builder, type.GetArrayRank()); type = type.GetElementType(); } }
public static DynamicFlagsCustomTypeInfo Create(ImmutableArray<bool> dynamicFlags) { Debug.Assert(!dynamicFlags.IsDefaultOrEmpty); var builder = ArrayBuilder<bool>.GetInstance(dynamicFlags.Length); builder.AddRange(dynamicFlags); var result = new DynamicFlagsCustomTypeInfo(builder, startIndex: 0); builder.Free(); return result; }
/// <returns>The qualified name (i.e. including containing types and namespaces) of a named, /// pointer, or array type.</returns> internal string GetTypeName(TypeAndCustomInfo typeAndInfo, bool escapeKeywordIdentifiers = false) { var type = typeAndInfo.Type; if (type == null) { throw new ArgumentNullException("type"); } var dynamicFlags = new DynamicFlagsCustomTypeInfo(typeAndInfo.Info); var index = 0; var pooled = PooledStringBuilder.GetInstance(); AppendQualifiedTypeName(pooled.Builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers); return pooled.ToStringAndFree(); }
private DynamicFlagsMap( Type typeDefinition, DynamicFlagsCustomTypeInfo dynamicFlagsArray, int[] startIndices) { Debug.Assert(typeDefinition != null); Debug.Assert(startIndices != null); Debug.Assert(typeDefinition.IsGenericTypeDefinition); Debug.Assert(startIndices.Length == typeDefinition.GetGenericArguments().Length + 1); _typeDefinition = typeDefinition; _dynamicFlags = dynamicFlagsArray; _startIndices = startIndices; }
internal static DynamicFlagsMap Create(TypeAndCustomInfo typeAndInfo) { var type = typeAndInfo.Type; Debug.Assert(type != null); if (!type.IsGenericType) { return Empty; } var dynamicFlags = new DynamicFlagsCustomTypeInfo(typeAndInfo.Info); if (!dynamicFlags.Any()) { return Empty; } var typeDefinition = type.GetGenericTypeDefinition(); Debug.Assert(typeDefinition != null); var typeArgs = type.GetGenericArguments(); Debug.Assert(typeArgs.Length > 0); int pos = 1; // Consider "type" to have already been consumed. var startsBuilder = ArrayBuilder<int>.GetInstance(); foreach (var typeArg in typeArgs) { startsBuilder.Add(pos); foreach (Type curr in new TypeWalker(typeArg)) { pos++; } } Debug.Assert(pos > 1); startsBuilder.Add(pos); return new DynamicFlagsMap(typeDefinition, dynamicFlags, startsBuilder.ToArrayAndFree()); }
public DynamicFlagsCustomTypeInfo SkipOne() { if (_bytes == null) { return this; } var builder = ArrayBuilder<bool>.GetInstance(); this.CopyTo(builder); var result = new DynamicFlagsCustomTypeInfo(builder, startIndex: 1); builder.Free(); return result; }
private static void ValidateBytes(DynamicFlagsCustomTypeInfo dynamicFlags, params byte[] expectedBytes) { Assert.NotNull(expectedBytes); var dkmClrCustomTypeInfo = dynamicFlags.GetCustomTypeInfo(); if (dynamicFlags.Any()) { Assert.NotNull(dkmClrCustomTypeInfo); var actualBytes = dkmClrCustomTypeInfo.Payload; Assert.Equal(expectedBytes, actualBytes); } else { AssertEx.All(expectedBytes, b => b == 0); Assert.Null(dkmClrCustomTypeInfo); } }
internal Expansion GetTypeExpansion( DkmInspectionContext inspectionContext, TypeAndCustomInfo declaredTypeAndInfo, DkmClrValue value, ExpansionFlags flags) { var declaredType = declaredTypeAndInfo.Type; Debug.Assert(!declaredType.IsTypeVariables()); if ((inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoExpansion) != 0) { return null; } var runtimeType = value.Type.GetLmrType(); // If the value is an array, expand the array elements. if (runtimeType.IsArray) { var sizes = value.ArrayDimensions; if (sizes == null) { // Null array. No expansion. return null; } var lowerBounds = value.ArrayLowerBounds; Type elementType; DkmClrCustomTypeInfo elementTypeInfo; if (declaredType.IsArray) { elementType = declaredType.GetElementType(); elementTypeInfo = new DynamicFlagsCustomTypeInfo(declaredTypeAndInfo.Info).SkipOne().GetCustomTypeInfo(); } else { elementType = runtimeType.GetElementType(); elementTypeInfo = null; } return ArrayExpansion.CreateExpansion(new TypeAndCustomInfo(elementType, elementTypeInfo), sizes, lowerBounds); } if (this.Formatter.IsPredefinedType(runtimeType)) { return null; } if (declaredType.IsPointer) { // If this ever happens, the element type info is just .SkipOne(). Debug.Assert(!new DynamicFlagsCustomTypeInfo(declaredTypeAndInfo.Info).Any()); var elementType = declaredType.GetElementType(); return value.IsNull || elementType.IsVoid() ? null : new PointerDereferenceExpansion(new TypeAndCustomInfo(elementType)); } if (value.EvalFlags.Includes(DkmEvaluationResultFlags.ExceptionThrown) && runtimeType.IsEmptyResultsViewException()) { // The value is an exception thrown expanding an empty // IEnumerable. Use the runtime type of the exception and // skip base types. (This matches the native EE behavior // to expose a single property from the exception.) flags &= ~ExpansionFlags.IncludeBaseMembers; } return MemberExpansion.CreateExpansion(inspectionContext, declaredTypeAndInfo, value, flags, TypeHelpers.IsVisibleMember, this.Formatter); }
/// <summary> /// Append the name of the type and its type arguments. Do not append the type's containing type or namespace. /// </summary> /// <param name="builder">Builder to which the name will be appended.</param> /// <param name="type">Type, the name of which will be appended.</param> /// <param name="dynamicFlags">Flags indicating which occurrences of "object" need to be replaced by "dynamic".</param> /// <param name="index">Current index into <paramref name="dynamicFlags"/>.</param> /// <param name="escapeKeywordIdentifiers">True if identifiers that are also keywords should be prefixed with '@'.</param> /// <param name="typeArguments"> /// The type arguments of the type passed to <see cref="AppendQualifiedTypeNameInternal"/>, which might be nested /// within <paramref name="type"/>. In the Reflection/LMR object model, all type arguments are passed to the /// most nested type. To get back to the C# model, we have to propagate them out to containing types. /// </param> /// <param name="typeArgumentOffset"> /// The first position in <paramref name="typeArguments"/> that is a type argument to <paramref name="type"/>, /// from a C# perspective. /// </param> /// <param name="arity"> /// The number of type parameters of <paramref name="type"/>, from a C# perspective. /// </param> /// <param name="sawInvalidIdentifier">True if the name includes an invalid identifier (see <see cref="IsValidIdentifier"/>); false otherwise.</param> /// <remarks> /// We're passing the full array plus bounds, rather than a tailored array, to avoid creating a lot of short-lived /// temporary arrays. /// </remarks> private void AppendUnqualifiedTypeName( StringBuilder builder, Type type, DynamicFlagsCustomTypeInfo dynamicFlags, ref int index, bool escapeKeywordIdentifiers, Type[] typeArguments, int typeArgumentOffset, int arity, out bool sawInvalidIdentifier) { if (typeArguments == null || arity == 0) { AppendIdentifier(builder, escapeKeywordIdentifiers, type.Name, out sawInvalidIdentifier); return; } var mangledName = type.Name; var separatorIndex = mangledName.IndexOf('`'); var unmangledName = separatorIndex < 0 ? mangledName : mangledName.Substring(0, separatorIndex); AppendIdentifier(builder, escapeKeywordIdentifiers, unmangledName, out sawInvalidIdentifier); bool argumentsSawInvalidIdentifier; AppendGenericTypeArgumentList(builder, typeArguments, typeArgumentOffset, dynamicFlags, ref index, arity, escapeKeywordIdentifiers, out argumentsSawInvalidIdentifier); sawInvalidIdentifier |= argumentsSawInvalidIdentifier; }
internal Expansion GetTypeExpansion( DkmInspectionContext inspectionContext, TypeAndCustomInfo declaredTypeAndInfo, DkmClrValue value, ExpansionFlags flags) { var declaredType = declaredTypeAndInfo.Type; Debug.Assert(!declaredType.IsTypeVariables()); if ((inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoExpansion) != 0) { return(null); } var runtimeType = value.Type.GetLmrType(); // If the value is an array, expand the array elements. if (runtimeType.IsArray) { var sizes = value.ArrayDimensions; if (sizes == null) { // Null array. No expansion. return(null); } var lowerBounds = value.ArrayLowerBounds; Type elementType; DkmClrCustomTypeInfo elementTypeInfo; if (declaredType.IsArray) { elementType = declaredType.GetElementType(); elementTypeInfo = DynamicFlagsCustomTypeInfo.Create(declaredTypeAndInfo.Info).SkipOne().GetCustomTypeInfo(); } else { elementType = runtimeType.GetElementType(); elementTypeInfo = null; } return(ArrayExpansion.CreateExpansion(new TypeAndCustomInfo(elementType, elementTypeInfo), sizes, lowerBounds)); } if (this.Formatter.IsPredefinedType(runtimeType)) { return(null); } if (declaredType.IsFunctionPointer()) { // Function pointers have no expansion return(null); } if (declaredType.IsPointer) { // If this ever happens, the element type info is just .SkipOne(). Debug.Assert(!DynamicFlagsCustomTypeInfo.Create(declaredTypeAndInfo.Info).Any()); var elementType = declaredType.GetElementType(); return(value.IsNull || elementType.IsVoid() ? null : new PointerDereferenceExpansion(new TypeAndCustomInfo(elementType))); } if (value.EvalFlags.Includes(DkmEvaluationResultFlags.ExceptionThrown) && runtimeType.IsEmptyResultsViewException()) { // The value is an exception thrown expanding an empty // IEnumerable. Use the runtime type of the exception and // skip base types. (This matches the native EE behavior // to expose a single property from the exception.) flags &= ~ExpansionFlags.IncludeBaseMembers; } return(MemberExpansion.CreateExpansion(inspectionContext, declaredTypeAndInfo, value, flags, TypeHelpers.IsVisibleMember, this.Formatter)); }
private void AppendTupleElements( StringBuilder builder, Type type, int cardinality, ReadOnlyCollection <byte> dynamicFlags, ref int dynamicFlagIndex, ReadOnlyCollection <string> tupleElementNames, ref int tupleElementIndex, bool escapeKeywordIdentifiers, out bool sawInvalidIdentifier) { sawInvalidIdentifier = false; #if DEBUG int lastNameIndex = tupleElementIndex + cardinality; #endif int nameIndex = tupleElementIndex; builder.Append('('); bool any = false; while (true) { tupleElementIndex += cardinality; var typeArguments = type.GetGenericArguments(); int nTypeArgs = typeArguments.Length; Debug.Assert(nTypeArgs > 0); Debug.Assert(nTypeArgs <= TypeHelpers.TupleFieldRestPosition); int nFields = Math.Min(nTypeArgs, TypeHelpers.TupleFieldRestPosition - 1); for (int i = 0; i < nFields; i++) { if (any) { builder.Append(", "); } bool sawSingleInvalidIdentifier; var name = CustomTypeInfo.GetTupleElementNameIfAny(tupleElementNames, nameIndex); nameIndex++; AppendTupleElement( builder, typeArguments[i], name, dynamicFlags, ref dynamicFlagIndex, tupleElementNames, ref tupleElementIndex, escapeKeywordIdentifiers, sawInvalidIdentifier: out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; any = true; } if (nTypeArgs < TypeHelpers.TupleFieldRestPosition) { break; } Debug.Assert(!DynamicFlagsCustomTypeInfo.GetFlag(dynamicFlags, dynamicFlagIndex)); dynamicFlagIndex++; type = typeArguments[nTypeArgs - 1]; cardinality = type.GetTupleCardinalityIfAny(); } #if DEBUG Debug.Assert(nameIndex == lastNameIndex); #endif builder.Append(')'); }
/// <summary> /// Append the qualified name (i.e. including containing types and namespaces) of a named type /// (i.e. not a pointer or array type) to <paramref name="builder"/>. /// </summary> /// <remarks> /// Keyword strings are appended for primitive types (e.g. "int" for "System.Int32"). /// </remarks> /// <remarks> /// Does not call itself or <see cref="AppendQualifiedTypeName"/> (directly). /// </remarks> private void AppendQualifiedTypeNameInternal( StringBuilder builder, Type type, ReadOnlyCollection <byte> dynamicFlags, ref int dynamicFlagIndex, ReadOnlyCollection <string> tupleElementNames, ref int tupleElementIndex, bool escapeKeywordIdentifiers, out bool sawInvalidIdentifier) { var isDynamic = DynamicFlagsCustomTypeInfo.GetFlag(dynamicFlags, dynamicFlagIndex++) && type.IsObject(); if (AppendSpecialTypeName(builder, type, isDynamic)) { sawInvalidIdentifier = false; return; } Debug.Assert(!isDynamic, $"Dynamic should have been handled by {nameof(AppendSpecialTypeName)}"); Debug.Assert(!IsPredefinedType(type)); if (type.IsGenericParameter) { AppendIdentifier(builder, escapeKeywordIdentifiers, type.Name, out sawInvalidIdentifier); return; } int cardinality; if (type.IsTupleCompatible(out cardinality)) { if (cardinality == 1) { // Not displayed as a tuple but is included in tuple element names. tupleElementIndex++; } else { AppendTupleElements( builder, type, cardinality, dynamicFlags, ref dynamicFlagIndex, tupleElementNames, ref tupleElementIndex, escapeKeywordIdentifiers, out sawInvalidIdentifier); return; } } // Note: in the Reflection/LMR object model, all type arguments are on the most nested type. var hasTypeArguments = type.IsGenericType; var typeArguments = hasTypeArguments ? type.GetGenericArguments() : null; Debug.Assert(hasTypeArguments == (typeArguments != null)); var numTypeArguments = hasTypeArguments ? typeArguments.Length : 0; sawInvalidIdentifier = false; bool sawSingleInvalidIdentifier; var typeArgumentOffset = 0; if (type.IsNested) { // Push from inside, out. var stack = ArrayBuilder <Type> .GetInstance(); { var containingType = type.DeclaringType; while (containingType != null) { stack.Add(containingType); containingType = containingType.DeclaringType; } } var lastContainingTypeIndex = stack.Count - 1; AppendNamespacePrefix(builder, stack[lastContainingTypeIndex], escapeKeywordIdentifiers, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; // Pop from outside, in. for (int i = lastContainingTypeIndex; i >= 0; i--) { var containingType = stack[i]; // ACASEY: I explored the type in the debugger and couldn't find the arity stored/exposed separately. int arity = hasTypeArguments ? containingType.GetGenericArguments().Length - typeArgumentOffset : 0; AppendUnqualifiedTypeName( builder, containingType, dynamicFlags, ref dynamicFlagIndex, tupleElementNames, ref tupleElementIndex, escapeKeywordIdentifiers, typeArguments, typeArgumentOffset, arity, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; builder.Append('.'); typeArgumentOffset += arity; } stack.Free(); } else { AppendNamespacePrefix(builder, type, escapeKeywordIdentifiers, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; } AppendUnqualifiedTypeName( builder, type, dynamicFlags, ref dynamicFlagIndex, tupleElementNames, ref tupleElementIndex, escapeKeywordIdentifiers, typeArguments, typeArgumentOffset, numTypeArguments - typeArgumentOffset, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; }
internal static EvalResultDataItem CreateMemberDataItem( ResultProvider resultProvider, DkmInspectionContext inspectionContext, MemberAndDeclarationInfo member, DkmClrValue memberValue, EvalResultDataItem parent, DynamicFlagsMap dynamicFlagsMap, ExpansionFlags flags) { var declaredType = member.Type; var declaredTypeInfo = dynamicFlagsMap.SubstituteDynamicFlags(member.OriginalDefinitionType, DynamicFlagsCustomTypeInfo.Create(member.TypeInfo)).GetCustomTypeInfo(); string memberName; // Considering, we're not handling the case of a member inherited from a generic base type. var typeDeclaringMember = member.GetExplicitlyImplementedInterface(out memberName) ?? member.DeclaringType; var typeDeclaringMemberInfo = typeDeclaringMember.IsInterface ? dynamicFlagsMap.SubstituteDynamicFlags(typeDeclaringMember.GetInterfaceListEntry(member.DeclaringType), originalDynamicFlags: default(DynamicFlagsCustomTypeInfo)).GetCustomTypeInfo() : null; var formatter = resultProvider.Formatter; memberName = formatter.GetIdentifierEscapingPotentialKeywords(memberName); var fullName = MakeFullName( formatter, memberName, new TypeAndCustomInfo(typeDeclaringMember, typeDeclaringMemberInfo), // Note: Won't include DynamicAttribute. member.RequiresExplicitCast, member.IsStatic, parent); return(resultProvider.CreateDataItem( inspectionContext, memberName, typeDeclaringMemberAndInfo: (member.IncludeTypeInMemberName || typeDeclaringMember.IsInterface) ? new TypeAndCustomInfo(typeDeclaringMember, typeDeclaringMemberInfo) : default(TypeAndCustomInfo), // Note: Won't include DynamicAttribute. declaredTypeAndInfo: new TypeAndCustomInfo(declaredType, declaredTypeInfo), value: memberValue, parent: parent, expansionFlags: flags, childShouldParenthesize: false, fullName: fullName, formatSpecifiers: Formatter.NoFormatSpecifiers, category: DkmEvaluationResultCategory.Other, flags: memberValue.EvalFlags, evalFlags: DkmEvaluationFlags.None)); }
/// <summary> /// Append the qualified name (i.e. including containing types and namespaces) of a named type /// (i.e. not a pointer or array type) to <paramref name="builder"/>. /// </summary> /// <remarks> /// Keyword strings are appended for primitive types (e.g. "int" for "System.Int32"). /// </remarks> /// <remarks> /// Does not call itself or <see cref="AppendQualifiedTypeName"/> (directly). /// </remarks> private void AppendQualifiedTypeNameInternal( StringBuilder builder, Type type, DynamicFlagsCustomTypeInfo dynamicFlags, ref int index, bool escapeKeywordIdentifiers, out bool sawInvalidIdentifier) { var isDynamic = dynamicFlags[index++] && type.IsObject(); if (AppendSpecialTypeName(builder, type, isDynamic)) { sawInvalidIdentifier = false; return; } Debug.Assert(!isDynamic, $"Dynamic should have been handled by {nameof(AppendSpecialTypeName)}"); Debug.Assert(!IsPredefinedType(type)); if (type.IsGenericParameter) { AppendIdentifier(builder, escapeKeywordIdentifiers, type.Name, out sawInvalidIdentifier); return; } // Note: in the Reflection/LMR object model, all type arguments are on the most nested type. var hasTypeArguments = type.IsGenericType; var typeArguments = type.IsGenericType ? type.GetGenericArguments() : null; Debug.Assert(hasTypeArguments == (typeArguments != null)); var numTypeArguments = hasTypeArguments ? typeArguments.Length : 0; sawInvalidIdentifier = false; bool sawSingleInvalidIdentifier; if (type.IsNested) { // Push from inside, out. var stack = ArrayBuilder<Type>.GetInstance(); { var containingType = type.DeclaringType; while (containingType != null) { stack.Add(containingType); containingType = containingType.DeclaringType; } } var lastContainingTypeIndex = stack.Count - 1; AppendNamespacePrefix(builder, stack[lastContainingTypeIndex], escapeKeywordIdentifiers, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; var typeArgumentOffset = 0; // Pop from outside, in. for (int i = lastContainingTypeIndex; i >= 0; i--) { var containingType = stack[i]; // ACASEY: I explored the type in the debugger and couldn't find the arity stored/exposed separately. int arity = hasTypeArguments ? containingType.GetGenericArguments().Length - typeArgumentOffset : 0; AppendUnqualifiedTypeName(builder, containingType, dynamicFlags, ref index, escapeKeywordIdentifiers, typeArguments, typeArgumentOffset, arity, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; builder.Append('.'); typeArgumentOffset += arity; } stack.Free(); AppendUnqualifiedTypeName(builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers, typeArguments, typeArgumentOffset, numTypeArguments - typeArgumentOffset, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; } else { AppendNamespacePrefix(builder, type, escapeKeywordIdentifiers, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; AppendUnqualifiedTypeName(builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers, typeArguments, 0, numTypeArguments, out sawSingleInvalidIdentifier); sawInvalidIdentifier |= sawSingleInvalidIdentifier; } }
/// <summary> /// Append the name of the type and its type arguments. Do not append the type's containing type or namespace. /// </summary> /// <param name="builder">Builder to which the name will be appended.</param> /// <param name="type">Type, the name of which will be appended.</param> /// <param name="dynamicFlags">Flags indicating which occurrences of "object" need to be replaced by "dynamic".</param> /// <param name="index">Current index into <paramref name="dynamicFlags"/>.</param> /// <param name="escapeKeywordIdentifiers">True if identifiers that are also keywords should be prefixed with '@'.</param> /// <param name="typeArguments"> /// The type arguments of the type passed to <see cref="AppendQualifiedTypeNameInternal"/>, which might be nested /// within <paramref name="type"/>. In the Reflection/LMR object model, all type arguments are passed to the /// most nested type. To get back to the C# model, we have to propagate them out to containing types. /// </param> /// <param name="typeArgumentOffset"> /// The first position in <paramref name="typeArguments"/> that is a type argument to <paramref name="type"/>, /// from a C# perspective. /// </param> /// <param name="arity"> /// The number of type parameters of <paramref name="type"/>, from a C# perspective. /// </param> /// <remarks> /// We're passing the full array plus bounds, rather than a tailored array, to avoid creating a lot of short-lived /// temporary arrays. /// </remarks> private void AppendUnqualifiedTypeName(StringBuilder builder, Type type, DynamicFlagsCustomTypeInfo dynamicFlags, ref int index, bool escapeKeywordIdentifiers, Type[] typeArguments, int typeArgumentOffset, int arity) { if (typeArguments == null || arity == 0) { AppendIdentifier(builder, escapeKeywordIdentifiers, type.Name); return; } var mangledName = type.Name; var separatorIndex = mangledName.IndexOf('`'); AppendIdentifier(builder, escapeKeywordIdentifiers, mangledName, separatorIndex); AppendGenericTypeArgumentList(builder, typeArguments, typeArgumentOffset, dynamicFlags, ref index, arity, escapeKeywordIdentifiers); }
protected abstract void AppendGenericTypeArgumentList( StringBuilder builder, Type[] typeArguments, int typeArgumentOffset, DynamicFlagsCustomTypeInfo dynamicFlags, ref int index, int arity, bool escapeKeywordIdentifiers, out bool sawInvalidIdentifier);
internal static ReadOnlyCollection<byte> GetCustomTypeInfoPayload(this MethodSymbol method) { bool[] dynamicFlags = CSharpCompilation.DynamicTransformsEncoder.Encode(method.ReturnType, method.ReturnTypeCustomModifiers.Length, RefKind.None).ToArray(); var dynamicFlagsInfo = new DynamicFlagsCustomTypeInfo(new BitArray(dynamicFlags)); return dynamicFlagsInfo.GetCustomTypeInfoPayload(); }