Browse Source

implement display of enum values in debugger tooltips

pull/45/merge
Siegfried Pammer 12 years ago
parent
commit
9d92c13c9d
  1. 12
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs
  2. 7
      src/AddIns/Debugger/Debugger.Core/Value.cs
  3. 73
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs

12
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs

@ -9,6 +9,8 @@ using System.Linq;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using Debugger.AddIn.Visualizers; using Debugger.AddIn.Visualizers;
using Debugger.MetaData; using Debugger.MetaData;
using ICSharpCode.Core; using ICSharpCode.Core;
@ -147,14 +149,20 @@ namespace Debugger.AddIn.TreeModel
} }
} else if (val.Type.Kind == TypeKind.Pointer) { } else if (val.Type.Kind == TypeKind.Pointer) {
fullValue = String.Format("0x{0:X}", val.PointerAddress); fullValue = String.Format("0x{0:X}", val.PointerAddress);
} else if (val.Type.FullName == typeof(string).FullName) { } else if (val.Type.IsKnownType(KnownTypeCode.String)) {
fullValue = '"' + val.InvokeToString(WindowsDebugger.EvalThread).Replace("\n", "\\n").Replace("\t", "\\t").Replace("\r", "\\r").Replace("\0", "\\0").Replace("\b", "\\b").Replace("\a", "\\a").Replace("\f", "\\f").Replace("\v", "\\v").Replace("\"", "\\\"") + '"'; fullValue = '"' + val.InvokeToString(WindowsDebugger.EvalThread).Replace("\n", "\\n").Replace("\t", "\\t").Replace("\r", "\\r").Replace("\0", "\\0").Replace("\b", "\\b").Replace("\a", "\\a").Replace("\f", "\\f").Replace("\v", "\\v").Replace("\"", "\\\"") + '"';
} else if (val.Type.FullName == typeof(char).FullName) { } else if (val.Type.IsKnownType(KnownTypeCode.Char)) {
fullValue = "'" + val.InvokeToString(WindowsDebugger.EvalThread).Replace("\n", "\\n").Replace("\t", "\\t").Replace("\r", "\\r").Replace("\0", "\\0").Replace("\b", "\\b").Replace("\a", "\\a").Replace("\f", "\\f").Replace("\v", "\\v").Replace("\"", "\\\"") + "'"; fullValue = "'" + val.InvokeToString(WindowsDebugger.EvalThread).Replace("\n", "\\n").Replace("\t", "\\t").Replace("\r", "\\r").Replace("\0", "\\0").Replace("\b", "\\b").Replace("\a", "\\a").Replace("\f", "\\f").Replace("\v", "\\v").Replace("\"", "\\\"") + "'";
} else if ((val.Type.Kind == TypeKind.Class || val.Type.Kind == TypeKind.Struct)) { } else if ((val.Type.Kind == TypeKind.Class || val.Type.Kind == TypeKind.Struct)) {
fullValue = val.FormatByDebuggerDisplayAttribute(WindowsDebugger.EvalThread); fullValue = val.FormatByDebuggerDisplayAttribute(WindowsDebugger.EvalThread);
if (fullValue == null) if (fullValue == null)
fullValue = val.InvokeToString(WindowsDebugger.EvalThread); fullValue = val.InvokeToString(WindowsDebugger.EvalThread);
} else if (val.Type.Kind == TypeKind.Enum) {
var primitiveValue = val.PrimitiveValue;
var builder = new TypeSystemAstBuilder();
builder.AlwaysUseShortTypeNames = true;
AstNode node = builder.ConvertConstantValue(val.Type, primitiveValue);
fullValue = node + "=" + primitiveValue;
} else { } else {
fullValue = val.AsString(); fullValue = val.AsString();
} }

7
src/AddIns/Debugger/Debugger.Core/Value.cs

@ -289,9 +289,12 @@ namespace Debugger
if (this.IsNull) return null; if (this.IsNull) return null;
return ((ICorDebugStringValue)this.CorReferenceValue.Dereference()).GetString(); return ((ICorDebugStringValue)this.CorReferenceValue.Dereference()).GetString();
} else { } else {
if (!this.Type.IsPrimitiveType()) var type = this.Type;
if (type.Kind == TypeKind.Enum)
type = type.GetDefinition().EnumUnderlyingType;
if (!type.IsPrimitiveType())
throw new DebuggerException("Value is not a primitive type"); throw new DebuggerException("Value is not a primitive type");
return CorGenericValue.GetValue(this.Type.GetDefinition().KnownTypeCode); return CorGenericValue.GetValue(type.GetDefinition().KnownTypeCode);
} }
} }
} }

73
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/TypeSystemAstBuilder.cs

@ -450,11 +450,82 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
else else
return new DefaultValueExpression(ConvertType(type)); return new DefaultValueExpression(ConvertType(type));
} else if (type.Kind == TypeKind.Enum) { } else if (type.Kind == TypeKind.Enum) {
return new CastExpression(ConvertType(type), ConvertConstantValue(type.GetDefinition().EnumUnderlyingType, constantValue)); return ConvertEnumValue(type, constantValue is long ? (long)constantValue : (long)((int)constantValue));
} else { } else {
return new PrimitiveExpression(constantValue); return new PrimitiveExpression(constantValue);
} }
} }
bool IsFlagsEnum(ITypeDefinition type)
{
IType flagsAttributeType = type.Compilation.FindType(typeof(System.FlagsAttribute));
return type.GetAttribute(flagsAttributeType) != null;
}
Expression ConvertEnumValue(IType type, long val)
{
ITypeDefinition enumDefinition = type.GetDefinition();
TypeCode enumBaseTypeCode = ReflectionHelper.GetTypeCode(enumDefinition.EnumUnderlyingType);
foreach (IField field in enumDefinition.Fields) {
if (field.IsConst && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.ConstantValue, false), val))
return ConvertType(type).Member(field.Name);
}
if (IsFlagsEnum(enumDefinition)) {
long enumValue = val;
Expression expr = null;
long negatedEnumValue = ~val;
// limit negatedEnumValue to the appropriate range
switch (enumBaseTypeCode) {
case TypeCode.Byte:
case TypeCode.SByte:
negatedEnumValue &= byte.MaxValue;
break;
case TypeCode.Int16:
case TypeCode.UInt16:
negatedEnumValue &= ushort.MaxValue;
break;
case TypeCode.Int32:
case TypeCode.UInt32:
negatedEnumValue &= uint.MaxValue;
break;
}
Expression negatedExpr = null;
foreach (IField field in enumDefinition.Fields.Where(fld => fld.IsConst)) {
long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.ConstantValue, false);
if (fieldValue == 0)
continue; // skip None enum value
if ((fieldValue & enumValue) == fieldValue) {
var fieldExpression = ConvertType(type).Member(field.Name);
if (expr == null)
expr = fieldExpression;
else
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression);
enumValue &= ~fieldValue;
}
if ((fieldValue & negatedEnumValue) == fieldValue) {
var fieldExpression = ConvertType(type).Member(field.Name);
if (negatedExpr == null)
negatedExpr = fieldExpression;
else
negatedExpr = new BinaryOperatorExpression(negatedExpr, BinaryOperatorType.BitwiseOr, fieldExpression);
negatedEnumValue &= ~fieldValue;
}
}
if (enumValue == 0 && expr != null) {
if (!(negatedEnumValue == 0 && negatedExpr != null && negatedExpr.Descendants.Count() < expr.Descendants.Count())) {
return expr;
}
}
if (negatedEnumValue == 0 && negatedExpr != null) {
return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr);
}
}
return new PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(type));
}
#endregion #endregion
#region Convert Parameter #region Convert Parameter

Loading…
Cancel
Save