From 8a0dc0ba3e53b2fe11be6bb0d81bf9e1b58d77da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 12 Nov 2009 19:22:03 +0000 Subject: [PATCH] Show only variables in scope git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5248 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../TreeModel/StackFrameNode.cs | 2 +- .../Debugger/Debugger.Core/ManagedCallback.cs | 2 +- .../MetaData/DebugLocalVariableInfo.cs | 8 +- .../Debugger.Core/MetaData/DebugMethodInfo.cs | 40 +++++- .../Visitors/ExpressionEvaluator.cs | 9 +- .../Debugger.Core/SourcecodeSegment.cs | 4 +- .../Debugger/Debugger.Core/StackFrame.cs | 23 +++- .../Debugger.Tests/Debugger.Tests.csproj | 6 +- .../Debugger.Tests/DebuggerTestsBase.cs | 11 ++ .../DebugType_CompilerGeneratedClasses.cs | 6 +- .../Debugger.Tests/Tests/DebugType_Tests.cs | 10 +- .../Tests/ExpressionEvaluator_Tests.cs | 8 +- .../Debugger.Tests/Tests/StackFrame_Tests.cs | 115 ++++++++++++++++++ .../Debugger.Tests/Tests/Value_Tests.cs | 2 +- 14 files changed, 211 insertions(+), 35 deletions(-) create mode 100644 src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_Tests.cs diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs index f6df8750d2..a7331b5eb0 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs @@ -31,7 +31,7 @@ namespace Debugger.AddIn.TreeModel foreach(DebugParameterInfo par in stackFrame.MethodInfo.GetParameters()) { yield return new ExpressionNode(ExpressionNode.GetImageForParameter(), par.Name, par.GetExpression()); } - foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables()) { + foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(this.StackFrame.IP)) { yield return new ExpressionNode(ExpressionNode.GetImageForLocalVariable(), locVar.Name, locVar.GetExpression()); } if (stackFrame.Thread.CurrentException != null) { diff --git a/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs b/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs index 494972ffbe..42c974b1ca 100644 --- a/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs +++ b/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs @@ -140,7 +140,7 @@ namespace Debugger process.TraceMessage(" - ignored"); } else if (thread.CurrentStepIn != null && thread.CurrentStepIn.StackFrame.Equals(currentStackFrame) && - thread.CurrentStepIn.IsInStepRanges((int)currentStackFrame.CorInstructionPtr)) { + thread.CurrentStepIn.IsInStepRanges((int)currentStackFrame.IP)) { Stepper.StepIn(currentStackFrame, thread.CurrentStepIn.StepRanges, "finishing step in"); process.TraceMessage(" - finishing step in"); } else if (currentStackFrame.MethodInfo.StepOver) { diff --git a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugLocalVariableInfo.cs b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugLocalVariableInfo.cs index 439e1aaf38..1906b6d4c0 100644 --- a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugLocalVariableInfo.cs +++ b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugLocalVariableInfo.cs @@ -31,13 +31,19 @@ namespace Debugger.MetaData } public string Name { get; internal set; } + /// IL offset of the start of the variable scope (inclusive) + public int StartOffset { get; private set; } + /// IL offset of the end of the variable scope (exclusive) + public int EndOffset { get; private set; } public bool IsThis { get; internal set; } public bool IsCaptured { get; internal set; } - public DebugLocalVariableInfo(string name, int localIndex, DebugType localType, ValueGetter getter) + public DebugLocalVariableInfo(string name, int localIndex, int startOffset, int endOffset, DebugType localType, ValueGetter getter) { this.Name = name; this.localIndex = localIndex; + this.StartOffset = startOffset; + this.EndOffset = endOffset; this.localType = localType; this.getter = getter; } diff --git a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs index ce5e484499..8f77c86ce6 100644 --- a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs +++ b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs @@ -443,30 +443,51 @@ namespace Debugger.MetaData } } - public DebugLocalVariableInfo GetLocalVariable(string name) + public DebugLocalVariableInfo GetLocalVariable(int offset, string name) { - foreach(DebugLocalVariableInfo loc in GetLocalVariables()) { + foreach(DebugLocalVariableInfo loc in GetLocalVariables(offset)) { if (loc.Name == name) return loc; } return null; } + [Debugger.Tests.Ignore] + public DebugLocalVariableInfo GetLocalVariableThis() + { + foreach(DebugLocalVariableInfo loc in GetLocalVariables()) { + if (loc.IsThis) + return loc; + } + return null; + } + + /// Get local variables valid at the given IL offset + public IEnumerable GetLocalVariables(int offset) + { + foreach (DebugLocalVariableInfo varInfo in GetLocalVariables()) { + if (varInfo.StartOffset <= offset && offset < varInfo.EndOffset) { + yield return varInfo; + } + } + } + List localVariables; public List GetLocalVariables() { + if (localVariables != null) return localVariables; + // Generated constructor may not have any symbols if (this.SymMethod == null) return new List(); - - if (localVariables != null) return localVariables; localVariables = GetLocalVariablesInScope(this.SymMethod.GetRootScope()); if (declaringType.IsDisplayClass || declaringType.IsYieldEnumerator) { // Get display class from self AddCapturedLocalVariables( localVariables, + 0, int.MaxValue, delegate(StackFrame context) { return context.GetThisValue(); }, @@ -478,6 +499,7 @@ namespace Debugger.MetaData if (fieldInfo.Name.StartsWith("CS$")) { AddCapturedLocalVariables( localVariables, + 0, int.MaxValue, delegate(StackFrame context) { return context.GetThisValue().GetFieldValue(fieldInfoCopy); }, @@ -491,6 +513,7 @@ namespace Debugger.MetaData DebugLocalVariableInfo thisVar = new DebugLocalVariableInfo( "this", -1, + 0, int.MaxValue, declaringType, delegate(StackFrame context) { return context.GetThisValue(); @@ -503,7 +526,7 @@ namespace Debugger.MetaData return localVariables; } - static void AddCapturedLocalVariables(List vars, ValueGetter getCaptureClass, DebugType captureClassType) + static void AddCapturedLocalVariables(List vars, int scopeStartOffset, int scopeEndOffset, ValueGetter getCaptureClass, DebugType captureClassType) { if (captureClassType.IsDisplayClass || captureClassType.IsYieldEnumerator) { foreach(DebugFieldInfo fieldInfo in captureClassType.GetFields()) { @@ -512,6 +535,8 @@ namespace Debugger.MetaData DebugLocalVariableInfo locVar = new DebugLocalVariableInfo( fieldInfo.Name, -1, + scopeStartOffset, + scopeEndOffset, (DebugType)fieldInfo.FieldType, delegate(StackFrame context) { return getCaptureClass(context).GetFieldValue(fieldInfoCopy); @@ -559,6 +584,8 @@ namespace Debugger.MetaData if (locVarType.IsDisplayClass) { AddCapturedLocalVariables( vars, + (int)symScope.GetStartOffset(), + (int)symScope.GetEndOffset(), delegate(StackFrame context) { return GetLocalVariableValue(context, symVarCopy); }, @@ -569,6 +596,9 @@ namespace Debugger.MetaData DebugLocalVariableInfo locVar = new DebugLocalVariableInfo( symVar.GetName(), (int)symVar.GetAddressField1(), + // symVar also has Get*Offset methods, but the are not implemented + (int)symScope.GetStartOffset(), + (int)symScope.GetEndOffset(), locVarType, delegate(StackFrame context) { return GetLocalVariableValue(context, symVarCopy); diff --git a/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs b/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs index cc4d103b4e..edaf3aabf9 100644 --- a/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs +++ b/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs @@ -392,7 +392,7 @@ namespace ICSharpCode.NRefactory.Visitors if (par != null) return new TypedValue(par.GetValue(context), (DebugType)par.ParameterType); - DebugLocalVariableInfo loc = context.MethodInfo.GetLocalVariable(identifier); + DebugLocalVariableInfo loc = context.MethodInfo.GetLocalVariable(context.IP, identifier); if (loc != null) return new TypedValue(loc.GetValue(context), (DebugType)loc.LocalType); @@ -562,10 +562,9 @@ namespace ICSharpCode.NRefactory.Visitors TypedValue GetThisValue() { // This is needed so that captured 'this' is supported - foreach(DebugLocalVariableInfo locVar in context.MethodInfo.GetLocalVariables()) { - if (locVar.IsThis) - return new TypedValue(locVar.GetValue(context), (DebugType)locVar.LocalType); - } + DebugLocalVariableInfo thisVar = context.MethodInfo.GetLocalVariableThis(); + if (thisVar != null) + return new TypedValue(thisVar.GetValue(context), (DebugType)thisVar.LocalType); return null; } diff --git a/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs b/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs index 41144da9f3..64c7af15e0 100644 --- a/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs +++ b/src/AddIns/Debugger/Debugger.Core/SourcecodeSegment.cs @@ -232,7 +232,7 @@ namespace Debugger /// 'ILStart <= ILOffset <= ILEnd' and this range includes at least /// the returned area of source code. (May incude some extra compiler generated IL too) /// - internal static SourcecodeSegment Resolve(Module module, ICorDebugFunction corFunction, uint offset) + internal static SourcecodeSegment Resolve(Module module, ICorDebugFunction corFunction, int offset) { ISymUnmanagedReader symReader = module.SymReader; if (symReader == null) return null; // No symbols @@ -253,7 +253,7 @@ namespace Debugger // Get i for which: offsets[i] <= offset < offsets[i + 1] // or fallback to first element if offset < offsets[0] for (int i = (int)sequencePointCount - 1; i >= 0; i--) { // backwards - if (sequencePoints[i].Offset <= offset || i == 0) { + if ((int)sequencePoints[i].Offset <= offset || i == 0) { // Set inforamtion about current IL range int codeSize = (int)corFunction.GetILCode().GetSize(); diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs index 339ed81014..2976e1be53 100644 --- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs +++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs @@ -133,16 +133,17 @@ namespace Debugger } } - internal uint CorInstructionPtr { + [Debugger.Tests.Ignore] + public int IP { get { uint corInstructionPtr; CorDebugMappingResult mappingResult; CorILFrame.GetIP(out corInstructionPtr, out mappingResult); - return corInstructionPtr; + return (int)corInstructionPtr; } } - SourcecodeSegment GetSegmentForOffet(uint offset) + SourcecodeSegment GetSegmentForOffet(int offset) { return SourcecodeSegment.Resolve(this.MethodInfo.DebugModule, corFunction, offset); } @@ -232,7 +233,7 @@ namespace Debugger /// public SourcecodeSegment NextStatement { get { - return GetSegmentForOffet(CorInstructionPtr); + return GetSegmentForOffet(IP); } } @@ -282,6 +283,8 @@ namespace Debugger /// /// Gets the instance of the class asociated with the current frame. /// That is, 'this' in C#. + /// Note that for delegates and enumerators this returns the instance of the display class. + /// The get the captured this, use GetLocalVariableThis. /// [Debugger.Tests.Ignore] public Value GetThisValue() @@ -367,12 +370,22 @@ namespace Debugger /// Null if not found public Value GetLocalVariableValue(string name) { - DebugLocalVariableInfo loc = this.MethodInfo.GetLocalVariable(name); + DebugLocalVariableInfo loc = this.MethodInfo.GetLocalVariable(this.IP, name); if (loc == null) return null; return loc.GetValue(this); } + /// Get instance of 'this'. It works well with delegates and enumerators. + [Debugger.Tests.Ignore] + public Value GetLocalVariableThis() + { + DebugLocalVariableInfo thisVar = this.MethodInfo.GetLocalVariableThis(); + if (thisVar != null) + return thisVar.GetValue(this); + return null; + } + public override bool Equals(object obj) { StackFrame other = obj as StackFrame; diff --git a/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj b/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj index 28e6a7ad12..a424db6663 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj +++ b/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj @@ -1,4 +1,5 @@ - + + Library Debugger.Tests @@ -55,6 +56,7 @@ + @@ -80,4 +82,4 @@ - + \ No newline at end of file diff --git a/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs b/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs index cc3ef923be..56681830b8 100644 --- a/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs +++ b/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs @@ -35,6 +35,17 @@ namespace Debugger.Tests protected XmlElement snapshotNode; protected int shapshotID; + public StackFrame SelectedStackFrame { + get { + return process.SelectedStackFrame; + } + } + + public void Continue() + { + process.Continue(); + } + [TestFixtureSetUp] public virtual void TestFixtureSetUp() { diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs index 549fac3ecf..4af8a1de76 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs @@ -73,11 +73,11 @@ namespace Debugger.Tests { public void DebugType_CompilerGeneratedClasses() { StartTest(); - PrintLocalVariables("YieldLocalVariables"); + DumpLocalVariables("YieldLocalVariables"); process.Continue(); - PrintLocalVariables("OutterDelegateLocalVariables"); + DumpLocalVariables("OutterDelegateLocalVariables"); process.Continue(); - PrintLocalVariables("InnterDelegateLocalVariables"); + DumpLocalVariables("InnterDelegateLocalVariables"); Eval("nestedDelegArg"); Eval("instanceField"); Eval("staticField"); diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs index 28c467ef7a..9c08ec24f1 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_Tests.cs @@ -188,16 +188,16 @@ namespace Debugger.Tests { public Value Value { get; set; } } - void PrintLocalVariables() + void DumpLocalVariables() { - PrintLocalVariables("LocalVariables"); + DumpLocalVariables("LocalVariables"); } - void PrintLocalVariables(string msg) + void DumpLocalVariables(string msg) { ObjectDump( msg, - process.SelectedStackFrame.MethodInfo.GetLocalVariables().Select(v => new LocalVariable() { Name = v.Name, Type = v.LocalType, Value = v.GetValue(process.SelectedStackFrame) }) + SelectedStackFrame.MethodInfo.GetLocalVariables(SelectedStackFrame.IP).Select(v => new LocalVariable() { Name = v.Name, Type = v.LocalType, Value = v.GetValue(process.SelectedStackFrame)}) ); } @@ -219,7 +219,7 @@ namespace Debugger.Tests { ObjectDump("Members", process.SelectedStackFrame.GetLocalVariableValue("members").Type.GetMembers(DebugType.BindingFlagsAllDeclared)); ObjectDump("Access-Members", process.SelectedStackFrame.GetLocalVariableValue("access").Type.GetMembers()); ObjectDump("MyInterfaceImpl-Members", process.SelectedStackFrame.GetLocalVariableValue("myInterfaceImpl").Type.GetMembers()); - PrintLocalVariables(); + DumpLocalVariables(); EndTest(); } diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs index 302f4eac3e..a85c7bdf2d 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs @@ -208,8 +208,8 @@ namespace Debugger.Tests { // Test member hiding / overloading - Value myClass = process.SelectedStackFrame.GetLocalVariableValue("myClass").GetPermanentReference(); - Expression myClassExpr = process.SelectedStackFrame.MethodInfo.GetLocalVariable("myClass").GetExpression(); + Value myClass = SelectedStackFrame.GetLocalVariableValue("myClass").GetPermanentReference(); + Expression myClassExpr = SelectedStackFrame.MethodInfo.GetLocalVariable(SelectedStackFrame.IP, "myClass").GetExpression(); List expressions = new List(); foreach(MemberInfo memberInfo in myClass.Type.GetFieldsAndNonIndexedProperties(DebugType.BindingFlagsAll)) { @@ -254,9 +254,9 @@ namespace Debugger.Tests { // Type equality - DebugLocalVariableInfo loc = process.SelectedStackFrame.MethodInfo.GetLocalVariable("list"); + DebugLocalVariableInfo loc = SelectedStackFrame.MethodInfo.GetLocalVariable(SelectedStackFrame.IP, "list"); Type locType = loc.LocalType; - Type valType = loc.GetValue(process.SelectedStackFrame).Type; + Type valType = loc.GetValue(SelectedStackFrame).Type; ObjectDump("TypesIdentitcal", object.ReferenceEquals(locType, valType)); ObjectDump("TypesEqual", locType == valType); diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_Tests.cs new file mode 100644 index 0000000000..0bb4572c7a --- /dev/null +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/StackFrame_Tests.cs @@ -0,0 +1,115 @@ +// +// +// +// +// $Revision$ +// + +using System; + +namespace Debugger.Tests +{ + public class StackFrame_Tests + { + public static void Main() + { + for (int i = 10; i < 11; i++) { + System.Diagnostics.Debugger.Break(); + } + for (short i = 20; i < 21; i++) { + System.Diagnostics.Debugger.Break(); + } + + System.Diagnostics.Debugger.Break(); + + int j = 30; + + System.Diagnostics.Debugger.Break(); + } + } +} + +#if TEST_CODE +namespace Debugger.Tests { + public partial class DebuggerTests + { + [NUnit.Framework.Test] + public void StackFrame_Tests() + { + StartTest(); + + // Test scoping + DumpLocalVariables("Loop1"); + Continue(); + DumpLocalVariables("Loop2"); + Continue(); + DumpLocalVariables("None"); + Continue(); + DumpLocalVariables("NewVarDefined"); + + EndTest(); + } + } +} +#endif + +#if EXPECTED_OUTPUT + + + + + mscorlib.dll (No symbols) + StackFrame_Tests.exe (Has symbols) + Break StackFrame_Tests.cs:17,5-17,41 + + + + + + + + + Break StackFrame_Tests.cs:20,5-20,41 + + + + + + + + + Break StackFrame_Tests.cs:23,4-23,40 + + + + + + Break StackFrame_Tests.cs:27,4-27,40 + + + + + + + + +#endif // EXPECTED_OUTPUT \ No newline at end of file diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs index af8df77a44..87ef0b6119 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/Value_Tests.cs @@ -42,7 +42,7 @@ namespace Debugger.Tests { { StartTest(); - PrintLocalVariables(); + DumpLocalVariables(); Value array = process.SelectedStackFrame.GetLocalVariableValue("array").GetPermanentReference(); ObjectDump("array.Length", array.GetMemberValue("Length"));