Пример #1
0
        /// <summary>
        /// Extracts information from the first <see cref="DebuggerDisplayAttribute"/> on the runtime type of <paramref name="value"/>, if there is one.
        /// </summary>
        internal static bool TryGetDebuggerDisplayInfo(this DkmClrValue value, out DebuggerDisplayInfo displayInfo)
        {
            displayInfo = default(DebuggerDisplayInfo);

            // The native EE does not consider DebuggerDisplayAttribute
            // on null or error instances.
            if (value.IsError() || value.IsNull)
            {
                return(false);
            }

            var clrType = value.Type;

            DkmClrType attributeTarget;
            DkmClrDebuggerDisplayAttribute attribute;

            if (clrType.TryGetEvalAttribute(out attributeTarget, out attribute)) // First, as in dev12.
            {
                displayInfo = new DebuggerDisplayInfo(attributeTarget, attribute);
                return(true);
            }

            return(false);
        }
Пример #2
0
        internal string GetValueString(DkmClrValue value, ObjectDisplayOptions options, GetValueFlags flags)
        {
            if (value.IsError())
            {
                return((string)value.HostObjectValue);
            }

            if (UsesHexadecimalNumbers(value))
            {
                options |= ObjectDisplayOptions.UseHexadecimalNumbers;
            }

            var lmrType = value.Type.GetLmrType();

            if (IsPredefinedType(lmrType) && !lmrType.IsObject())
            {
                if (lmrType.IsString())
                {
                    var stringValue = (string)value.HostObjectValue;
                    if (stringValue == null)
                    {
                        return(_nullString);
                    }
                    return(IncludeObjectId(
                               value,
                               FormatString(stringValue, options),
                               flags));
                }
                else if (lmrType.IsCharacter())
                {
                    return(IncludeObjectId(
                               value,
                               FormatLiteral((char)value.HostObjectValue, options | ObjectDisplayOptions.IncludeCodePoints),
                               flags));
                }
                else
                {
                    return(IncludeObjectId(
                               value,
                               FormatPrimitive(value, options & ~ObjectDisplayOptions.UseQuotes),
                               flags));
                }
            }
            else if (value.IsNull && !lmrType.IsPointer)
            {
                return(_nullString);
            }
            else if (lmrType.IsEnum)
            {
                return(IncludeObjectId(
                           value,
                           GetEnumDisplayString(lmrType, value, options, (flags & GetValueFlags.IncludeTypeName) != 0),
                           flags));
            }
            else if (lmrType.IsArray)
            {
                return(IncludeObjectId(
                           value,
                           GetArrayDisplayString(lmrType, value.ArrayDimensions, value.ArrayLowerBounds, options),
                           flags));
            }
            else if (lmrType.IsPointer)
            {
                // NOTE: the HostObjectValue will have a size corresponding to the process bitness
                // and FormatPrimitive will adjust accordingly.
                var tmp = FormatPrimitive(value, ObjectDisplayOptions.UseHexadecimalNumbers); // Always in hex.
                Debug.Assert(tmp != null);
                return(tmp);
            }
            else if (lmrType.IsNullable())
            {
                var nullableValue = value.GetNullableValue();
                // It should be impossible to nest nullables, so this recursion should introduce only a single extra stack frame.
                return(nullableValue == null
                    ? _nullString
                    : GetValueString(nullableValue, ObjectDisplayOptions.None, GetValueFlags.IncludeTypeName));
            }

            // "value.EvaluateToString()" will check "Call string-conversion function on objects in variables windows"
            // (Tools > Options setting) and call "value.ToString()" if appropriate.
            return(IncludeObjectId(
                       value,
                       string.Format(_defaultFormat, value.EvaluateToString() ?? value.InspectionContext.GetTypeName(value.Type)),
                       flags));
        }
Пример #3
0
        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));
        }
Пример #4
0
        private string GetEditableValue(
            DkmClrValue value,
            DkmInspectionContext inspectionContext,
            DkmClrCustomTypeInfo customTypeInfo
            )
        {
            if (value.IsError())
            {
                return(null);
            }

            if (value.EvalFlags.Includes(DkmEvaluationResultFlags.ReadOnly))
            {
                return(null);
            }

            var type = value.Type.GetLmrType();

            if (type.IsEnum)
            {
                return(this.GetValueString(
                           value,
                           inspectionContext,
                           ObjectDisplayOptions.None,
                           GetValueFlags.IncludeTypeName
                           ));
            }
            else if (type.IsDecimal())
            {
                return(this.GetValueString(
                           value,
                           inspectionContext,
                           ObjectDisplayOptions.IncludeTypeSuffix,
                           GetValueFlags.None
                           ));
            }
            // The legacy EE didn't special-case strings or chars (when ",nq" was used,
            // you had to manually add quotes when editing) but it makes sense to
            // always automatically quote (non-null) strings and chars when editing.
            else if (type.IsString())
            {
                if (!value.IsNull)
                {
                    return(this.GetValueString(
                               value,
                               inspectionContext,
                               ObjectDisplayOptions.UseQuotes
                               | ObjectDisplayOptions.EscapeNonPrintableCharacters,
                               GetValueFlags.None
                               ));
                }
            }
            else if (type.IsCharacter())
            {
                return(this.GetValueStringForCharacter(
                           value,
                           inspectionContext,
                           ObjectDisplayOptions.UseQuotes
                           | ObjectDisplayOptions.EscapeNonPrintableCharacters
                           ));
            }

            return(null);
        }
Пример #5
0
        private string GetValueString(
            DkmClrValue value,
            DkmInspectionContext inspectionContext,
            ObjectDisplayOptions options,
            GetValueFlags flags
            )
        {
            if (value.IsError())
            {
                return((string)value.HostObjectValue);
            }

            if (UsesHexadecimalNumbers(inspectionContext))
            {
                options |= ObjectDisplayOptions.UseHexadecimalNumbers;
            }

            var lmrType = value.Type.GetLmrType();

            if (IsPredefinedType(lmrType) && !lmrType.IsObject())
            {
                if (lmrType.IsString())
                {
                    var stringValue = (string)value.HostObjectValue;
                    if (stringValue == null)
                    {
                        return(_nullString);
                    }
                    return(IncludeObjectId(value, FormatString(stringValue, options), flags));
                }
                else if (lmrType.IsCharacter())
                {
                    // check if HostObjectValue is null, since any of these types might actually be a synthetic value as well.
                    if (value.HostObjectValue == null)
                    {
                        return(_hostValueNotFoundString);
                    }

                    return(IncludeObjectId(
                               value,
                               FormatLiteral(
                                   (char)value.HostObjectValue,
                                   options | ObjectDisplayOptions.IncludeCodePoints
                                   ),
                               flags
                               ));
                }
                else
                {
                    return(IncludeObjectId(
                               value,
                               FormatPrimitive(
                                   value,
                                   options
                                   & ~(
                                       ObjectDisplayOptions.UseQuotes
                                       | ObjectDisplayOptions.EscapeNonPrintableCharacters
                                       ),
                                   inspectionContext
                                   ),
                               flags
                               ));
                }
            }
            else if (value.IsNull && !lmrType.IsPointer)
            {
                return(_nullString);
            }
            else if (lmrType.IsEnum)
            {
                return(IncludeObjectId(
                           value,
                           GetEnumDisplayString(
                               lmrType,
                               value,
                               options,
                               (flags & GetValueFlags.IncludeTypeName) != 0,
                               inspectionContext
                               ),
                           flags
                           ));
            }
            else if (lmrType.IsArray)
            {
                return(IncludeObjectId(
                           value,
                           GetArrayDisplayString(
                               value.Type.AppDomain,
                               lmrType,
                               value.ArrayDimensions,
                               value.ArrayLowerBounds,
                               options
                               ),
                           flags
                           ));
            }
            else if (lmrType.IsPointer)
            {
                // NOTE: the HostObjectValue will have a size corresponding to the process bitness
                // and FormatPrimitive will adjust accordingly.
                var tmp = FormatPrimitive(
                    value,
                    ObjectDisplayOptions.UseHexadecimalNumbers,
                    inspectionContext
                    ); // Always in hex.
                Debug.Assert(tmp != null);
                return(tmp);
            }
            else if (lmrType.IsNullable())
            {
                var nullableValue = value.GetNullableValue(inspectionContext);
                // It should be impossible to nest nullables, so this recursion should introduce only a single extra stack frame.
                return(nullableValue == null
                  ? _nullString
                  : GetValueString(
                           nullableValue,
                           inspectionContext,
                           ObjectDisplayOptions.None,
                           GetValueFlags.IncludeTypeName
                           ));
            }
            else if (lmrType.IsIntPtr())
            {
                // check if HostObjectValue is null, since any of these types might actually be a synthetic value as well.
                if (value.HostObjectValue == null)
                {
                    return(_hostValueNotFoundString);
                }

                if (IntPtr.Size == 8)
                {
                    var intPtr = ((IntPtr)value.HostObjectValue).ToInt64();
                    return(FormatPrimitiveObject(
                               intPtr,
                               ObjectDisplayOptions.UseHexadecimalNumbers
                               ));
                }
                else
                {
                    var intPtr = ((IntPtr)value.HostObjectValue).ToInt32();
                    return(FormatPrimitiveObject(
                               intPtr,
                               ObjectDisplayOptions.UseHexadecimalNumbers
                               ));
                }
            }
            else if (lmrType.IsUIntPtr())
            {
                // check if HostObjectValue is null, since any of these types might actually be a synthetic value as well.
                if (value.HostObjectValue == null)
                {
                    return(_hostValueNotFoundString);
                }

                if (UIntPtr.Size == 8)
                {
                    var uIntPtr = ((UIntPtr)value.HostObjectValue).ToUInt64();
                    return(FormatPrimitiveObject(
                               uIntPtr,
                               ObjectDisplayOptions.UseHexadecimalNumbers
                               ));
                }
                else
                {
                    var uIntPtr = ((UIntPtr)value.HostObjectValue).ToUInt32();
                    return(FormatPrimitiveObject(
                               uIntPtr,
                               ObjectDisplayOptions.UseHexadecimalNumbers
                               ));
                }
            }
            else
            {
                int cardinality;
                if (lmrType.IsTupleCompatible(out cardinality) && (cardinality > 1))
                {
                    var values = ArrayBuilder <string> .GetInstance();

                    if (value.TryGetTupleFieldValues(cardinality, values, inspectionContext))
                    {
                        return(IncludeObjectId(
                                   value,
                                   GetTupleExpression(values.ToArrayAndFree()),
                                   flags
                                   ));
                    }
                    values.Free();
                }
            }

            // "value.EvaluateToString()" will check "Call string-conversion function on objects in variables windows"
            // (Tools > Options setting) and call "value.ToString()" if appropriate.
            return(IncludeObjectId(
                       value,
                       string.Format(
                           _defaultFormat,
                           value.EvaluateToString(inspectionContext)
                           ?? inspectionContext.GetTypeName(
                               value.Type,
                               CustomTypeInfo: null,
                               FormatSpecifiers: NoFormatSpecifiers
                               )
                           ),
                       flags
                       ));
        }
Пример #6
0
        internal EvalResult CreateDataItem(
            DkmInspectionContext inspectionContext,
            string name,
            TypeAndCustomInfo typeDeclaringMemberAndInfo,
            TypeAndCustomInfo declaredTypeAndInfo,
            DkmClrValue value,
            bool useDebuggerDisplay,
            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 declaredType       = declaredTypeAndInfo.Type;
            var lmrNullableTypeArg = declaredType.GetNullableTypeArgument();

            if (lmrNullableTypeArg != null && !value.HasExceptionThrown())
            {
                Debug.Assert(value.Type.GetProxyType() == null);

                DkmClrValue nullableValue;
                if (value.IsError())
                {
                    expansion = null;
                }
                else if ((nullableValue = value.GetNullableValue(lmrNullableTypeArg, inspectionContext)) == 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.
                    // CONSIDER: The DynamicAttribute for the type argument should just be Skip(1) of the original flag array.
                    expansion = this.GetTypeExpansion(inspectionContext, new TypeAndCustomInfo(DkmClrType.Create(declaredTypeAndInfo.ClrType.AppDomain, lmrNullableTypeArg)), value, ExpansionFlags.IncludeResultsView);
                }
            }
            else if (value.IsError() || (inspectionContext.EvaluationFlags & DkmEvaluationFlags.NoExpansion) != 0)
            {
                expansion = null;
            }
            else
            {
                expansion = DebuggerTypeProxyExpansion.CreateExpansion(
                    this,
                    inspectionContext,
                    name,
                    typeDeclaringMemberAndInfo,
                    declaredTypeAndInfo,
                    value,
                    childShouldParenthesize,
                    fullName,
                    flags.Includes(DkmEvaluationResultFlags.ExceptionThrown) ? null : fullName,
                    formatSpecifiers,
                    flags,
                    Formatter2.GetEditableValueString(value, inspectionContext, declaredTypeAndInfo.Info));
                if (expansion == null)
                {
                    expansion = value.HasExceptionThrown()
                        ? this.GetTypeExpansion(inspectionContext, new TypeAndCustomInfo(value.Type), value, expansionFlags)
                        : this.GetTypeExpansion(inspectionContext, declaredTypeAndInfo, value, expansionFlags);
                }
            }

            return(new EvalResult(
                       ExpansionKind.Default,
                       name,
                       typeDeclaringMemberAndInfo,
                       declaredTypeAndInfo,
                       useDebuggerDisplay: useDebuggerDisplay,
                       value: value,
                       displayValue: null,
                       expansion: expansion,
                       childShouldParenthesize: childShouldParenthesize,
                       fullName: fullName,
                       childFullNamePrefixOpt: flags.Includes(DkmEvaluationResultFlags.ExceptionThrown) ? null : fullName,
                       formatSpecifiers: formatSpecifiers,
                       category: category,
                       flags: flags,
                       editableValue: Formatter2.GetEditableValueString(value, inspectionContext, declaredTypeAndInfo.Info),
                       inspectionContext: inspectionContext));
        }
Пример #7
0
        private static DkmEvaluationResult CreateEvaluationResult(
            DkmInspectionContext inspectionContext,
            DkmClrValue value,
            string name,
            string typeName,
            string display,
            EvalResultDataItem dataItem)
        {
            if (value.IsError())
            {
                // Evaluation failed
                return(DkmFailedEvaluationResult.Create(
                           InspectionContext: inspectionContext,
                           StackFrame: value.StackFrame,
                           Name: name,
                           FullName: dataItem.FullName,
                           ErrorMessage: display,
                           Flags: dataItem.Flags,
                           Type: typeName,
                           DataItem: dataItem));
            }
            else if (dataItem.Kind == ExpansionKind.NativeView)
            {
                // For Native View, create a DkmIntermediateEvaluationResult.  This will allow the C++ EE
                // to take over expansion.
                DkmProcess  process = inspectionContext.RuntimeInstance.Process;
                DkmLanguage cpp     = process.EngineSettings.GetLanguage(new DkmCompilerId(DkmVendorId.Microsoft, DkmLanguageId.Cpp));
                return(DkmIntermediateEvaluationResult.Create(
                           InspectionContext: inspectionContext,
                           StackFrame: value.StackFrame,
                           Name: Resources.NativeView,
                           FullName: dataItem.FullName,
                           Expression: dataItem.Name,
                           IntermediateLanguage: cpp,
                           TargetRuntime: process.GetNativeRuntimeInstance(),
                           DataItem: dataItem));
            }
            else
            {
                ReadOnlyCollection <DkmCustomUIVisualizerInfo> customUIVisualizers = null;

                if (!value.IsNull)
                {
                    DkmCustomUIVisualizerInfo[] customUIVisualizerInfo = value.Type.GetDebuggerCustomUIVisualizerInfo();
                    if (customUIVisualizerInfo != null)
                    {
                        customUIVisualizers = new ReadOnlyCollection <DkmCustomUIVisualizerInfo>(customUIVisualizerInfo);
                    }
                }

                // If the EvalResultData item doesn't specify a particular category, we'll just propagate DkmClrValue.Category,
                // which typically appears to be set to the default value ("Other").
                var category = (dataItem.Category != DkmEvaluationResultCategory.Other) ? dataItem.Category : value.Category;

                // Valid value
                return(DkmSuccessEvaluationResult.Create(
                           InspectionContext: inspectionContext,
                           StackFrame: value.StackFrame,
                           Name: name,
                           FullName: dataItem.FullName,
                           Flags: dataItem.Flags,
                           Value: display,
                           EditableValue: dataItem.EditableValue,
                           Type: typeName,
                           Category: category,
                           Access: value.Access,
                           StorageType: value.StorageType,
                           TypeModifierFlags: value.TypeModifierFlags,
                           Address: value.Address,
                           CustomUIVisualizers: customUIVisualizers,
                           ExternalModules: null,
                           DataItem: dataItem));
            }
        }