private ReadOnlyCollection <byte> SubstituteDynamicFlags(Type type, ReadOnlyCollection <byte> dynamicFlagsOpt) { var builder = ArrayBuilder <bool> .GetInstance(); int f = 0; foreach (Type curr in new TypeWalker(type)) { if (curr.IsGenericParameter && curr.DeclaringType.Equals(_typeDefinition)) { AppendRangeFor( curr, _dynamicFlags, _dynamicFlagStartIndices, DynamicFlagsCustomTypeInfo.GetFlag, builder); } else { builder.Add(DynamicFlagsCustomTypeInfo.GetFlag(dynamicFlagsOpt, f)); } f++; } var result = DynamicFlagsCustomTypeInfo.ToBytes(builder); builder.Free(); return(result); }
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; int nameIndex = tupleElementIndex; tupleElementIndex += cardinality; builder.Append('('); bool any = false; while (true) { 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]; } 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; }