diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs index 6157580a14..cc1b6cfc35 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs @@ -255,13 +255,25 @@ namespace Debugger.AddIn.TreeModel public static IEnumerable GetLocalVariables() { var stackFrame = GetCurrentStackFrame(); + var localVars = stackFrame.GetLocalVariables(stackFrame.IP).ToList(); foreach(var par in stackFrame.MethodInfo.Parameters.Select((p, i) => new { Param = p, Index = i})) { var parCopy = par; - yield return new ValueNode(ClassBrowserIconService.Parameter, par.Param.Name, () => GetCurrentStackFrame().GetArgumentValue(par.Index)); + // do not display parameters that have been copied to captured variables twice. (see SD-1912) + // display only the value of the captured instance (the value of the parameter still has the original value) + var localVar = localVars.FirstOrDefault(v => string.Equals(v.Name, parCopy.Param.Name, StringComparison.Ordinal)); + if (localVar == null) + yield return new ValueNode(ClassBrowserIconService.Parameter, par.Param.Name, + () => stackFrame.GetArgumentValue(par.Index)); + else { + yield return new ValueNode(ClassBrowserIconService.Parameter, localVar.Name, + () => localVar.GetValue(stackFrame)); + localVars.Remove(localVar); + } } - foreach(LocalVariable locVar in stackFrame.GetLocalVariables(stackFrame.IP)) { + foreach(LocalVariable locVar in localVars) { var locVarCopy = locVar; - yield return new ValueNode(ClassBrowserIconService.LocalVariable, locVar.Name, () => locVarCopy.GetValue(GetCurrentStackFrame())); + yield return new ValueNode(ClassBrowserIconService.LocalVariable, locVar.Name, + () => locVarCopy.GetValue(stackFrame)); } } diff --git a/src/AddIns/Debugger/Debugger.Core/LocalVariable.cs b/src/AddIns/Debugger/Debugger.Core/LocalVariable.cs index 3e9aeef644..b3fa13c7aa 100644 --- a/src/AddIns/Debugger/Debugger.Core/LocalVariable.cs +++ b/src/AddIns/Debugger/Debugger.Core/LocalVariable.cs @@ -89,7 +89,7 @@ namespace Debugger.MetaData context => context.GetThisValue(false), method.DeclaringType ); - // Get dispaly classes from fields + // Get display classes from fields foreach(IField fieldInfo in method.DeclaringType.GetFields(f => f.Name.StartsWith("CS$"), GetMemberOptions.None)) { IField fieldInfoCopy = fieldInfo; AddCapturedLocalVariables( diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs index ebe49ec296..298553d136 100644 --- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs +++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs @@ -270,6 +270,9 @@ namespace Debugger { for (int i = 0; i < this.MethodInfo.Parameters.Count; i++) { if (this.MethodInfo.Parameters[i].Name == name) { + LocalVariable capturedVar; + if (HasCapturedVariable(name, out capturedVar)) + return capturedVar.GetValue(this); return GetArgumentValue(i); } } @@ -280,6 +283,10 @@ namespace Debugger /// Zero-based index public Value GetArgumentValue(int index) { + var param = this.MethodInfo.Parameters[index]; + LocalVariable capturedVariable; + if (HasCapturedVariable(param.Name, out capturedVariable)) + return capturedVariable.GetValue(this); return new Value(this.AppDomain, GetArgumentCorValue(index)); } @@ -312,6 +319,13 @@ namespace Debugger return corValue; } + /// Gets whether a captured variable with the exists. + public bool HasCapturedVariable(string name, out LocalVariable variable) + { + variable = GetLocalVariables(this.IP).FirstOrDefault(v => v.IsCaptured && v.Name == name); + return variable != null; + } + /// Get all local variables public IEnumerable GetLocalVariables() {