diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugFieldInfo.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugFieldInfo.cs index 7c305045ca..10477f7db9 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugFieldInfo.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugFieldInfo.cs @@ -127,5 +127,9 @@ namespace Debugger.MetaData { return this.FieldType + " " + this.Name; } + + DebugType IDebugMemberInfo.MemberType { + get { return (DebugType)this.FieldType; } + } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugMethodInfo.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugMethodInfo.cs index 25a56c0b6d..43670c5be5 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugMethodInfo.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugMethodInfo.cs @@ -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 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 } 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 } } + 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 { return methodProps.SigBlob.Adress; } + + DebugType IDebugMemberInfo.MemberType { + get { return (DebugType)this.ReturnType; } + } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugParameterInfo.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugParameterInfo.cs index 9b527f2706..e82d6ded2d 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugParameterInfo.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugParameterInfo.cs @@ -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 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; } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugPropertyInfo.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugPropertyInfo.cs index efd4e1679c..18b823f35e 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugPropertyInfo.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugPropertyInfo.cs @@ -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 } return sb.ToString(); } - - ParameterInfo[] IOverloadable.GetParameters() - { - return GetIndexParameters(); - } - - IntPtr IOverloadable.GetSignarture() - { - return ((IOverloadable)(getMethod ?? setMethod)).GetSignarture(); - } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugType.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugType.cs index ce22eb17c9..669fdf9fc4 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugType.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/DebugType.cs @@ -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 // 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 // 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 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 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; } + } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/IDebugMemberInfo.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/IDebugMemberInfo.cs index a715e4893a..72d19f46ab 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/IDebugMemberInfo.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/MetaData/IDebugMemberInfo.cs @@ -19,5 +19,6 @@ namespace Debugger.MetaData bool IsAssembly { get; } bool IsFamily { get; } bool IsPrivate { get; } + DebugType MemberType { get; } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/NRefactory/Visitors/ExpressionEvaluator.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/NRefactory/Visitors/ExpressionEvaluator.cs index 4b8acb6c47..2ae9f96dd9 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/NRefactory/Visitors/ExpressionEvaluator.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/NRefactory/Visitors/ExpressionEvaluator.cs @@ -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 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 } } - 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 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 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 } } + 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 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 } // 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 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 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 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 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 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 } } - 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; } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Process.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Process.cs index a6e984c208..b4ba197847 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Process.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Process.cs @@ -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 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 diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/StackFrame.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/StackFrame.cs index 9d0e8641df..f26cca5def 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/StackFrame.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/StackFrame.cs @@ -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 /// <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) diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Value.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Value.cs index 674d866fb2..8b3f5fdf37 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Value.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Value.cs @@ -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 ); } - /// <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() diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/Tests/ExpressionEvaluator_Tests.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/Tests/ExpressionEvaluator_Tests.cs index e828940e03..96d2717bcf 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/Tests/ExpressionEvaluator_Tests.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/Tests/ExpressionEvaluator_Tests.cs @@ -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 { <Eval> </Eval> <TypeResulution> typeof(System.Int32*[][,]) = System.Int32*[,][] (ok)</TypeResulution> <TypeResulution> typeof(Debugger.Tests.ExpressionEvaluator_Tests.A<System.Int32>.B.C<System.Char>[][,]) = Debugger.Tests.ExpressionEvaluator_Tests+A`1+B+C`1[System.Int32,System.Char][,][] (ok)</TypeResulution> + <TypesIdentitcal>False</TypesIdentitcal> + <TypesEqual>True</TypesEqual> <ProcessExited /> </Test> </DebuggerTests>