Browse Source

Making ExpressionEvaluator statically typed

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5157 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 16 years ago
parent
commit
b461c24712
  1. 4
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugFieldInfo.cs
  2. 28
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugMethodInfo.cs
  3. 9
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugParameterInfo.cs
  4. 24
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugPropertyInfo.cs
  5. 70
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugType.cs
  6. 1
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/IDebugMemberInfo.cs
  7. 258
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/NRefactory/Visitors/ExpressionEvaluator.cs
  8. 5
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Process.cs
  9. 20
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/StackFrame.cs
  10. 30
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Value.cs
  11. 10
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/Tests/ExpressionEvaluator_Tests.cs

4
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugFieldInfo.cs

@ -127,5 +127,9 @@ namespace Debugger.MetaData @@ -127,5 +127,9 @@ namespace Debugger.MetaData
{
return this.FieldType + " " + this.Name;
}
DebugType IDebugMemberInfo.MemberType {
get { return (DebugType)this.FieldType; }
}
}
}

28
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugMethodInfo.cs

@ -179,7 +179,7 @@ namespace Debugger.MetaData @@ -179,7 +179,7 @@ namespace Debugger.MetaData
public override ParameterInfo ReturnParameter {
get {
if (this.MethodDefSig.RetType.Void) return null;
return new DebugParameterInfo(this, string.Empty, this.ReturnType, -1);
return new DebugParameterInfo(this, string.Empty, this.ReturnType, -1, delegate { throw new NotSupportedException(); });
}
}
@ -207,6 +207,15 @@ namespace Debugger.MetaData @@ -207,6 +207,15 @@ namespace Debugger.MetaData
ParameterInfo[] parameters;
public DebugParameterInfo GetParameter(string name)
{
foreach(DebugParameterInfo par in GetParameters()) {
if (par.Name == name)
return par;
}
return null;
}
/// <inheritdoc/>
public override ParameterInfo[] GetParameters()
{
@ -220,12 +229,14 @@ namespace Debugger.MetaData @@ -220,12 +229,14 @@ namespace Debugger.MetaData
} catch {
name = String.Empty;
}
int iCopy = i;
parameters[i] =
new DebugParameterInfo(
this,
name,
DebugType.CreateFromSignature(this.DebugModule, this.MethodDefSig.Parameters[i].Type, declaringType),
i
i,
delegate (StackFrame context) { return context.GetArgumentValue(iCopy); }
);
}
}
@ -467,6 +478,15 @@ namespace Debugger.MetaData @@ -467,6 +478,15 @@ namespace Debugger.MetaData
}
}
public DebugLocalVariableInfo GetLocalVariable(string name)
{
foreach(DebugLocalVariableInfo loc in GetLocalVariables()) {
if (loc.Name == name)
return loc;
}
return null;
}
List<DebugLocalVariableInfo> localVariables;
public List<DebugLocalVariableInfo> GetLocalVariables()
@ -629,5 +649,9 @@ namespace Debugger.MetaData @@ -629,5 +649,9 @@ namespace Debugger.MetaData
{
return methodProps.SigBlob.Adress;
}
DebugType IDebugMemberInfo.MemberType {
get { return (DebugType)this.ReturnType; }
}
}
}

9
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugParameterInfo.cs

@ -12,6 +12,7 @@ namespace Debugger.MetaData @@ -12,6 +12,7 @@ namespace Debugger.MetaData
{
public class DebugParameterInfo : System.Reflection.ParameterInfo
{
ValueGetter getter;
MemberInfo member;
string name;
Type parameterType;
@ -37,12 +38,18 @@ namespace Debugger.MetaData @@ -37,12 +38,18 @@ namespace Debugger.MetaData
get { return position; }
}
public DebugParameterInfo(MemberInfo member, string name, Type parameterType, int position)
public DebugParameterInfo(MemberInfo member, string name, Type parameterType, int position, ValueGetter getter)
{
this.member = member;
this.name = name;
this.parameterType = parameterType;
this.position = position;
this.getter = getter;
}
public Value GetValue(StackFrame context)
{
return getter(context);
}
// public virtual ParameterAttributes Attributes { get; }

24
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugPropertyInfo.cs

@ -193,6 +193,20 @@ namespace Debugger.MetaData @@ -193,6 +193,20 @@ namespace Debugger.MetaData
get { return (getMethod ?? setMethod).IsStatic; }
}
DebugType IDebugMemberInfo.MemberType {
get { return (DebugType)this.PropertyType; }
}
ParameterInfo[] IOverloadable.GetParameters()
{
return GetIndexParameters();
}
IntPtr IOverloadable.GetSignarture()
{
return ((IOverloadable)(getMethod ?? setMethod)).GetSignarture();
}
/// <inheritdoc/>
public override string ToString()
{
@ -215,15 +229,5 @@ namespace Debugger.MetaData @@ -215,15 +229,5 @@ namespace Debugger.MetaData
}
return sb.ToString();
}
ParameterInfo[] IOverloadable.GetParameters()
{
return GetIndexParameters();
}
IntPtr IOverloadable.GetSignarture()
{
return ((IOverloadable)(getMethod ?? setMethod)).GetSignarture();
}
}
}

70
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugType.cs

@ -31,6 +31,7 @@ namespace Debugger.MetaData @@ -31,6 +31,7 @@ namespace Debugger.MetaData
{
public const BindingFlags BindingFlagsAll = BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
public const BindingFlags BindingFlagsAllDeclared = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
public const BindingFlags BindingFlagsAllInScope = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
Module module;
ICorDebugType corType;
@ -286,9 +287,11 @@ namespace Debugger.MetaData @@ -286,9 +287,11 @@ namespace Debugger.MetaData
// Filter by name
IEnumerable<List<MemberInfo>> searchScope;
if (name != null) {
if (!membersByName.ContainsKey(name))
return new T[] {};
searchScope = new List<MemberInfo>[] { membersByName[name] };
if (membersByName.ContainsKey(name)) {
searchScope = new List<MemberInfo>[] { membersByName[name] };
} else {
searchScope = new List<MemberInfo>[] { };
}
} else {
searchScope = membersByName.Values;
}
@ -326,8 +329,11 @@ namespace Debugger.MetaData @@ -326,8 +329,11 @@ namespace Debugger.MetaData
// Do not include static types
bindingFlags = bindingFlags & ~BindingFlags.Static;
}
T[] superResults = ((DebugType)this.BaseType).GetMembers<T>(name, bindingFlags, filter);
results.AddRange(superResults);
// Any flags left?
if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) != 0) {
T[] superResults = ((DebugType)this.BaseType).GetMembers<T>(name, bindingFlags, filter);
results.AddRange(superResults);
}
}
return results.ToArray();
@ -590,15 +596,18 @@ namespace Debugger.MetaData @@ -590,15 +596,18 @@ namespace Debugger.MetaData
public MemberInfo[] GetFieldsAndNonIndexedProperties(BindingFlags bindingAttr)
{
return GetMembers<MemberInfo>(null, bindingAttr, delegate (MemberInfo info) {
if (info is FieldInfo)
return true;
if (info is PropertyInfo) {
return ((PropertyInfo)info).GetGetMethod(true) != null &&
((PropertyInfo)info).GetGetMethod(true).GetParameters().Length == 0;
}
return false;
});
return GetMembers<MemberInfo>(null, bindingAttr, IsFieldOrNonIndexedProperty);
}
public static bool IsFieldOrNonIndexedProperty(MemberInfo info)
{
if (info is FieldInfo)
return true;
if (info is PropertyInfo) {
return ((PropertyInfo)info).GetGetMethod(true) != null &&
((PropertyInfo)info).GetGetMethod(true).GetParameters().Length == 0;
}
return false;
}
public PropertyInfo[] GetProperties(string name, BindingFlags bindingAttr)
@ -1241,10 +1250,43 @@ namespace Debugger.MetaData @@ -1241,10 +1250,43 @@ namespace Debugger.MetaData
membersByToken[member.MetadataToken] = member;
}
public override bool Equals(object o)
{
DebugType other = o as DebugType;
if (other == null)
return false;
return this.MetadataToken == other.MetadataToken && // Performance optimization
this.DebugModule == other.DebugModule &&
this.FullName == other.FullName;
}
public override int GetHashCode()
{
return this.FullName.GetHashCode();
}
public static bool operator == (DebugType a, DebugType b)
{
if ((object)a == (object)b)
return true;
if (((object)a == null) || ((object)b == null))
return false;
return a.Equals(b);
}
public static bool operator != (DebugType a, DebugType b)
{
return !(a == b);
}
/// <inheritdoc/>
public override string ToString()
{
return this.FullName;
}
DebugType IDebugMemberInfo.MemberType {
get { return null; }
}
}
}

1
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/IDebugMemberInfo.cs

@ -19,5 +19,6 @@ namespace Debugger.MetaData @@ -19,5 +19,6 @@ namespace Debugger.MetaData
bool IsAssembly { get; }
bool IsFamily { get; }
bool IsPrivate { get; }
DebugType MemberType { get; }
}
}

258
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/NRefactory/Visitors/ExpressionEvaluator.cs

@ -22,6 +22,30 @@ namespace ICSharpCode.NRefactory.Visitors @@ -22,6 +22,30 @@ namespace ICSharpCode.NRefactory.Visitors
public EvaluateException(INode code, string msgFmt, params object[] msgArgs):base(code, string.Format(msgFmt, msgArgs)) {}
}
class TypedValue
{
Value value;
DebugType type;
public Value Value {
get { return value; }
}
public DebugType Type {
get { return type; }
}
public object PrimitiveValue {
get { return value.PrimitiveValue; }
}
public TypedValue(Value value, DebugType type)
{
this.value = value;
this.type = type;
}
}
public class ExpressionEvaluator: NotImplementedAstVisitor
{
const BindingFlags BindingFlagsAll = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
@ -64,7 +88,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -64,7 +88,7 @@ namespace ICSharpCode.NRefactory.Visitors
if (context == null) throw new ArgumentNullException("context");
if (context.IsInvalid) throw new DebuggerException("The context is no longer valid");
return new ExpressionEvaluator(context).Evaluate(code, false);
return new ExpressionEvaluator(context).Evaluate(code, false).Value;
}
/// <summary>
@ -127,28 +151,27 @@ namespace ICSharpCode.NRefactory.Visitors @@ -127,28 +151,27 @@ namespace ICSharpCode.NRefactory.Visitors
}
}
Value Evaluate(INode expression)
TypedValue Evaluate(INode expression)
{
return Evaluate(expression, true);
}
Value Evaluate(INode expression, bool permRef)
TypedValue Evaluate(INode expression, bool permRef)
{
// Try to get the value from cache
// (the cache is cleared when the process is resumed)
Value val;
TypedValue val;
if (context.Process.CachedExpressions.TryGetValue(expression, out val)) {
if (val == null || !val.IsInvalid) {
if (val == null || !val.Value.IsInvalid)
return val;
}
}
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
try {
val = (Value)expression.AcceptVisitor(this, null);
val = (TypedValue)expression.AcceptVisitor(this, null);
if (val != null && permRef)
val = val.GetPermanentReference();
val = new TypedValue(val.Value.GetPermanentReference(), val.Type);
} catch (GetValueException e) {
e.Expression = expression;
throw;
@ -159,7 +182,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -159,7 +182,7 @@ namespace ICSharpCode.NRefactory.Visitors
context.Process.TraceMessage("Evaluated: {0} in {1} ms total", expression.PrettyPrint(), watch.ElapsedMilliseconds);
}
if (val != null && val.IsInvalid)
if (val != null && val.Value.IsInvalid)
throw new DebuggerException("Expression \"" + expression.PrettyPrint() + "\" is invalid right after evaluation");
// Add the result to cache
@ -179,7 +202,25 @@ namespace ICSharpCode.NRefactory.Visitors @@ -179,7 +202,25 @@ namespace ICSharpCode.NRefactory.Visitors
this.context = context;
}
public DebugType GetDebugType(INode expr)
Value[] GetValues(List<TypedValue> typedVals)
{
List<Value> vals = new List<Value>(typedVals.Count);
foreach(TypedValue typedVal in typedVals) {
vals.Add(typedVal.Value);
}
return vals.ToArray();
}
DebugType[] GetTypes(List<TypedValue> typedVals)
{
List<DebugType> types = new List<DebugType>(typedVals.Count);
foreach(TypedValue typedVal in typedVals) {
types.Add(typedVal.Type);
}
return types.ToArray();
}
DebugType GetDebugType(INode expr)
{
if (expr is ParenthesizedExpression) {
return GetDebugType(((ParenthesizedExpression)expr).Expression);
@ -190,6 +231,12 @@ namespace ICSharpCode.NRefactory.Visitors @@ -190,6 +231,12 @@ namespace ICSharpCode.NRefactory.Visitors
}
}
TypedValue CreateValue(object primitiveValue)
{
Value val = Eval.CreateValue(context.AppDomain, primitiveValue);
return new TypedValue(val, val.Type);
}
public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data)
{
BinaryOperatorType op;
@ -211,7 +258,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -211,7 +258,7 @@ namespace ICSharpCode.NRefactory.Visitors
default: throw new GetValueException("Unknown operator " + assignmentExpression.Op);
}
Value right;
TypedValue right;
if (op == BinaryOperatorType.None) {
right = Evaluate(assignmentExpression.Right);
} else {
@ -223,16 +270,16 @@ namespace ICSharpCode.NRefactory.Visitors @@ -223,16 +270,16 @@ namespace ICSharpCode.NRefactory.Visitors
}
// We can not have perfRef because we need to be able to set the value
Value left = (Value)assignmentExpression.Left.AcceptVisitor(this, null);
TypedValue left = (TypedValue)assignmentExpression.Left.AcceptVisitor(this, null);
if (left == null) {
// Can this happen?
throw new GetValueException(string.Format("\"{0}\" can not be set", assignmentExpression.Left.PrettyPrint()));
}
if (!left.IsReference && left.Type.FullName != right.Type.FullName) {
if (!left.Value.IsReference && left.Type.FullName != right.Type.FullName) {
throw new GetValueException(string.Format("Type {0} expected, {1} seen", left.Type.FullName, right.Type.FullName));
}
left.SetValue(right);
left.Value.SetValue(right.Value);
return right;
}
@ -257,7 +304,12 @@ namespace ICSharpCode.NRefactory.Visitors @@ -257,7 +304,12 @@ namespace ICSharpCode.NRefactory.Visitors
public override object VisitCastExpression(CastExpression castExpression, object data)
{
return Evaluate(castExpression.Expression);
TypedValue val = Evaluate(castExpression.Expression);
DebugType castTo = castExpression.CastTo.ResolveType(context.AppDomain);
if (!castTo.IsAssignableFrom(val.Value.Type))
throw new GetValueException("Can not cast {0} to {1}", val.Value.Type.FullName, castTo.FullName);
// TODO: Primitive values
return new TypedValue(val.Value, castTo);
}
public override object VisitIdentifierExpression(IdentifierExpression identifierExpression, object data)
@ -266,91 +318,93 @@ namespace ICSharpCode.NRefactory.Visitors @@ -266,91 +318,93 @@ namespace ICSharpCode.NRefactory.Visitors
if (identifier == "__exception") {
if (context.Thread.CurrentException != null) {
return context.Thread.CurrentException.Value;
return new TypedValue(
context.Thread.CurrentException.Value,
DebugType.CreateFromType(context.AppDomain.Mscorlib, typeof(System.Exception))
);
} else {
throw new GetValueException("No current exception");
}
}
Value arg = context.GetArgumentValue(identifier);
if (arg != null) return arg;
DebugParameterInfo par = context.MethodInfo.GetParameter(identifier);
if (par != null)
return new TypedValue(par.GetValue(context), (DebugType)par.ParameterType);
Value local = context.GetLocalVariableValue(identifier);
if (local != null) return local;
DebugLocalVariableInfo loc = context.MethodInfo.GetLocalVariable(identifier);
if (loc != null)
return new TypedValue(loc.GetValue(context), (DebugType)loc.LocalType);
// Instance class members
Value thisValue = GetThisValue();
// Note that the method might be generated instance method that represents anonymous method
TypedValue thisValue = GetThisValue();
if (thisValue != null) {
Value member = thisValue.GetMemberValue(identifier);
if (member != null) return member;
IDebugMemberInfo instMember = (IDebugMemberInfo)thisValue.Type.GetMember<MemberInfo>(identifier, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, DebugType.IsFieldOrNonIndexedProperty);
if (instMember != null)
return new TypedValue(Value.GetMemberValue(thisValue.Value, (MemberInfo)instMember), instMember.MemberType);
}
// Static class members
IDebugMemberInfo memberInfo =
(IDebugMemberInfo)context.MethodInfo.DeclaringType.GetField(identifier) ??
(IDebugMemberInfo)context.MethodInfo.DeclaringType.GetProperty(identifier);
if (memberInfo != null && memberInfo.IsStatic) {
return Value.GetMemberValue(null, (MemberInfo)memberInfo, null);
}
// TODO: Static members in outter class
IDebugMemberInfo statMember = (IDebugMemberInfo)((DebugType)context.MethodInfo.DeclaringType).GetMember<MemberInfo>(identifier, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, DebugType.IsFieldOrNonIndexedProperty);
if (statMember != null)
return new TypedValue(Value.GetMemberValue(null, (MemberInfo)statMember), statMember.MemberType);
throw new GetValueException("Identifier \"" + identifier + "\" not found in this context");
}
public override object VisitIndexerExpression(IndexerExpression indexerExpression, object data)
{
List<Value> indexes = new List<Value>();
TypedValue target = Evaluate(indexerExpression.TargetObject);
List<TypedValue> indexes = new List<TypedValue>();
foreach(Expression indexExpr in indexerExpression.Indexes) {
Value indexValue = Evaluate(indexExpr);
indexes.Add(indexValue);
indexes.Add(Evaluate(indexExpr));
}
Value target = Evaluate(indexerExpression.TargetObject);
if (target.Type.IsArray) {
List<int> intIndexes = new List<int>();
foreach(Value index in indexes) {
if (!index.Type.IsInteger) throw new GetValueException("Integer expected for indexer");
foreach(TypedValue index in indexes) {
if (!index.Type.IsInteger)
throw new GetValueException("Integer expected for indexer");
intIndexes.Add((int)index.PrimitiveValue);
}
return target.GetArrayElement(intIndexes.ToArray());
return new TypedValue(
target.Value.GetArrayElement(intIndexes.ToArray()),
(DebugType)target.Type.GetElementType()
);
}
if (target.Type.IsPrimitive && target.PrimitiveValue is string) {
if (target.Type.FullName == typeof(string).FullName) {
if (indexes.Count == 1 && indexes[0].Type.IsInteger) {
int index = (int)indexes[0].PrimitiveValue;
return Eval.CreateValue(context.AppDomain, ((string)target.PrimitiveValue)[index]);
return CreateValue(((string)target.PrimitiveValue)[index]);
} else {
throw new GetValueException("Expected single integer index");
}
}
Type[] indexerTypes = GetTypes(indexerExpression.Indexes);
DebugPropertyInfo pi = (DebugPropertyInfo)target.Type.GetProperty("Item", indexerTypes);
if (pi == null) throw new GetValueException("The object does not have an indexer property");
return target.GetPropertyValue(pi, indexes.ToArray());
}
Type[] GetTypes(List<Expression> args)
{
List<DebugType> argTypes = new List<DebugType>();
foreach(Expression arg in args) {
DebugType argType = GetDebugType(arg) ?? Evaluate(arg).Type;
argTypes.Add(argType);
}
return argTypes.ToArray();
DebugPropertyInfo pi = (DebugPropertyInfo)target.Type.GetProperty("Item", GetTypes(indexes));
if (pi == null)
throw new GetValueException("The object does not have an indexer property");
return new TypedValue(
target.Value.GetPropertyValue(pi, GetValues(indexes)),
(DebugType)pi.PropertyType
);
}
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
Value target;
TypedValue target;
DebugType targetType;
string methodName;
MemberReferenceExpression memberRef = invocationExpression.TargetObject as MemberReferenceExpression;
if (memberRef != null) {
// TODO: Optimize
try {
// Instance
target = Evaluate(memberRef.TargetObject);
targetType = GetDebugType(memberRef.TargetObject) ?? target.Type;
targetType = target.Type;
} catch (GetValueException) {
// Static
target = null;
@ -369,43 +423,42 @@ namespace ICSharpCode.NRefactory.Visitors @@ -369,43 +423,42 @@ namespace ICSharpCode.NRefactory.Visitors
throw new GetValueException("Member reference expected for method invocation");
}
}
Type[] argTypes = GetTypes(invocationExpression.Arguments);
MethodInfo method = targetType.GetMethod(methodName, BindingFlagsAll, null, argTypes, null);
if (method == null)
throw new GetValueException("Method " + methodName + " not found");
List<Value> args = new List<Value>();
List<TypedValue> args = new List<TypedValue>();
foreach(Expression expr in invocationExpression.Arguments) {
args.Add(Evaluate(expr));
}
return Value.InvokeMethod(target, method, args.ToArray());
MethodInfo method = targetType.GetMethod(methodName, DebugType.BindingFlagsAllInScope, null, GetTypes(args), null);
if (method == null)
throw new GetValueException("Method " + methodName + " not found");
Value retVal = Value.InvokeMethod(target != null ? target.Value : null, method, GetValues(args));
if (retVal == null)
return null;
return new TypedValue(retVal, (DebugType)method.ReturnType);
}
public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data)
{
List<Expression> constructorParameters = objectCreateExpression.Parameters;
DebugType[] constructorParameterTypes = new DebugType[constructorParameters.Count];
for (int i = 0; i < constructorParameters.Count; i++) {
constructorParameterTypes[i] = GetDebugType(constructorParameters[i]);
}
Value[] constructorParameterValues = new Value[constructorParameters.Count];
for (int i = 0; i < constructorParameters.Count; i++) {
constructorParameterValues[i] = Evaluate(constructorParameters[i]);
}
return Eval.NewObject(
objectCreateExpression.CreateType.ResolveType(context.AppDomain),
constructorParameterValues,
constructorParameterTypes
List<TypedValue> ctorArgs = new List<TypedValue>(objectCreateExpression.Parameters.Count);
foreach(Expression argExpr in objectCreateExpression.Parameters) {
ctorArgs.Add(Evaluate(argExpr));
}
// TODO: Use reflection
// TODO: Arrays
DebugType type = objectCreateExpression.CreateType.ResolveType(context.AppDomain);
return new TypedValue(
Eval.NewObject((DebugType)type, GetValues(ctorArgs), GetTypes(ctorArgs)),
type
);
}
public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data)
{
Value target;
TypedValue target;
DebugType targetType;
try {
// Instance
target = Evaluate(memberReferenceExpression.TargetObject);
targetType = GetDebugType(memberReferenceExpression.TargetObject) ?? target.Type;
targetType = target.Type;
} catch (GetValueException) {
// Static
target = null;
@ -413,13 +466,13 @@ namespace ICSharpCode.NRefactory.Visitors @@ -413,13 +466,13 @@ namespace ICSharpCode.NRefactory.Visitors
if (targetType == null)
throw;
}
MemberInfo[] memberInfos = targetType.GetMember(memberReferenceExpression.MemberName, BindingFlagsAllDeclared);
if (memberInfos.Length == 0)
memberInfos = targetType.GetMember(memberReferenceExpression.MemberName, BindingFlagsAll);
MemberInfo[] memberInfos = targetType.GetMember(memberReferenceExpression.MemberName, DebugType.BindingFlagsAllInScope);
if (memberInfos.Length == 0)
throw new GetValueException("Member \"" + memberReferenceExpression.MemberName + "\" not found");
Value member = Value.GetMemberValue(target, memberInfos[0]);
return member;
return new TypedValue(
Value.GetMemberValue(target != null ? target.Value : null, memberInfos[0]),
((IDebugMemberInfo)memberInfos[0]).MemberType
);
}
public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data)
@ -429,38 +482,41 @@ namespace ICSharpCode.NRefactory.Visitors @@ -429,38 +482,41 @@ namespace ICSharpCode.NRefactory.Visitors
public override object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data)
{
return Eval.CreateValue(context.AppDomain, primitiveExpression.Value);
return CreateValue(primitiveExpression.Value);
}
Value GetThisValue()
TypedValue GetThisValue()
{
// This is needed so that captured 'this' is supported
foreach(DebugLocalVariableInfo locVar in context.MethodInfo.GetLocalVariables()) {
if (locVar.IsThis)
return locVar.GetValue(context);
return new TypedValue(locVar.GetValue(context), (DebugType)locVar.LocalType);
}
return null;
}
public override object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data)
{
Value thisValue = GetThisValue();
TypedValue thisValue = GetThisValue();
if (thisValue == null)
throw new GetValueException(context.MethodInfo.FullName + " does not have \"this\"");
throw new GetValueException(context.MethodInfo.FullName + " is static method and does not have \"this\"");
return thisValue;
}
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data)
{
Value value = Evaluate(unaryOperatorExpression.Expression);
TypedValue value = Evaluate(unaryOperatorExpression.Expression);
UnaryOperatorType op = unaryOperatorExpression.Op;
if (op == UnaryOperatorType.Dereference) {
if (!value.Type.IsPointer) throw new GetValueException("Target object is not a pointer");
return value.Dereference(); // TODO: Test
if (!value.Type.IsPointer)
throw new GetValueException("Target object is not a pointer");
// TODO: Test
return new TypedValue(value.Value.Dereference(), (DebugType)value.Type.GetElementType());
}
if (!value.Type.IsPrimitive) throw new GetValueException("Primitive value expected");
if (!value.Type.IsPrimitive)
throw new GetValueException("Primitive value expected");
object val = value.PrimitiveValue;
@ -507,34 +563,36 @@ namespace ICSharpCode.NRefactory.Visitors @@ -507,34 +563,36 @@ namespace ICSharpCode.NRefactory.Visitors
}
}
if (result == null) throw new GetValueException("Unsuppored unary expression " + op);
if (result == null)
throw new GetValueException("Unsuppored unary expression " + op);
return Eval.CreateValue(context.AppDomain, result);
return CreateValue(result);
}
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
{
Value left = Evaluate(binaryOperatorExpression.Left);
Value right = Evaluate(binaryOperatorExpression.Right);
TypedValue left = Evaluate(binaryOperatorExpression.Left);
TypedValue right = Evaluate(binaryOperatorExpression.Right);
object result = VisitBinaryOperatorExpressionInternal(left, right, binaryOperatorExpression.Op);
// Conver long to int if possible
if (result is long && int.MinValue <= (long)result && (long)result <= int.MaxValue) result = (int)(long)result;
return Eval.CreateValue(context.AppDomain, result);
if (result is long && int.MinValue <= (long)result && (long)result <= int.MaxValue)
result = (int)(long)result;
return CreateValue(result);
}
public object VisitBinaryOperatorExpressionInternal(Value leftValue, Value rightValue, BinaryOperatorType op)
object VisitBinaryOperatorExpressionInternal(TypedValue leftValue, TypedValue rightValue, BinaryOperatorType op)
{
object left = leftValue.Type.IsPrimitive ? leftValue.PrimitiveValue : null;
object right = rightValue.Type.IsPrimitive ? rightValue.PrimitiveValue : null;
// Both are classes - do reference comparison
if (left == null && right == null) {
if (leftValue.IsNull || rightValue.IsNull) {
return leftValue.IsNull && rightValue.IsNull;
if (leftValue.Value.IsNull || rightValue.Value.IsNull) {
return leftValue.Value.IsNull && rightValue.Value.IsNull;
} else {
// TODO: Make sure this works for byrefs and arrays
return leftValue.Address == rightValue.Address;
return leftValue.Value.Address == rightValue.Value.Address;
}
}

5
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Process.cs

@ -5,9 +5,10 @@ @@ -5,9 +5,10 @@
// <version>$Revision$</version>
// </file>
using Debugger.Internal;
using ICSharpCode.NRefactory.Visitors;
using System;
using System.Collections.Generic;
using Debugger.Internal;
using Debugger.Interop.CorDebug;
using ICSharpCode.NRefactory.Ast;
@ -214,7 +215,7 @@ namespace Debugger @@ -214,7 +215,7 @@ namespace Debugger
internal bool TerminateCommandIssued = false;
internal Queue<Breakpoint> BreakpointHitEventQueue = new Queue<Breakpoint>();
internal Dictionary<INode, Value> CachedExpressions = new Dictionary<INode, Value>();
internal Dictionary<INode, TypedValue> CachedExpressions = new Dictionary<INode, TypedValue>();
#region Events

20
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/StackFrame.cs

@ -314,12 +314,10 @@ namespace Debugger @@ -314,12 +314,10 @@ namespace Debugger
/// <returns> Null if not found </returns>
public Value GetArgumentValue(string name)
{
for(int i = 0; i < this.ArgumentCount; i++) {
if (this.MethodInfo.GetParameters()[i].Name == name) {
return GetArgumentValue(i);
}
}
return null;
DebugParameterInfo par = this.MethodInfo.GetParameter(name);
if (par == null)
return null;
return GetArgumentValue(par.Position);
}
/// <summary> Gets argument with a given index </summary>
@ -360,12 +358,10 @@ namespace Debugger @@ -360,12 +358,10 @@ namespace Debugger
/// <returns> Null if not found </returns>
public Value GetLocalVariableValue(string name)
{
foreach(DebugLocalVariableInfo locVar in this.MethodInfo.GetLocalVariables()) {
if (locVar.Name == name) {
return locVar.GetValue(this);
}
}
return null;
DebugLocalVariableInfo loc = this.MethodInfo.GetLocalVariable(name);
if (loc == null)
return null;
return loc.GetValue(this);
}
public override bool Equals(object obj)

30
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Value.cs

@ -381,6 +381,16 @@ namespace Debugger @@ -381,6 +381,16 @@ namespace Debugger
#region Convenience overload methods
/// <summary> Get a field or property of an object with a given name. </summary>
/// <returns> Null if not found </returns>
public Value GetMemberValue(string name)
{
MemberInfo memberInfo = this.Type.GetMember<MemberInfo>(name, DebugType.BindingFlagsAllInScope, DebugType.IsFieldOrNonIndexedProperty);
if (memberInfo == null)
return null;
return GetMemberValue(memberInfo);
}
/// <summary> Get the value of given member. </summary>
public Value GetMemberValue(MemberInfo memberInfo, params Value[] arguments)
{
@ -600,26 +610,6 @@ namespace Debugger @@ -600,26 +610,6 @@ namespace Debugger
);
}
/// <summary> Get a field or property of an object with a given name. </summary>
/// <returns> Null if not found </returns>
public Value GetMemberValue(string name)
{
DebugType currentType = this.Type;
while (currentType != null) {
MemberInfo memberInfo = currentType.GetMember<MemberInfo>(name, DebugType.BindingFlagsAll, null);
if (memberInfo != null) {
if (memberInfo is DebugFieldInfo) {
return this.GetFieldValue((DebugFieldInfo)memberInfo);
}
if (memberInfo is DebugPropertyInfo) {
return this.GetPropertyValue((DebugPropertyInfo)memberInfo);
}
}
currentType = (DebugType)currentType.BaseType;
}
return null;
}
#endregion
public override string ToString()

10
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/Tests/ExpressionEvaluator_Tests.cs

@ -262,6 +262,14 @@ namespace Debugger.Tests { @@ -262,6 +262,14 @@ namespace Debugger.Tests {
}
}
// Type equality
DebugLocalVariableInfo loc = process.SelectedStackFrame.MethodInfo.GetLocalVariable("list");
Type locType = loc.LocalType;
Type valType = loc.GetValue(process.SelectedStackFrame).Type;
ObjectDump("TypesIdentitcal", object.ReferenceEquals(locType, valType));
ObjectDump("TypesEqual", locType == valType);
EndTest();
}
@ -379,6 +387,8 @@ namespace Debugger.Tests { @@ -379,6 +387,8 @@ namespace Debugger.Tests {
<Eval> </Eval>
<TypeResulution> typeof(System.Int32*[][,]) = System.Int32*[,][] (ok)</TypeResulution>
<TypeResulution> typeof(Debugger.Tests.ExpressionEvaluator_Tests.A&lt;System.Int32&gt;.B.C&lt;System.Char&gt;[][,]) = Debugger.Tests.ExpressionEvaluator_Tests+A`1+B+C`1[System.Int32,System.Char][,][] (ok)</TypeResulution>
<TypesIdentitcal>False</TypesIdentitcal>
<TypesEqual>True</TypesEqual>
<ProcessExited />
</Test>
</DebuggerTests>

Loading…
Cancel
Save