From 98377f4d0f1300b4c6e76d74683b3c4d956be4c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Sat, 24 Oct 2009 12:24:35 +0000 Subject: [PATCH] Support for local variables captured by yield git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@5095 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/Expressions/ExpressionEvaluator.cs | 7 +- .../Project/Src/Metadata/MethodInfo.cs | 78 ++++++++++++------- .../Project/Src/TestPrograms/DebugType.cs | 5 ++ .../DebugType_CompilerGeneratedClasses.cs | 20 +++++ .../Project/Src/TestPrograms/Expressions.cs | 19 ++++- 5 files changed, 99 insertions(+), 30 deletions(-) diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs index b8f660df55..e7991e4d44 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Expressions/ExpressionEvaluator.cs @@ -399,7 +399,12 @@ namespace Debugger public override object VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression, object data) { - return context.GetThisValue(); + // This is needed so that captured 'this' is supported + foreach(LocalVariableInfo locVar in context.MethodInfo.LocalVariables) { + if (locVar.IsThis) + return locVar.GetValue(context); + } + throw new GetValueException(context.MethodInfo.FullName + " does not have \"this\""); } public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs index a50e5b66c1..7fad270961 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/MethodInfo.cs @@ -453,57 +453,82 @@ namespace Debugger.MetaData if (localVariables != null) return localVariables; localVariables = GetLocalVariablesInScope(this.SymMethod.RootScope); - if (!this.IsStatic && this.DeclaringType.IsDisplayClass) { + if (this.DeclaringType.IsDisplayClass || this.DeclaringType.IsYieldEnumerator) { // Get display class from self - localVariables.AddRange(GetLocalVariablesFromDisplayClass( + AddCapturedLocalVariables( + localVariables, delegate(StackFrame context) { return context.GetThisValue(); }, this.DeclaringType - )); + ); // Get dispaly classes from fields foreach(FieldInfo fieldInfo in this.DeclaringType.GetFields()) { FieldInfo fieldInfoCopy = fieldInfo; if (fieldInfo.Name.StartsWith("CS$")) { - localVariables.AddRange(GetLocalVariablesFromDisplayClass( + AddCapturedLocalVariables( + localVariables, delegate(StackFrame context) { return context.GetThisValue().GetFieldValue(fieldInfoCopy); }, fieldInfo.Type - )); + ); } } - } - if (this.DeclaringType.IsYieldEnumerator) { - + } else { + // Add this + if (!this.IsStatic) { + LocalVariableInfo thisVar = new LocalVariableInfo( + "this", + this.DeclaringType, + delegate(StackFrame context) { + return context.GetThisValue(); + } + ); + thisVar.IsThis = true; + localVariables.Add(thisVar); + } } return localVariables; } - List GetLocalVariablesFromDisplayClass(ValueGetter getDisplayClass, DebugType displayClassType) + static void AddCapturedLocalVariables(List vars, ValueGetter getCaptureClass, DebugType captureClassType) { - List vars = new List(); - if (displayClassType.IsDisplayClass) { - foreach(FieldInfo fieldInfo in displayClassType.GetFields()) { + if (captureClassType.IsDisplayClass || captureClassType.IsYieldEnumerator) { + foreach(FieldInfo fieldInfo in captureClassType.GetFields()) { FieldInfo fieldInfoCopy = fieldInfo; - if (!fieldInfo.Name.StartsWith("CS$")) { - LocalVariableInfo locVar = new LocalVariableInfo( - fieldInfo.Name, - fieldInfo.Type, - delegate(StackFrame context) { - return getDisplayClass(context).GetFieldValue(fieldInfoCopy); + if (fieldInfo.Name.StartsWith("CS$")) continue; // Ignore + LocalVariableInfo locVar = new LocalVariableInfo( + fieldInfo.Name, + fieldInfo.Type, + delegate(StackFrame context) { + return getCaptureClass(context).GetFieldValue(fieldInfoCopy); + } + ); + locVar.IsCaptured = true; + if (locVar.Name.StartsWith("<>")) { + bool hasThis = false; + foreach(LocalVariableInfo l in vars) { + if (l.IsThis) { + hasThis = true; + break; } - ); - locVar.IsCapturedByDelegate = true; - if (fieldInfo.Name.StartsWith("<>") && fieldInfo.Name.EndsWith("__this")) { + } + if (!hasThis && locVar.Name.EndsWith("__this")) { locVar.Name = "this"; locVar.IsThis = true; + } else { + continue; // Ignore } - vars.Add(locVar); } + if (locVar.Name.StartsWith("<")) { + int endIndex = locVar.Name.IndexOf('>'); + if (endIndex == -1) continue; // Ignore + locVar.Name = fieldInfo.Name.Substring(1, endIndex - 1); + } + vars.Add(locVar); } } - return vars; } List GetLocalVariablesInScope(ISymUnmanagedScope symScope) @@ -520,12 +545,13 @@ namespace Debugger.MetaData if ((symVar.Attributes & 1) == 1 || symVar.Name.StartsWith("CS$")) { // Get display class from local variable if (locVarType.IsDisplayClass) { - vars.AddRange(GetLocalVariablesFromDisplayClass( + AddCapturedLocalVariables( + vars, delegate(StackFrame context) { return GetLocalVariableValue(context, symVarCopy); }, locVarType - )); + ); } } else { LocalVariableInfo locVar = new LocalVariableInfo( @@ -566,7 +592,7 @@ namespace Debugger.MetaData public string Name { get; internal set; } public DebugType Type { get; private set; } public bool IsThis { get; internal set; } - public bool IsCapturedByDelegate { get; internal set; } + public bool IsCaptured { get; internal set; } public LocalVariableInfo(string name, DebugType type, ValueGetter getter) { diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebugType.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebugType.cs index 59a60b7670..c6f01733d5 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebugType.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebugType.cs @@ -298,6 +298,7 @@ namespace Debugger.Tests { FullName="Access.get_publicProperty" IsPublic="True" IsSpecialName="True" + LocalVariableNames="{this}" Module="DebugType.exe" Name="get_publicProperty" ReturnType="System.Int32" /> @@ -307,6 +308,7 @@ namespace Debugger.Tests { DeclaringType="Access" FullName="Access.publicMethod" IsPublic="True" + LocalVariableNames="{this}" Module="DebugType.exe" Name="publicMethod" /> @@ -316,6 +318,7 @@ namespace Debugger.Tests { FullName="Access..ctor" IsPublic="True" IsSpecialName="True" + LocalVariableNames="{this}" Module="DebugType.exe" Name=".ctor" /> @@ -348,6 +351,7 @@ namespace Debugger.Tests { FullName="MyInterfaceImpl<System.Int32>.get_Prop" IsPublic="True" IsSpecialName="True" + LocalVariableNames="{this}" Module="DebugType.exe" Name="get_Prop" ReturnType="System.Collections.Generic.List<System.Int32>" /> @@ -357,6 +361,7 @@ namespace Debugger.Tests { DeclaringType="MyInterfaceImpl<System.Int32>" FullName="MyInterfaceImpl<System.Int32>.Fun2" IsPublic="True" + LocalVariableNames="{this}" Module="DebugType.exe" Name="Fun2" ParameterCount="3" diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebugType_CompilerGeneratedClasses.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebugType_CompilerGeneratedClasses.cs index 5ab06f6b62..c881c9a4c3 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebugType_CompilerGeneratedClasses.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/DebugType_CompilerGeneratedClasses.cs @@ -120,6 +120,26 @@ namespace Debugger.Tests { Name="stateLessVar_NestedDelegRef" Value="203" /> + + + + + + + + + + + + Break DebugType_CompilerGeneratedClasses.cs:54,6-54,42 diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Expressions.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Expressions.cs index 4e4a03e9e1..cdecd1a626 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Expressions.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/Expressions.cs @@ -130,8 +130,8 @@ namespace Debugger.Tests { + Capacity="8" + Count="5"> + + + @@ -236,6 +243,7 @@ namespace Debugger.Tests { FullName="Debugger.Tests.TestPrograms.TestClass.get_Name" IsPublic="True" IsSpecialName="True" + LocalVariableNames="{this}" Module="Expressions.exe" Name="get_Name" ReturnType="System.String" @@ -255,7 +263,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.TestClass" FullName="Debugger.Tests.TestPrograms.TestClass.Test" IsPublic="True" - LocalVariableNames="{array, array2, BaseClass, i}" + LocalVariableNames="{array, array2, BaseClass, i, this}" Module="Expressions.exe" Name="Test" ParameterCount="1" @@ -266,6 +274,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.TestClass" FullName="Debugger.Tests.TestPrograms.TestClass.Test" IsPublic="True" + LocalVariableNames="{this}" Module="Expressions.exe" Name="Test" ParameterCount="1" @@ -276,6 +285,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.TestClass" FullName="Debugger.Tests.TestPrograms.TestClass.Test" IsPublic="True" + LocalVariableNames="{this}" Module="Expressions.exe" Name="Test" ParameterCount="1" @@ -286,6 +296,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.TestClass" FullName="Debugger.Tests.TestPrograms.TestClass.Foo" IsPublic="True" + LocalVariableNames="{this}" Module="Expressions.exe" Name="Foo" ParameterCount="1" @@ -297,6 +308,7 @@ namespace Debugger.Tests { DeclaringType="Debugger.Tests.TestPrograms.TestClass" FullName="Debugger.Tests.TestPrograms.TestClass.Foo" IsPublic="True" + LocalVariableNames="{this}" Module="Expressions.exe" Name="Foo" ParameterCount="1" @@ -309,6 +321,7 @@ namespace Debugger.Tests { FullName="Debugger.Tests.TestPrograms.TestClass..ctor" IsPublic="True" IsSpecialName="True" + LocalVariableNames="{this}" Module="Expressions.exe" Name=".ctor" />