Ejemplo n.º 1
0
        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('>');
        }
Ejemplo n.º 3
0
        /// <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 "&lt;Anonymous Type&gt;.
        /// 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;
        }
Ejemplo n.º 5
0
        /// <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();
        }
Ejemplo n.º 6
0
        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;
        }
Ejemplo n.º 7
0
        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());
        }
Ejemplo n.º 8
0
        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);
            }
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 11
0
        /// <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 &quot;object&quot; need to be replaced by &quot;dynamic&quot;.</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;
        }
Ejemplo n.º 12
0
        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));
        }
Ejemplo n.º 13
0
        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(')');
        }
Ejemplo n.º 14
0
        /// <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;
        }
Ejemplo n.º 15
0
        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));
        }
Ejemplo n.º 16
0
        /// <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 "&lt;Anonymous Type&gt;.
        /// 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();
            }
        }
Ejemplo n.º 17
0
        /// <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;
            }
        }
Ejemplo n.º 18
0
        /// <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 &quot;object&quot; need to be replaced by &quot;dynamic&quot;.</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);
        }
Ejemplo n.º 19
0
 protected abstract void AppendGenericTypeArgumentList(
     StringBuilder builder, 
     Type[] typeArguments, 
     int typeArgumentOffset,
     DynamicFlagsCustomTypeInfo dynamicFlags,
     ref int index,
     int arity, 
     bool escapeKeywordIdentifiers,
     out bool sawInvalidIdentifier);
Ejemplo n.º 20
0
 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();
 }