/// <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(); } }
/// <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?"); AppendQualifiedTypeNameInternal(builder, type, dynamicFlags, ref index, escapeKeywordIdentifiers, out sawInvalidIdentifier); builder.Append('?', nullableCount); builder.Append('*', pointerCount); type = originalType; while (type.IsArray) { AppendRankSpecifier(builder, type.GetArrayRank()); type = type.GetElementType(); } }
/// <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, bool escapeKeywordIdentifiers) { 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) { type = type.GetElementType(); } int pointerCount = 0; while (type.IsPointer) { pointerCount++; type = type.GetElementType(); } int nullableCount = 0; Type typeArg; while ((typeArg = type.GetNullableTypeArgument()) != null) { 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, escapeKeywordIdentifiers); 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(); } }
internal EvalResultDataItem CreateDataItem( DkmInspectionContext inspectionContext, string name, Type typeDeclaringMember, Type declaredType, DkmClrValue value, EvalResultDataItem parent, ExpansionFlags expansionFlags, bool childShouldParenthesize, string fullName, ReadOnlyCollection <string> formatSpecifiers, DkmEvaluationResultCategory category, DkmEvaluationResultFlags flags, DkmEvaluationFlags evalFlags) { if ((evalFlags & DkmEvaluationFlags.ShowValueRaw) != 0) { formatSpecifiers = Formatter.AddFormatSpecifier(formatSpecifiers, "raw"); } Expansion expansion; // If the declared type is Nullable<T>, the value should // have no expansion if null, or be expanded as a T. var lmrNullableTypeArg = declaredType.GetNullableTypeArgument(); if (lmrNullableTypeArg != null && !value.HasExceptionThrown(parent)) { Debug.Assert(value.Type.GetProxyType() == null); var nullableValue = value.GetNullableValue(inspectionContext); if (nullableValue == null) { Debug.Assert(declaredType.Equals(value.Type.GetLmrType())); // No expansion of "null". expansion = null; } else { value = nullableValue; Debug.Assert(lmrNullableTypeArg.Equals(value.Type.GetLmrType())); // If this is not the case, add a test for includeRuntimeTypeIfNecessary. expansion = this.GetTypeExpansion(inspectionContext, lmrNullableTypeArg, value, ExpansionFlags.IncludeResultsView); } } else if (value.IsError() || (inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoExpansion) != 0) { expansion = null; } else { expansion = DebuggerTypeProxyExpansion.CreateExpansion( this, inspectionContext, name, typeDeclaringMember, declaredType, value, childShouldParenthesize, fullName, flags.Includes(DkmEvaluationResultFlags.ExceptionThrown) ? null : fullName, formatSpecifiers, flags, this.Formatter.GetEditableValue(value, inspectionContext)); if (expansion == null) { var expansionType = value.HasExceptionThrown(parent) ? value.Type.GetLmrType() : declaredType; expansion = this.GetTypeExpansion(inspectionContext, expansionType, value, expansionFlags); } } return(new EvalResultDataItem( ExpansionKind.Default, name, typeDeclaringMember, declaredType, parent: parent, value: value, displayValue: null, expansion: expansion, childShouldParenthesize: childShouldParenthesize, fullName: fullName, childFullNamePrefixOpt: flags.Includes(DkmEvaluationResultFlags.ExceptionThrown) ? null : fullName, formatSpecifiers: formatSpecifiers, category: category, flags: flags, editableValue: this.Formatter.GetEditableValue(value, inspectionContext), inspectionContext: inspectionContext)); }
internal EvalResultDataItem CreateDataItem( DkmInspectionContext inspectionContext, string name, Type typeDeclaringMember, Type declaredType, DkmClrValue value, EvalResultDataItem parent, ExpansionFlags expansionFlags, bool childShouldParenthesize, string fullName, ReadOnlyCollection<string> formatSpecifiers, DkmEvaluationResultCategory category, DkmEvaluationResultFlags flags, DkmEvaluationFlags evalFlags) { if ((evalFlags & DkmEvaluationFlags.ShowValueRaw) != 0) { formatSpecifiers = Formatter.AddFormatSpecifier(formatSpecifiers, "raw"); } Expansion expansion; // If the declared type is Nullable<T>, the value should // have no expansion if null, or be expanded as a T. var lmrNullableTypeArg = declaredType.GetNullableTypeArgument(); if (lmrNullableTypeArg != null && !value.HasExceptionThrown(parent)) { Debug.Assert(value.Type.GetProxyType() == null); var nullableValue = value.GetNullableValue(); if (nullableValue == null) { Debug.Assert(declaredType.Equals(value.Type.GetLmrType())); // No expansion of "null". expansion = null; } else { value = nullableValue; Debug.Assert(lmrNullableTypeArg.Equals(value.Type.GetLmrType())); // If this is not the case, add a test for includeRuntimeTypeIfNecessary. expansion = this.GetTypeExpansion(inspectionContext, lmrNullableTypeArg, value, ExpansionFlags.IncludeResultsView); } } else if (value.IsError() || (inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoExpansion) != 0) { expansion = null; } else { expansion = DebuggerTypeProxyExpansion.CreateExpansion( this, inspectionContext, name, typeDeclaringMember, declaredType, value, childShouldParenthesize, fullName, flags.Includes(DkmEvaluationResultFlags.ExceptionThrown) ? null : fullName, formatSpecifiers, flags, this.Formatter.GetEditableValue(value)); if (expansion == null) { var expansionType = value.HasExceptionThrown(parent) ? value.Type.GetLmrType() : declaredType; expansion = this.GetTypeExpansion(inspectionContext, expansionType, value, expansionFlags); } } return new EvalResultDataItem( name, typeDeclaringMember, declaredType, value, expansion, childShouldParenthesize, fullName, flags.Includes(DkmEvaluationResultFlags.ExceptionThrown) ? null : fullName, formatSpecifiers, category, flags, this.Formatter.GetEditableValue(value)); }