Browse Source

ObjectValue split into ObjectValue and ObjectValueClass;

Variable submenus implemented in Debugger.Core

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@1582 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
David Srbecký 19 years ago
parent
commit
a57ab03b7f
  1. 52
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/LocalVarPad.cs
  2. 74
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs
  3. 5
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj
  4. 19
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Exception.cs
  5. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Thread.cs
  6. 12
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs
  7. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Evals/Eval.CallFunctionEval.cs
  8. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs
  9. 237
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs
  10. 227
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs
  11. 2
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs
  12. 4
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/UnavailableValue.cs
  13. 16
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs
  14. 40
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs
  15. 51
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/VariableCollection.cs
  16. 1
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs

52
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Pads/LocalVarPad.cs

@ -95,44 +95,20 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -95,44 +95,20 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
public static void AddVariableCollectionToTree(VariableCollection varCollection, TreeListViewItemCollection tree)
{
TreeListViewItem privateInstanceMenu = new TreeListViewItem(privateMembersName, 0);
TreeListViewItem staticMenu = new TreeListViewItem(staticMembersName, 0);
TreeListViewItem privateStaticMenu = new TreeListViewItem(privateStaticMembersName, 0);
foreach(Variable variable in varCollection) {
if (variable.IsPublic) {
if (variable.IsStatic) {
// Public static
if (staticMenu.TreeListView == null) {
tree.Add(staticMenu);
tree.Sort(false);
}
staticMenu.Items.Add(new TreeListViewDebuggerItem(variable));
} else {
// Public instance
tree.Add(new TreeListViewDebuggerItem(variable));
}
} else {
if (variable.IsStatic) {
// Private static
if (staticMenu.TreeListView == null) {
tree.Add(staticMenu);
tree.Sort(false);
}
if (privateStaticMenu.TreeListView == null) {
staticMenu.Items.Add(privateStaticMenu);
staticMenu.Items.Sort(false);
}
privateStaticMenu.Items.Add(new TreeListViewDebuggerItem(variable));
} else {
// Private instance
if (privateInstanceMenu.TreeListView == null) {
tree.Add(privateInstanceMenu);
tree.Sort(false);
}
privateInstanceMenu.Items.Add(new TreeListViewDebuggerItem(variable));
}
}
foreach(VariableCollection sub in varCollection.SubCollections) {
VariableCollection subCollection = sub;
TreeListViewItem subMenu = new TreeListViewItem("<" + subCollection.Name + ">", 0);
subMenu.SubItems.Add(subCollection.Value);
tree.Add(subMenu);
TreeListViewItem.TreeListViewItemHanlder populate = null;
populate = delegate {
AddVariableCollectionToTree(subCollection, subMenu.Items);
subMenu.AfterExpand -= populate;
};
subMenu.AfterExpand += populate;
}
foreach(Variable variable in varCollection.Items) {
tree.Add(new TreeListViewDebuggerItem(variable));
}
}

74
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Service/DynamicTreeDebuggerRow.cs

@ -177,64 +177,34 @@ namespace ICSharpCode.SharpDevelop.Services @@ -177,64 +177,34 @@ namespace ICSharpCode.SharpDevelop.Services
void Populate()
{
List<Variable> publicStatic = new List<Variable>();
List<Variable> publicInstance = new List<Variable>();
List<Variable> privateStatic = new List<Variable>();
List<Variable> privateInstance = new List<Variable>();
foreach(Variable variable in this.Variable.Value.SubVariables) {
if (variable.IsPublic) {
if (variable.IsStatic) {
publicStatic.Add(variable);
} else {
publicInstance.Add(variable);
}
} else {
if (variable.IsStatic) {
privateStatic.Add(variable);
} else {
privateInstance.Add(variable);
}
}
}
this.ChildRows.Clear();
// Private Members
if (privateInstance.Count > 0) {
this.ChildRows.Add(MakeSubMenu("Private Members",
RowsFromVariables(privateInstance)));
}
// Static Members
if (publicStatic.Count > 0 || privateStatic.Count > 0) {
DynamicTreeRow privateStaticSubMenu = MakeSubMenu("Private Static Members",
RowsFromVariables(privateStatic));
this.ChildRows.Add(MakeSubMenu("Static Members",
privateStatic.Count > 0 ? new DynamicListRow[]{privateStaticSubMenu} : new DynamicListRow[]{},
RowsFromVariables(publicStatic)));
}
// Public Members
this.ChildRows.AddRange(RowsFromVariables(publicInstance));
Fill(this, Variable.Value.SubVariables);
populated = true;
}
IEnumerable<DynamicListRow> RowsFromVariables(IEnumerable<Variable> variables)
static void Fill(DynamicTreeRow row, VariableCollection collection)
{
foreach(Variable variable in variables) {
yield return new DynamicTreeDebuggerRow(variable);
row.ChildRows.Clear();
foreach(VariableCollection sub in collection.SubCollections) {
VariableCollection subCollection = sub;
DynamicTreeRow subMenu = new DynamicTreeRow();
DebuggerGridControl.AddColumns(subMenu.ChildColumns);
subMenu[2].Text = subCollection.Name;
subMenu[3].Text = subCollection.Value;
subMenu.ShowMinusWhileExpanded = true;
EventHandler<DynamicListEventArgs> populate = null;
populate = delegate {
Fill(subMenu, subCollection);
subMenu.Expanding -= populate;
};
subMenu.Expanding += populate;
row.ChildRows.Add(subMenu);
}
}
DynamicTreeRow MakeSubMenu(string name, params IEnumerable<DynamicListRow>[] elements)
{
DynamicTreeRow rootRow = new DynamicTreeRow();
rootRow.ShowMinusWhileExpanded = true;
DebuggerGridControl.AddColumns(rootRow.ChildColumns);
rootRow[2].Text = name;
foreach(IEnumerable<DynamicListRow> rows in elements) {
rootRow.ChildRows.AddRange(rows);
foreach(Variable variable in collection.Items) {
row.ChildRows.Add(new DynamicTreeDebuggerRow(variable));
}
return rootRow;
}
}
}

5
src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj

@ -188,7 +188,7 @@ @@ -188,7 +188,7 @@
<Compile Include="Src\Variables\Evals\NDebugger-Evals.cs" />
<Compile Include="Src\Variables\ArrayValue.cs" />
<Compile Include="Src\Variables\NullValue.cs" />
<Compile Include="Src\Variables\ObjectValue.cs" />
<Compile Include="Src\Variables\ObjectValueClass.cs" />
<Compile Include="Src\Variables\PrimitiveValue.cs" />
<Compile Include="Src\Variables\SignatureStream.cs" />
<Compile Include="Src\Variables\UnavailableValue.cs" />
@ -380,7 +380,8 @@ @@ -380,7 +380,8 @@
<Compile Include="Src\Boo\InterpreterWrapper.cs" />
<Compile Include="Src\Variables\Evals\Eval.CallFunctionEval.cs" />
<Compile Include="Src\Variables\Evals\Eval.NewStringEval.cs" />
<Compile Include="Src\Variables\PersistentValue.cs" />
<Compile Include="Src\Variables\Variable.cs" />
<Compile Include="Src\Variables\ObjectValue.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="README.TXT" />

19
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Exception.cs

@ -20,7 +20,7 @@ namespace Debugger @@ -20,7 +20,7 @@ namespace Debugger
Thread thread;
ICorDebugValue corValue;
Value runtimeValue;
ObjectValue runtimeValueException;
ObjectValueClass runtimeValueException;
ExceptionType exceptionType;
SourcecodeSegment location;
DateTime creationTime;
@ -45,19 +45,10 @@ namespace Debugger @@ -45,19 +45,10 @@ namespace Debugger
"$exception",
Variable.Flags.Default,
new IExpirable[] {debugger.PauseSession},
corValue).Value;
runtimeValueException = runtimeValue as ObjectValue;
if (runtimeValueException != null) {
while (runtimeValueException.Type != "System.Exception") {
if (runtimeValueException.HasBaseClass == false) {
runtimeValueException = null;
break;
}
runtimeValueException = runtimeValueException.BaseClass;
}
message = runtimeValueException["_message"].Value.AsString;
}
delegate { return corValue; } ).Value;
runtimeValueException = ((ObjectValue)runtimeValue).GetClass("System.Exception");
message = runtimeValueException.SubVariables["_message"].Value.AsString;
if (thread.LastFunctionWithLoadedSymbols != null) {
location = thread.LastFunctionWithLoadedSymbols.NextStatement;
}

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Thread.cs

@ -118,7 +118,7 @@ namespace Debugger @@ -118,7 +118,7 @@ namespace Debugger
"thread" + id,
Variable.Flags.Default,
new IExpirable[] {debugger.PauseSession},
corThread.Object).Value;
delegate { return corThread.Object;} ).Value;
}
}

12
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ArrayValue.cs

@ -60,7 +60,7 @@ namespace Debugger @@ -60,7 +60,7 @@ namespace Debugger
}
internal unsafe ArrayValue(NDebugger debugger, Variable variable):base(debugger, variable)
internal unsafe ArrayValue(Variable variable):base(variable)
{
corElementType = (CorElementType)CorArrayValue.ElementType;
@ -118,7 +118,7 @@ namespace Debugger @@ -118,7 +118,7 @@ namespace Debugger
elementName += indices[i].ToString() + ",";
elementName = elementName.TrimEnd(new char[] {','}) + "]";
return new Variable(debugger,
return new Variable(Debugger,
elementName,
Variable.Flags.Default,
new IExpirable[] {this.Variable},
@ -139,7 +139,13 @@ namespace Debugger @@ -139,7 +139,13 @@ namespace Debugger
}
}
protected override IEnumerable<Variable> GetSubVariables()
public override VariableCollection SubVariables {
get {
return new VariableCollection(GetSubVariables());
}
}
IEnumerable<Variable> GetSubVariables()
{
uint[] indices = new uint[rank];

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Evals/Eval.CallFunctionEval.cs

@ -75,7 +75,7 @@ namespace Debugger @@ -75,7 +75,7 @@ namespace Debugger
OnError("Can not evaluate on a value which is not an object");
return false;
}
if (corFunction != null && !((ObjectValue)val).IsSuperClass(corFunction.Class)) {
if (corFunction != null && !((ObjectValue)val).IsInClassHierarchy(corFunction.Class)) {
OnError("Can not evaluate because the object does not contain specified function");
return false;
}

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/NullValue.cs

@ -36,7 +36,7 @@ namespace Debugger @@ -36,7 +36,7 @@ namespace Debugger
}
}
internal unsafe NullValue(NDebugger debugger, Variable variable):base(debugger, variable)
internal unsafe NullValue(Variable variable):base(variable)
{
}

237
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValue.cs

@ -18,18 +18,7 @@ namespace Debugger @@ -18,18 +18,7 @@ namespace Debugger
{
public class ObjectValue: Value
{
Module finalCorClassModule;
uint finalCorClassToken;
Module module;
ICorDebugClass corClass;
TypeDefProps classProps;
protected ICorDebugObjectValue CorObjectValue {
get {
return this.CorValue.CastTo<ICorDebugObjectValue>();
}
}
ObjectValueClass topClass;
public override string AsString {
get {
@ -39,244 +28,66 @@ namespace Debugger @@ -39,244 +28,66 @@ namespace Debugger
public override string Type {
get{
return classProps.Name;
return topClass.Type;
}
}
public Module Module {
get {
return module;
}
}
public uint ClassToken {
public ObjectValueClass TopClass {
get {
return classProps.Token;
return topClass;
}
}
public IEnumerable<ObjectValue> SuperClasses {
public IEnumerable<ObjectValueClass> Classes {
get {
ICorDebugClass currentClass = corClass;
ObjectValueClass currentClass = topClass;
do {
yield return new ObjectValue(debugger, this.Variable, currentClass);
currentClass = GetSuperClass(debugger, currentClass);
yield return currentClass;
currentClass = currentClass.BaseClass;
} while (currentClass != null);
}
}
internal bool IsSuperClass(ICorDebugClass corClass)
public ObjectValueClass GetClass(string type)
{
foreach(ObjectValue superClass in SuperClasses) {
if (superClass.corClass == corClass) return true;
}
return false;
}
public ObjectValue BaseClass {
get {
ICorDebugClass superClass = GetSuperClass(debugger, corClass);
if (superClass == null) throw new DebuggerException("Does not have a base class");
return new ObjectValue(debugger, this.Variable, superClass);
foreach(ObjectValueClass cls in Classes) {
if (cls.Type == type) return cls;
}
return null;
}
public bool HasBaseClass {
get {
return GetSuperClass(debugger, corClass) != null;
internal bool IsInClassHierarchy(ICorDebugClass corClass)
{
foreach(ObjectValueClass cls in Classes) {
if (cls.CorClass == corClass) return true;
}
return false;
}
internal ObjectValue(NDebugger debugger, Variable variable):base(debugger, variable)
internal ObjectValue(Variable variable):base(variable)
{
InitObjectValue(this.CorObjectValue.Class);
}
internal ObjectValue(NDebugger debugger, Variable variable, ICorDebugClass corClass):base(debugger, variable)
{
InitObjectValue(corClass);
}
void InitObjectValue(ICorDebugClass corClass)
{
this.finalCorClassModule = debugger.GetModule(this.CorObjectValue.Class.Module);
this.finalCorClassToken = this.CorObjectValue.Class.Token;
this.module = debugger.GetModule(corClass.Module);
this.corClass = corClass;
this.classProps = Module.MetaData.GetTypeDefProps(corClass.Token);
topClass = new ObjectValueClass(this, this.CorValue.As<ICorDebugObjectValue>().Class);
}
bool IsCorValueCompatible {
internal bool IsCorValueCompatible {
get {
ObjectValue freshValue = this.FreshValue as ObjectValue;
return freshValue != null &&
this.finalCorClassModule == freshValue.Module &&
this.finalCorClassToken == freshValue.ClassToken;
topClass.Module == freshValue.TopClass.Module &&
topClass.ClassToken == freshValue.TopClass.ClassToken;
}
}
public ObjectValue ObjectClass {
get {
ObjectValue objectClass = this;
while (objectClass.HasBaseClass) {
objectClass = objectClass.BaseClass;
}
return objectClass;
}
}
IEnumerable<MethodProps> Methods {
get {
return this.Module.MetaData.EnumMethods(this.ClassToken);
}
}
public override bool MayHaveSubVariables {
get {
return true;
}
}
protected override IEnumerable<Variable> GetSubVariables()
{
if (HasBaseClass) {
yield return GetBaseClassVariable();
}
foreach(Variable var in GetFieldVariables()) {
yield return var;
}
foreach(Variable var in GetPropertyVariables()) {
yield return var;
}
}
public IEnumerable<Variable> GetFieldVariables()
{
foreach(FieldProps f in Module.MetaData.EnumFields(ClassToken)) {
FieldProps field = f; // One per scope/delegate
if (field.IsStatic && field.IsLiteral) continue; // Skip field
if (!field.IsStatic && CorValue == null) continue; // Skip field
yield return new Variable(debugger,
field.Name,
(field.IsStatic ? Variable.Flags.Static : Variable.Flags.None) |
(field.IsPublic ? Variable.Flags.Public : Variable.Flags.None),
new IExpirable[] {this.Variable},
delegate { return GetCorValueOfField(field); });
}
}
ICorDebugValue GetCorValueOfField(FieldProps field)
{
if (!IsCorValueCompatible) throw new CannotGetValueException("Object type changed");
// Current frame is used to resolve context specific static values (eg. ThreadStatic)
ICorDebugFrame curFrame = null;
if (debugger.IsPaused && debugger.SelectedThread != null && debugger.SelectedThread.LastFunction != null && debugger.SelectedThread.LastFunction.CorILFrame != null) {
curFrame = debugger.SelectedThread.LastFunction.CorILFrame.CastTo<ICorDebugFrame>();
}
try {
if (field.IsStatic) {
return corClass.GetStaticFieldValue(field.Token, curFrame);
} else {
return CorObjectValue.GetFieldValue(corClass, field.Token);
}
} catch {
throw new CannotGetValueException();
}
}
public IEnumerable<Variable> GetPropertyVariables()
{
foreach(MethodProps m in Methods) {
MethodProps method = m; // One per scope/delegate
if (method.HasSpecialName && method.Name.StartsWith("get_") && method.Name != "get_Item") {
Eval eval = Eval.CallFunction(debugger,
Module.CorModule.GetFunctionFromToken(method.Token),
true, // reevaluateAfterDebuggeeStateChange
method.IsStatic? null : this.Variable,
new Variable[] {});
Variable var = eval.Result;
var.Name = method.Name.Remove(0, 4);
var.VariableFlags = (method.IsStatic ? Variable.Flags.Static : Variable.Flags.None) |
(method.IsPublic ? Variable.Flags.Public : Variable.Flags.None);
yield return var;
}
}
}
public Variable GetBaseClassVariable()
{
if (HasBaseClass) {
return new Variable(debugger,
"<Base class>",
Variable.Flags.Default,
new IExpirable[] {this.Variable},
delegate { return GetBaseClassValue(); });
} else {
return null;
}
}
Value GetBaseClassValue()
{
if (!IsCorValueCompatible) throw new CannotGetValueException("Object type changed");
return this.BaseClass;
}
protected static ICorDebugClass GetSuperClass(NDebugger debugger, ICorDebugClass currClass)
{
Module currModule = debugger.GetModule(currClass.Module);
uint superToken = currModule.MetaData.GetTypeDefProps(currClass.Token).SuperClassToken;
// It has no base class
if ((superToken & 0x00FFFFFF) == 0x00000000) return null;
// TypeDef - Localy defined
if ((superToken & 0xFF000000) == 0x02000000) {
return currModule.CorModule.GetClassFromToken(superToken);
}
// TypeRef - Referencing to external assembly
if ((superToken & 0xFF000000) == 0x01000000) {
string fullTypeName = currModule.MetaData.GetTypeRefProps(superToken).Name;
foreach (Module superModule in debugger.Modules) {
// TODO: Does not work for nested
// TODO: preservesig
try {
uint token = superModule.MetaData.FindTypeDefByName(fullTypeName, 0).Token;
return superModule.CorModule.GetClassFromToken(token);
} catch {
continue;
}
}
}
throw new DebuggerException("Superclass not found");
}
/*
// May return null
public Eval ToStringEval {
public override VariableCollection SubVariables {
get {
ObjectValue baseClassObject = this.BaseClassObject;
foreach(MethodProps method in baseClassObject.Methods) {
if (method.Name == "ToString") {
ICorDebugValue[] evalArgs;
ICorDebugFunction evalCorFunction;
baseClassObject.Module.CorModule.GetFunctionFromToken(method.Token, out evalCorFunction);
evalArgs = new ICorDebugValue[] {this.SoftReference};
return new Eval(debugger, evalCorFunction, evalArgs);
}
}
throw new DebuggerException("ToString method not found");
return topClass.SubVariables;
}
}
*/
}
}

227
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/ObjectValueClass.cs

@ -0,0 +1,227 @@ @@ -0,0 +1,227 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using Debugger.Wrappers.CorDebug;
using Debugger.Wrappers.MetaData;
namespace Debugger
{
public class ObjectValueClass: RemotingObjectBase
{
NDebugger debugger;
ObjectValue objectValue;
Module module;
ICorDebugClass corClass;
TypeDefProps classProps;
ICorDebugObjectValue CorObjectValue {
get {
return objectValue.CorValue.As<ICorDebugObjectValue>();
}
}
bool IsCorValueCompatible {
get {
return objectValue.IsCorValueCompatible;
}
}
public Module Module {
get {
return module;
}
}
public string Type {
get{
return classProps.Name;
}
}
internal ICorDebugClass CorClass {
get {
return corClass;
}
}
public uint ClassToken {
get {
return classProps.Token;
}
}
public ObjectValueClass(ObjectValue objectValue, ICorDebugClass corClass)
{
this.debugger = objectValue.Debugger;
this.objectValue = objectValue;
this.module = debugger.GetModule(corClass.Module);
this.corClass = corClass;
this.classProps = Module.MetaData.GetTypeDefProps(corClass.Token);
}
public VariableCollection SubVariables {
get {
return new VariableCollection("Base class",
"{" + Type + "}",
SubCollections,
GetSubVariables(Variable.Flags.Public, Variable.Flags.PublicStatic));
}
}
IEnumerable<VariableCollection> SubCollections {
get {
ObjectValueClass baseClass = BaseClass;
VariableCollection privateStatic = new VariableCollection("Private static members",
String.Empty,
new VariableCollection[0],
GetSubVariables(Variable.Flags.Static, Variable.Flags.PublicStatic));
VariableCollection privateInstance = new VariableCollection("Private members",
String.Empty,
privateStatic.IsEmpty? new VariableCollection[0] : new VariableCollection[] {privateStatic},
GetSubVariables(Variable.Flags.None, Variable.Flags.PublicStatic));
VariableCollection publicStatic = new VariableCollection("Static members",
String.Empty,
new VariableCollection[0],
GetSubVariables(Variable.Flags.PublicStatic, Variable.Flags.PublicStatic));
if (baseClass != null) {
yield return baseClass.SubVariables;
}
if (!privateInstance.IsEmpty) {
yield return privateInstance;
}
if (!publicStatic.IsEmpty) {
yield return publicStatic;
}
}
}
IEnumerable<Variable> GetSubVariables(Variable.Flags requiredFlags, Variable.Flags mask) {
foreach(Variable var in GetFieldVariables()) {
if ((var.VariableFlags & mask) == requiredFlags) {
yield return var;
}
}
foreach(Variable var in GetPropertyVariables()) {
if ((var.VariableFlags & mask) == requiredFlags) {
yield return var;
}
}
}
public ObjectValueClass BaseClass {
get {
ICorDebugClass superClass = GetSuperClass(debugger, corClass);
if (superClass != null) {
return new ObjectValueClass(objectValue, superClass);
} else {
return null;
}
}
}
public IEnumerable<Variable> GetFieldVariables()
{
foreach(FieldProps f in Module.MetaData.EnumFields(ClassToken)) {
FieldProps field = f; // One per scope/delegate
if (field.IsStatic && field.IsLiteral) continue; // Skip field
yield return new Variable(debugger,
field.Name,
(field.IsStatic ? Variable.Flags.Static : Variable.Flags.None) |
(field.IsPublic ? Variable.Flags.Public : Variable.Flags.None),
new IExpirable[] {this.objectValue.Variable},
delegate { return GetCorValueOfField(field); });
}
}
ICorDebugValue GetCorValueOfField(FieldProps field)
{
if (!IsCorValueCompatible) throw new CannotGetValueException("Object type changed");
// Current frame is used to resolve context specific static values (eg. ThreadStatic)
ICorDebugFrame curFrame = null;
if (debugger.IsPaused && debugger.SelectedThread != null && debugger.SelectedThread.LastFunction != null && debugger.SelectedThread.LastFunction.CorILFrame != null) {
curFrame = debugger.SelectedThread.LastFunction.CorILFrame.CastTo<ICorDebugFrame>();
}
try {
if (field.IsStatic) {
return corClass.GetStaticFieldValue(field.Token, curFrame);
} else {
return CorObjectValue.GetFieldValue(corClass, field.Token);
}
} catch {
throw new CannotGetValueException("Can not get value of field");
}
}
IEnumerable<MethodProps> Methods {
get {
return this.Module.MetaData.EnumMethods(this.ClassToken);
}
}
public IEnumerable<Variable> GetPropertyVariables()
{
foreach(MethodProps m in Methods) {
MethodProps method = m; // One per scope/delegate
if (method.HasSpecialName && method.Name.StartsWith("get_") && method.Name != "get_Item") {
Eval eval = Eval.CallFunction(debugger,
Module.CorModule.GetFunctionFromToken(method.Token),
true, // reevaluateAfterDebuggeeStateChange
method.IsStatic? null : this.objectValue.Variable,
new Variable[] {});
Variable var = eval.Result;
var.Name = method.Name.Remove(0, 4);
var.VariableFlags = (method.IsStatic ? Variable.Flags.Static : Variable.Flags.None) |
(method.IsPublic ? Variable.Flags.Public : Variable.Flags.None);
yield return var;
}
}
}
protected static ICorDebugClass GetSuperClass(NDebugger debugger, ICorDebugClass currClass)
{
Module currModule = debugger.GetModule(currClass.Module);
uint superToken = currModule.MetaData.GetTypeDefProps(currClass.Token).SuperClassToken;
// It has no base class
if ((superToken & 0x00FFFFFF) == 0x00000000) return null;
// TypeDef - Localy defined
if ((superToken & 0xFF000000) == 0x02000000) {
return currModule.CorModule.GetClassFromToken(superToken);
}
// TypeRef - Referencing to external assembly
if ((superToken & 0xFF000000) == 0x01000000) {
string fullTypeName = currModule.MetaData.GetTypeRefProps(superToken).Name;
foreach (Module superModule in debugger.Modules) {
// TODO: Does not work for nested
// TODO: preservesig
try {
uint token = superModule.MetaData.FindTypeDefByName(fullTypeName, 0).Token;
return superModule.CorModule.GetClassFromToken(token);
} catch {
continue;
}
}
}
throw new DebuggerException("Superclass not found");
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PrimitiveValue.cs

@ -51,7 +51,7 @@ namespace Debugger @@ -51,7 +51,7 @@ namespace Debugger
}
}
internal PrimitiveValue(NDebugger debugger, Variable variable):base(debugger, variable)
internal PrimitiveValue(Variable variable):base(variable)
{
}

4
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/UnavailableValue.cs

@ -19,7 +19,7 @@ namespace Debugger @@ -19,7 +19,7 @@ namespace Debugger
public override string AsString {
get {
return message;
}
}
}
public override string Type {
@ -28,7 +28,7 @@ namespace Debugger @@ -28,7 +28,7 @@ namespace Debugger
}
}
internal UnavailableValue(NDebugger debugger, Variable variable, string message):base(debugger, variable)
internal UnavailableValue(Variable variable, string message):base(variable)
{
this.message = message;
}

16
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Value.cs

@ -15,12 +15,11 @@ namespace Debugger @@ -15,12 +15,11 @@ namespace Debugger
{
public abstract class Value: RemotingObjectBase
{
protected NDebugger debugger;
Variable variable;
public NDebugger Debugger {
get {
return debugger;
return variable.Debugger;
}
}
@ -68,17 +67,12 @@ namespace Debugger @@ -68,17 +67,12 @@ namespace Debugger
get;
}
public VariableCollection SubVariables {
public virtual VariableCollection SubVariables {
get {
return new VariableCollection(GetSubVariables());
return new VariableCollection(new Variable[] {});
}
}
protected virtual IEnumerable<Variable> GetSubVariables()
{
yield break;
}
public Variable this[string variableName] {
get {
foreach(Variable v in SubVariables) {
@ -88,9 +82,9 @@ namespace Debugger @@ -88,9 +82,9 @@ namespace Debugger
}
}
protected Value(NDebugger debugger, Variable variable)
protected Value(Variable variable)
{
this.debugger = debugger;
if (variable == null) throw new ArgumentNullException("variable");
this.variable = variable;
}

40
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/PersistentValue.cs → src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/Variable.cs

@ -17,12 +17,13 @@ namespace Debugger @@ -17,12 +17,13 @@ namespace Debugger
/// abstraction is necessary because the type of a value can change
/// (eg for local variable of type object)
///
/// Expiration: Once value expires it can not be used anymore. Expiration
/// is permanet - once value expires it stays expired. Value expires when
/// any object specified in constructor expires of when process exits.
/// Expiration: Once value expires it can not be used anymore.
/// Expiration is permanet - once value expires it stays expired.
/// Value expires when any object specified in constructor expires
/// or when process exits.
///
/// ValueChange: ValueChange event is called whenever DebugeeState changes
/// or when NotifyValueChange() is called.
/// ValueChange: ValueChange event is called whenever DebugeeState
/// changes or when NotifyValueChange() is called.
/// </summary>
public class Variable: IExpirable
{
@ -33,7 +34,7 @@ namespace Debugger @@ -33,7 +34,7 @@ namespace Debugger
public delegate ICorDebugValue CorValueGetter();
[Flags]
public enum Flags { Default = Public, None = 0, Public = 1, Static = 2};
public enum Flags { Default = Public, None = 0, Public = 1, Static = 2, PublicStatic = Public | Static};
NDebugger debugger;
@ -81,7 +82,7 @@ namespace Debugger @@ -81,7 +82,7 @@ namespace Debugger
try {
return valueGetter();
} catch (CannotGetValueException e) {
return new UnavailableValue(debugger, this, e.Message);
return new UnavailableValue(this, e.Message);
}
}
}
@ -150,18 +151,6 @@ namespace Debugger @@ -150,18 +151,6 @@ namespace Debugger
debugger.DebuggeeStateChanged += NotifyValueChange;
}
public Variable(NDebugger debugger, string name, Flags flags, IExpirable[] dependencies, ValueGetter valueGetter):this(debugger, name, flags, dependencies)
{
this.corValueGetter = delegate { throw new CannotGetValueException("CorValue not available for custom value"); };
this.valueGetter = valueGetter;
}
public Variable(NDebugger debugger, string name, Flags flags, IExpirable[] dependencies, ICorDebugValue corValue):this(debugger, name, flags, dependencies)
{
this.corValueGetter = delegate { return corValue; };
this.valueGetter = delegate { return CreateValue(); };
}
public Variable(NDebugger debugger, string name, Flags flags, IExpirable[] dependencies, CorValueGetter corValueGetter):this(debugger, name, flags, dependencies)
{
this.corValueGetter = corValueGetter;
@ -242,7 +231,7 @@ namespace Debugger @@ -242,7 +231,7 @@ namespace Debugger
ICorDebugValue corValue = this.CorValue;
if (corValue == null) {
return new NullValue(debugger, this);
return new NullValue(this);
}
CorElementType type = Value.GetCorType(corValue);
@ -263,16 +252,16 @@ namespace Debugger @@ -263,16 +252,16 @@ namespace Debugger
case CorElementType.I:
case CorElementType.U:
case CorElementType.STRING:
return new PrimitiveValue(debugger, this);
return new PrimitiveValue(this);
case CorElementType.ARRAY:
case CorElementType.SZARRAY: // Short-cut for single dimension zero lower bound array
return new ArrayValue(debugger, this);
return new ArrayValue(this);
case CorElementType.VALUETYPE:
case CorElementType.CLASS:
case CorElementType.OBJECT: // Short-cut for Class "System.Object"
return new ObjectValue(debugger, this);
return new ObjectValue(this);
default: // Unknown type
throw new CannotGetValueException("Unknown value type");
@ -282,11 +271,6 @@ namespace Debugger @@ -282,11 +271,6 @@ namespace Debugger
class CannotGetValueException: System.Exception
{
public CannotGetValueException():this("Unable to get value")
{
}
public CannotGetValueException(string message):base(message)
{

51
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Variables/VariableCollection.cs

@ -18,6 +18,9 @@ namespace Debugger @@ -18,6 +18,9 @@ namespace Debugger
{
public static VariableCollection Empty = new VariableCollection(new Variable[] {});
string name;
string val;
IEnumerable<VariableCollection> subCollectionsEnum;
IEnumerable<Variable> collectionEnum;
IEnumerator IEnumerable.GetEnumerator()
@ -27,15 +30,57 @@ namespace Debugger @@ -27,15 +30,57 @@ namespace Debugger
public IEnumerator<Variable> GetEnumerator()
{
return collectionEnum.GetEnumerator();
return Items.GetEnumerator();
}
public string Name {
get {
return name;
}
}
public string Value {
get {
return val;
}
}
public IEnumerable<VariableCollection> SubCollections {
get {
return subCollectionsEnum;
}
}
public IEnumerable<Variable> Items {
get {
return collectionEnum;
}
}
public bool IsEmpty {
get {
foreach(VariableCollection col in SubCollections) {
if (!col.IsEmpty) return false;
}
return !Items.GetEnumerator().MoveNext();
}
}
internal VariableCollection(IEnumerable<Variable> collectionEnum)
:this(String.Empty, String.Empty, new VariableCollection[0], collectionEnum)
{
}
public VariableCollection(string name, string val, IEnumerable<VariableCollection> subCollectionsEnum, IEnumerable<Variable> collectionEnum)
{
this.name = name;
this.val = val;
this.subCollectionsEnum = subCollectionsEnum;
this.collectionEnum = collectionEnum;
}
public Variable this[string variableName] {
public virtual Variable this[string variableName] {
get {
int index = variableName.IndexOf('.');
if (index != -1) {
@ -47,7 +92,7 @@ namespace Debugger @@ -47,7 +92,7 @@ namespace Debugger
if (v.Name == variableName) return v;
}
}
throw new DebuggerException("Variable \"" + variableName + "\" is not in collection");
return null;
}
}

1
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs

@ -490,7 +490,6 @@ namespace Debugger.Tests @@ -490,7 +490,6 @@ namespace Debugger.Tests
Assert.AreEqual(false, ((Variable)subVars[1]).IsPublic);
Assert.AreEqual(true, ((Variable)subVars[2]).IsPublic);
Assert.AreEqual(true, ((Variable)subVars[3]).IsPublic);
Assert.AreEqual(true, ((ObjectValue)local.Value).HasBaseClass);
baseClass = subVars[0];
Assert.AreEqual(typeof(ObjectValue), baseClass.Value.GetType());
Assert.AreEqual("{Debugger.Tests.TestPrograms.BaseClass}", baseClass.Value.AsString);

Loading…
Cancel
Save