Browse Source

Implemented debugger expression evaluation using NRefactory semantic trees.

newNRvisualizers
Siegfried Pammer 14 years ago
parent
commit
28bc1648b0
  1. 40
      SharpDevelop.Tests.sln
  2. 31
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs
  3. 5
      src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlParser.cs
  4. 7
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj
  5. 357
      src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs
  6. 43
      src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluator.cs
  7. 317
      src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionExtensionMethods.cs
  8. 17
      src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs
  9. 12
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs
  10. 58
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  11. 41
      src/AddIns/Debugger/Debugger.Core/Eval.cs
  12. 12
      src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj
  13. 9
      src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs
  14. 6
      src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs
  15. 328
      src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluatorVisitor_Tests.cs
  16. 459
      src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs
  17. 2
      src/AddIns/Debugger/Debugger.Tests/Tests/Thread_Tests.cs
  18. 8
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
  19. 11
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  20. 21
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  21. 10
      src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/ErrorResolveResult.cs
  22. 2
      src/Main/Base/Project/Src/Services/ParserService/IParser.cs
  23. 4
      src/Main/Base/Project/Src/Services/ParserService/IParserService.cs
  24. 16
      src/Main/SharpDevelop/Parser/ParserService.cs

40
SharpDevelop.Tests.sln

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.2.0.8717-Beta 2
# SharpDevelop 4.2.0.8783
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
@ -121,6 +121,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlEditor", "src\AddIns\Dis @@ -121,6 +121,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlEditor", "src\AddIns\Dis
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XmlEditor.Tests", "src\AddIns\DisplayBindings\XmlEditor\Test\XmlEditor.Tests.csproj", "{FC0FE702-A87D-4D70-A9B6-1ECCD611125F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Debugger", "Debugger", "{AF5E0DC1-1FA0-4346-A436-0C817C68F7C1}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debugger.Core", "src\AddIns\Debugger\Debugger.Core\Debugger.Core.csproj", "{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debugger.AddIn", "src\AddIns\Debugger\Debugger.AddIn\Debugger.AddIn.csproj", "{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Debugger.Tests", "src\AddIns\Debugger\Debugger.Tests\Debugger.Tests.csproj", "{A4C858C8-51B6-4265-A695-A20FCEBA1D19}"
EndProject
Project("{00000000-0000-0000-0000-000000000000}") = "Tools", "src\Tools\Tools.build", "{3DF4060F-5EE0-41CF-8096-F27355FD5511}"
EndProject
Global
@ -467,6 +477,30 @@ Global @@ -467,6 +477,30 @@ Global
{4980B743-B32F-4aba-AABD-45E2CAD3568D}.Debug|x86.ActiveCfg = Debug|Any CPU
{4980B743-B32F-4aba-AABD-45E2CAD3568D}.Release|x86.Build.0 = Debug|Any CPU
{4980B743-B32F-4aba-AABD-45E2CAD3568D}.Release|x86.ActiveCfg = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.Build.0 = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.ActiveCfg = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Release|Any CPU.Build.0 = Release|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Release|x86.Build.0 = Release|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Release|x86.ActiveCfg = Release|Any CPU
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}.Debug|x86.Build.0 = Debug|Any CPU
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}.Debug|x86.ActiveCfg = Debug|Any CPU
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}.Release|Any CPU.Build.0 = Release|Any CPU
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}.Release|x86.Build.0 = Release|Any CPU
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}.Release|x86.ActiveCfg = Release|Any CPU
{A4C858C8-51B6-4265-A695-A20FCEBA1D19}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A4C858C8-51B6-4265-A695-A20FCEBA1D19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A4C858C8-51B6-4265-A695-A20FCEBA1D19}.Debug|x86.Build.0 = Debug|Any CPU
{A4C858C8-51B6-4265-A695-A20FCEBA1D19}.Debug|x86.ActiveCfg = Debug|Any CPU
{A4C858C8-51B6-4265-A695-A20FCEBA1D19}.Release|Any CPU.Build.0 = Release|Any CPU
{A4C858C8-51B6-4265-A695-A20FCEBA1D19}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A4C858C8-51B6-4265-A695-A20FCEBA1D19}.Release|x86.Build.0 = Release|Any CPU
{A4C858C8-51B6-4265-A695-A20FCEBA1D19}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -497,6 +531,7 @@ Global @@ -497,6 +531,7 @@ Global
{E0646C25-36F2-4524-969F-FA621353AB94} = {39327899-ED91-4F7F-988C-4FE4E17C014D}
{F3662720-9EA2-4591-BBC6-97361DCE50A9} = {39327899-ED91-4F7F-988C-4FE4E17C014D}
{11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} = {39327899-ED91-4F7F-988C-4FE4E17C014D}
{AF5E0DC1-1FA0-4346-A436-0C817C68F7C1} = {39327899-ED91-4F7F-988C-4FE4E17C014D}
{83F15BA7-8478-4664-81BB-A82F146D88B3} = {F208FF4F-E5D8-41D5-A7C7-B463976F156E}
{17F4D7E0-6933-4C2E-8714-FD7E98D625D5} = {F208FF4F-E5D8-41D5-A7C7-B463976F156E}
{1F1AC7CD-D154-45BB-8EAF-804CA8055F5A} = {E0646C25-36F2-4524-969F-FA621353AB94}
@ -519,5 +554,8 @@ Global @@ -519,5 +554,8 @@ Global
{E618A9CD-A39F-4925-A538-E8A3FEF24E54} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}
{DCA2703D-250A-463E-A68A-07ED105AE6BD} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}
{FC0FE702-A87D-4D70-A9B6-1ECCD611125F} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8} = {AF5E0DC1-1FA0-4346-A436-0C817C68F7C1}
{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C} = {AF5E0DC1-1FA0-4346-A436-0C817C68F7C1}
{A4C858C8-51B6-4265-A695-A20FCEBA1D19} = {AF5E0DC1-1FA0-4346-A436-0C817C68F7C1}
EndGlobalSection
EndGlobal

31
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Parser/Parser.cs

@ -6,6 +6,7 @@ using System.Collections.Generic; @@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Core;
@ -166,5 +167,35 @@ namespace CSharpBinding.Parser @@ -166,5 +167,35 @@ namespace CSharpBinding.Parser
.UpdateProjectContent(null, parsedFile)
.CreateCompilation();
}
public ResolveResult ResolveSnippet(ParseInformation parseInfo, TextLocation location, string codeSnippet, ICompilation compilation, CancellationToken cancellationToken)
{
var csParseInfo = parseInfo as CSharpFullParseInformation;
if (csParseInfo == null)
throw new ArgumentException("Parse info does not have CompilationUnit");
CSharpAstResolver contextResolver = new CSharpAstResolver(compilation, csParseInfo.CompilationUnit, csParseInfo.ParsedFile);
var node = csParseInfo.CompilationUnit.GetNodeAt(location);
CSharpResolver context;
if (node != null)
context = contextResolver.GetResolverStateAfter(node, cancellationToken);
else
context = new CSharpResolver(compilation);
CSharpParser parser = new CSharpParser();
var expr = parser.ParseExpression(new StringReader(codeSnippet));
if (parser.HasErrors)
return new ErrorResolveResult(SpecialType.UnknownType, PrintErrorsAsString(parser.ErrorPrinter.Errors), TextLocation.Empty);
CSharpAstResolver snippetResolver = new CSharpAstResolver(context, expr);
return snippetResolver.Resolve(expr, cancellationToken);
}
string PrintErrorsAsString(List<Error> errors)
{
StringBuilder builder = new StringBuilder();
foreach (var error in errors)
builder.AppendLine(error.Message);
return builder.ToString();
}
}
}

5
src/AddIns/BackendBindings/XamlBinding/XamlBinding/XamlParser.cs

@ -110,5 +110,10 @@ namespace ICSharpCode.XamlBinding @@ -110,5 +110,10 @@ namespace ICSharpCode.XamlBinding
// TODO: create a simple compilation with WPF references?
return null;
}
public ResolveResult ResolveSnippet(ParseInformation parseInfo, TextLocation location, string codeSnippet, ICompilation compilation, CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
}

7
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj

@ -98,6 +98,7 @@ @@ -98,6 +98,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="NRefactory\ExpressionEvaluationVisitor.cs" />
<Compile Include="NRefactory\ExpressionExtensionMethods.cs" />
<Compile Include="Options\DebuggingOptionsPanel.xaml.cs">
<DependentUpon>DebuggingOptionsPanel.xaml</DependentUpon>
<SubType>Code</SubType>
@ -174,14 +175,10 @@ @@ -174,14 +175,10 @@
<Name>Mono.Cecil</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<ProjectReference Include="..\..\..\Libraries\NRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>

357
src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs

@ -2,7 +2,19 @@ @@ -2,7 +2,19 @@
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Debugger.MetaData;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn
{
@ -12,30 +24,367 @@ namespace Debugger.AddIn @@ -12,30 +24,367 @@ namespace Debugger.AddIn
VBNet
}
public static class Extensions
{
public static IType ToIType(this DebugType type, StackFrame frame)
{
var typeRef = ReflectionHelper.ParseReflectionName(type.FullName);
return typeRef.Resolve(frame.AppDomain.Compilation);
}
public static bool IsKnownType(this IType type, KnownTypeCode knownType)
{
var def = type.GetDefinition();
return def != null && def.KnownTypeCode == knownType;
}
public static ResolveResult ToResolveResult(this Value value, StackFrame context)
{
return new ConstantResolveResult(value.Type.ToIType(context), value.PrimitiveValue);
}
}
public class ExpressionEvaluationVisitor
{
public ExpressionEvaluationVisitor()
StackFrame context;
ICompilation debuggerTypeSystem;
Thread evalThread;
public ExpressionEvaluationVisitor(StackFrame context, Thread evalThread, ICompilation debuggerTypeSystem)
{
if (evalThread == null)
throw new ArgumentNullException("evalThread");
if (context == null)
throw new ArgumentNullException("context");
if (debuggerTypeSystem == null)
throw new ArgumentNullException("debuggerTypeSystem");
this.context = context;
this.debuggerTypeSystem = debuggerTypeSystem;
this.evalThread = evalThread;
}
public Value Convert(ResolveResult result)
{
if (result.IsCompileTimeConstant && !result.IsError)
return Eval.CreateValue(evalThread, result.ConstantValue);
return Visit((dynamic)result);
}
Value Visit(ResolveResult result)
{
return null;
if (result is ErrorResolveResult) {
var err = (ErrorResolveResult)result;
if (!string.IsNullOrWhiteSpace(err.Message))
throw new GetValueException(err.Message);
}
if (result.IsError)
throw new GetValueException("Unknown error");
throw new GetValueException("Unsupported language construct: " + result.GetType().Name);
}
Value Visit(ThisResolveResult result)
{
return null;
return context.GetLocalVariableThis();
}
Value Visit(MemberResolveResult result)
{
return null;
var importedMember = debuggerTypeSystem.Import(result.Member);
if (importedMember == null)
throw new GetValueException("Member not found!");
Value target = null;
if (!importedMember.IsStatic)
target = Convert(result.TargetResult);
Value val = Value.GetMemberValue(evalThread, target, importedMember);
if (val == null)
throw new GetValueException("Member not found!");
return target;
}
Value Visit(OperatorResolveResult result)
{
switch (result.OperatorType) {
case ExpressionType.Assign:
Debug.Assert(result.Operands.Count == 2);
return VisitAssignment((dynamic)result.Operands[0], (dynamic)result.Operands[1]);
case ExpressionType.Add:
return VisitBinaryOperator(result, BinaryOperatorType.Add, false);
case ExpressionType.AddChecked:
return VisitBinaryOperator(result, BinaryOperatorType.Add, true);
case ExpressionType.Subtract:
return VisitBinaryOperator(result, BinaryOperatorType.Subtract, false);
case ExpressionType.SubtractChecked:
return VisitBinaryOperator(result, BinaryOperatorType.Subtract, true);
case ExpressionType.Multiply:
return VisitBinaryOperator(result, BinaryOperatorType.Multiply, false);
case ExpressionType.MultiplyChecked:
return VisitBinaryOperator(result, BinaryOperatorType.Multiply, true);
case ExpressionType.Divide:
return VisitBinaryOperator(result, BinaryOperatorType.Divide, false);
case ExpressionType.Modulo:
return VisitBinaryOperator(result, BinaryOperatorType.Modulus, false);
case ExpressionType.And:
return VisitBinaryOperator(result, BinaryOperatorType.BitwiseAnd);
case ExpressionType.AndAlso:
return VisitConditionalOperator(result, BinaryOperatorType.BitwiseAnd);
case ExpressionType.Or:
return VisitBinaryOperator(result, BinaryOperatorType.BitwiseOr);
case ExpressionType.OrElse:
return VisitConditionalOperator(result, BinaryOperatorType.BitwiseOr);
case ExpressionType.ExclusiveOr:
return VisitBinaryOperator(result, BinaryOperatorType.ExclusiveOr);
case ExpressionType.Not:
return VisitUnaryOperator(result, UnaryOperatorType.Not);
// case ExpressionType.OnesComplement:
case ExpressionType.LeftShift:
return VisitBinaryOperator(result, BinaryOperatorType.ShiftLeft);
case ExpressionType.RightShift:
return VisitBinaryOperator(result, BinaryOperatorType.ShiftRight);
case ExpressionType.Equal:
return VisitBinaryOperator(result, BinaryOperatorType.Equality);
case ExpressionType.NotEqual:
return VisitBinaryOperator(result, BinaryOperatorType.InEquality);
case ExpressionType.GreaterThan:
return VisitBinaryOperator(result, BinaryOperatorType.GreaterThan);
case ExpressionType.GreaterThanOrEqual:
return VisitBinaryOperator(result, BinaryOperatorType.GreaterThanOrEqual);
case ExpressionType.LessThan:
return VisitBinaryOperator(result, BinaryOperatorType.LessThan);
case ExpressionType.LessThanOrEqual:
return VisitBinaryOperator(result, BinaryOperatorType.LessThanOrEqual);
case ExpressionType.Conditional:
return VisitTernaryOperator(result);
default:
throw new GetValueException("Unsupported operator: " + result.OperatorType);
}
}
Value VisitTernaryOperator(OperatorResolveResult result)
{
Debug.Assert(result.Operands.Count == 3);
var condition = Convert(result.Operands[0]);
if (!condition.Type.ToIType(context).IsKnownType(KnownTypeCode.Boolean))
throw new GetValueException("Boolean expression expected!");
if ((bool)condition.PrimitiveValue)
return Convert(result.Operands[1]);
return Convert(result.Operands[2]);
}
Value VisitAssignment(ResolveResult lhs, ResolveResult rhs)
{
throw new GetValueException("Assignment not supported!");
}
Value VisitAssignment(LocalResolveResult lhs, ResolveResult rhs)
{
var value = Convert(rhs);
if (lhs.IsParameter)
context.GetArgumentValue(lhs.Variable.Name).SetValue(evalThread, value);
else
context.GetLocalVariableValue(lhs.Variable.Name).SetValue(evalThread, value);
return value;
}
Value VisitUnaryOperator(OperatorResolveResult result, UnaryOperatorType operatorType, bool checkForOverflow = false)
{
Debug.Assert(result.Operands.Count == 1);
var operand = Convert(result.Operands[0]).ToResolveResult(context);
CSharpResolver resolver = new CSharpResolver(debuggerTypeSystem).WithCheckForOverflow(checkForOverflow);
var val = resolver.ResolveUnaryOperator(operatorType, operand);
if (val.IsCompileTimeConstant)
return Convert(val);
throw new InvalidOperationException();
}
Value VisitBinaryOperator(OperatorResolveResult result, BinaryOperatorType operatorType, bool checkForOverflow = false)
{
Debug.Assert(result.Operands.Count == 2);
Debug.Assert(operatorType != BinaryOperatorType.ConditionalAnd && operatorType != BinaryOperatorType.ConditionalOr && operatorType != BinaryOperatorType.NullCoalescing);
var lhs = Convert(result.Operands[0]).GetPermanentReference(evalThread);
var rhs = Convert(result.Operands[1]);
var lhsRR = lhs.ToResolveResult(context);
var rhsRR = rhs.ToResolveResult(context);
CSharpResolver resolver = new CSharpResolver(debuggerTypeSystem).WithCheckForOverflow(checkForOverflow);
var val = resolver.ResolveBinaryOperator(operatorType, lhsRR, rhsRR);
if (val.IsCompileTimeConstant)
return Convert(val);
if (operatorType == BinaryOperatorType.Add &&
(lhsRR.Type.IsKnownType(KnownTypeCode.String) || rhsRR.Type.IsKnownType(KnownTypeCode.String))) {
var method = debuggerTypeSystem.FindType(KnownTypeCode.String)
.GetMethods(m => m.Name == "Concat" && m.Parameters.Count == 2)
.Single(m => m.Parameters.All(p => p.Type.IsKnownType(KnownTypeCode.Object)));
return Value.InvokeMethod(evalThread, null, method, lhs, rhs);
}
throw new InvalidOperationException();
}
Value VisitConditionalOperator(OperatorResolveResult result, BinaryOperatorType bitwiseOperatorType)
{
Debug.Assert(result.Operands.Count == 2);
var lhs = Convert(result.Operands[0]).GetPermanentReference(evalThread);
CSharpResolver resolver = new CSharpResolver(debuggerTypeSystem);
Value condVal;
if (bitwiseOperatorType == BinaryOperatorType.BitwiseAnd)
condVal = Convert(resolver.ResolveConditionFalse(lhs.ToResolveResult(context)));
else
condVal = Convert(resolver.ResolveCondition(lhs.ToResolveResult(context)));
if ((bool)condVal.PrimitiveValue)
return lhs;
var rhs = Convert(result.Operands[1]);
var val = resolver.ResolveBinaryOperator(bitwiseOperatorType, lhs.ToResolveResult(context), rhs.ToResolveResult(context));
if (val.IsCompileTimeConstant)
return Convert(val);
throw new InvalidOperationException();
}
/// <remark
/// See $7.10.10 of C# 4 Spec for details.
/// </remarks>
Value Visit(TypeIsResolveResult result)
{
var importedType = NullableType.GetUnderlyingType(debuggerTypeSystem.Import(result.TargetType));
var val = Convert(result.Input);
var conversions = CSharpConversions.Get(debuggerTypeSystem);
bool evalResult = false;
if (!val.IsNull) {
var type = val.Type.ToIType(context);
IType inputType = NullableType.GetUnderlyingType(type);
if (inputType.Equals(importedType))
evalResult = true;
else if (conversions.IsImplicitReferenceConversion(inputType, importedType))
evalResult = true;
else if (conversions.IsBoxingConversion(inputType, importedType))
evalResult = true;
}
return Eval.CreateValue(evalThread, evalResult);
}
Value Visit(TypeOfResolveResult result)
{
return Eval.NewObjectNoConstructor(evalThread, debuggerTypeSystem.Import(result.ReferencedType));
}
Value Visit(TypeResolveResult result)
{
throw new GetValueException("Types not supported!");
}
Value Visit(UnknownMemberResolveResult result)
{
throw new GetValueException("Member not found!");
}
Value Visit(UnknownIdentifierResolveResult result)
{
throw new GetValueException("Identifier not found!");
}
Value Visit(ArrayAccessResolveResult result)
{
var val = Convert(result.Array);
return val.GetArrayElement(result.Indexes.Select(rr => (int)Convert(rr).PrimitiveValue).ToArray());
}
Value Visit(ArrayCreateResolveResult result)
{
throw new NotImplementedException();
}
Value Visit(ConversionResolveResult result)
{
var val = Convert(result.Input);
if (result.Conversion.IsBoxingConversion)
return val;
else if (result.Conversion.IsIdentityConversion)
return val;
else if (result.Conversion.IsNumericConversion) {
var convVal = CSharpPrimitiveCast.Cast(ReflectionHelper.GetTypeCode(result.Type), val.PrimitiveValue, false);
return Eval.CreateValue(evalThread, convVal);
} else
throw new NotImplementedException();
}
Value Visit(LocalResolveResult result)
{
if (result.IsParameter)
return context.GetArgumentValue(result.Variable.Name);
return context.GetLocalVariableValue(result.Variable.Name);
}
Value Visit(AmbiguousMemberResolveResult result)
{
throw new GetValueException("Ambiguous member: " + result.Member.FullName);
}
Value Visit(InvocationResolveResult result)
{
var importedMember = debuggerTypeSystem.Import(result.Member);
if (importedMember == null)
throw new GetValueException("Member not found!");
IMethod usedMethod;
if (importedMember is IProperty) {
var prop = (IProperty)importedMember;
if (!prop.CanGet)
throw new GetValueException("Indexer does not have a getter.");
usedMethod = prop.Getter;
} else if (importedMember is IMethod) {
usedMethod = (IMethod)importedMember;
} else
throw new GetValueException("Invoked member must be a method or property");
return Convert(result.TargetResult).InvokeMethod(evalThread, usedMethod, result.Arguments.Select(rr => Convert(rr)).ToArray());
}
Value Visit(NamespaceResolveResult result)
{
throw new GetValueException("Namespace not supported!");
}
public static string FormatValue(Thread evalThread, Value val)
{
if (val.IsNull) {
return "null";
} else if (val.Type.IsArray) {
StringBuilder sb = new StringBuilder();
sb.Append(val.Type.Name);
sb.Append(" {");
bool first = true;
foreach(Value item in val.GetArrayElements()) {
if (!first) sb.Append(", ");
first = false;
sb.Append(FormatValue(evalThread, item));
}
sb.Append("}");
return sb.ToString();
} else if (val.Type.GetInterface(typeof(ICollection).FullName) != null) {
StringBuilder sb = new StringBuilder();
sb.Append(val.Type.Name);
sb.Append(" {");
val = val.GetPermanentReference(evalThread);
int count = (int)val.GetMemberValue(evalThread, "Count").PrimitiveValue;
for(int i = 0; i < count; i++) {
if (i > 0) sb.Append(", ");
DebugPropertyInfo itemProperty = (DebugPropertyInfo)val.Type.GetProperty("Item");
Value item = val.GetPropertyValue(evalThread, itemProperty, Eval.CreateValue(evalThread, i));
sb.Append(FormatValue(evalThread, item));
}
sb.Append("}");
return sb.ToString();
} else if (val.Type.FullName == typeof(char).FullName) {
return "'" + CSharpOutputVisitor.ConvertChar((char)val.PrimitiveValue) + "'";
} else if (val.Type.FullName == typeof(string).FullName) {
return "\"" + CSharpOutputVisitor.ConvertString((string)val.PrimitiveValue) + "\"";
} else if (val.Type.IsPrimitive) {
return CSharpOutputVisitor.PrintPrimitiveValue(val.PrimitiveValue);
} else {
return val.InvokeToString(evalThread);
}
}
}
}

43
src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluator.cs

@ -110,48 +110,7 @@ namespace ICSharpCode.NRefactory.Visitors @@ -110,48 +110,7 @@ namespace ICSharpCode.NRefactory.Visitors
return astExpression;
}
public static string FormatValue(Thread evalThread, Value val)
{
if (val == null) {
return null;
} if (val.IsNull) {
return "null";
} else if (val.Type.IsArray) {
StringBuilder sb = new StringBuilder();
sb.Append(val.Type.Name);
sb.Append(" {");
bool first = true;
foreach(Value item in val.GetArrayElements()) {
if (!first) sb.Append(", ");
first = false;
sb.Append(FormatValue(evalThread, item));
}
sb.Append("}");
return sb.ToString();
} else if (val.Type.GetInterface(typeof(ICollection).FullName) != null) {
StringBuilder sb = new StringBuilder();
sb.Append(val.Type.Name);
sb.Append(" {");
val = val.GetPermanentReference(evalThread);
int count = (int)val.GetMemberValue(evalThread, "Count").PrimitiveValue;
for(int i = 0; i < count; i++) {
if (i > 0) sb.Append(", ");
DebugPropertyInfo itemProperty = (DebugPropertyInfo)val.Type.GetProperty("Item");
Value item = val.GetPropertyValue(evalThread, itemProperty, Eval.CreateValue(evalThread, i));
sb.Append(FormatValue(evalThread, item));
}
sb.Append("}");
return sb.ToString();
} else if (val.Type.FullName == typeof(char).FullName) {
return "'" + val.PrimitiveValue.ToString() + "'";
} else if (val.Type.FullName == typeof(string).FullName) {
return "\"" + val.PrimitiveValue.ToString() + "\"";
} else if (val.Type.IsPrimitive) {
return val.PrimitiveValue.ToString();
} else {
return val.InvokeToString(evalThread);
}
}
TypedValue Evaluate(INode expression)
{

317
src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionExtensionMethods.cs

@ -7,329 +7,12 @@ using System.Reflection; @@ -7,329 +7,12 @@ using System.Reflection;
using Debugger;
using Debugger.MetaData;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.PrettyPrinter;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop.Services;
namespace ICSharpCode.NRefactory.Ast
{
public static class ExpressionExtensionMethods
{
// EXPR-EVAL (To be removed when ExpressionEvaluator is deprecated)
public static Value Evaluate(this Expression expression)
{
return ExpressionEvaluator.Evaluate(expression, WindowsDebugger.CurrentStackFrame);
}
static M SetStaticType<M>(this M expr, DebugType type) where M: INode
{
expr.UserData = type;
return expr;
}
public static DebugType GetStaticType(this INode expr)
{
return expr.UserData as DebugType;
}
public static Expression Parenthesize(this Expression expr)
{
if (expr is IdentifierExpression ||
expr is MemberReferenceExpression ||
expr is IndexerExpression ||
expr is ParenthesizedExpression ||
expr is PrimitiveExpression)
return expr;
return new ParenthesizedExpression(expr);
}
public static Expression CastTo(this Expression expresion, DebugType castTo)
{
// No need to cast
if (expresion.GetStaticType() == castTo)
return expresion;
if (expresion is PrimitiveExpression) {
object val = ((PrimitiveExpression)expresion).Value;
if (val != null && val.GetType().FullName == castTo.FullName)
return expresion;
}
return new CastExpression(castTo.GetTypeReference(), expresion.Parenthesize(), CastType.Cast);
}
public static Expression GetExpression(this DebugLocalVariableInfo locVar)
{
return new IdentifierExpression(locVar.Name).SetStaticType((DebugType)locVar.LocalType);
}
public static Expression GetExpression(this DebugParameterInfo par)
{
return new IdentifierExpression(par.Name).SetStaticType((DebugType)par.ParameterType);
}
public static UnaryOperatorExpression AppendDereference(this Expression expression)
{
return new UnaryOperatorExpression(new ParenthesizedExpression(expression), UnaryOperatorType.Dereference);
}
public static IndexerExpression AppendIndexer(this Expression expression, params int[] indices)
{
IndexerExpression indexerExpr = new IndexerExpression(Parenthesize(expression), new List<Expression>());
foreach(int index in indices) {
indexerExpr.Indexes.Add(new PrimitiveExpression(index));
}
DebugType staticType = expression.GetStaticType();
if (staticType != null && staticType.IsArray)
indexerExpr.SetStaticType((DebugType)staticType.GetElementType());
if (staticType != null && staticType.FullNameWithoutGenericArguments == typeof(List<>).FullName)
indexerExpr.SetStaticType((DebugType)staticType.GetGenericArguments()[0]);
return indexerExpr;
}
public static Expression AppendMemberReference(this Expression expresion, IDebugMemberInfo memberInfo, params Expression[] args)
{
Expression target;
if (memberInfo.IsStatic) {
target = new TypeReferenceExpression(
memberInfo.DeclaringType.GetTypeReference()
);
} else {
target = expresion.CastTo((DebugType)memberInfo.DeclaringType);
}
if (memberInfo is DebugFieldInfo) {
if (args.Length > 0)
throw new DebuggerException("No arguments expected for a field");
return new MemberReferenceExpression(target, memberInfo.Name).SetStaticType(memberInfo.MemberType);
}
if (memberInfo is MethodInfo) {
return new InvocationExpression(
new MemberReferenceExpression(target, memberInfo.Name),
AddExplicitTypes((MethodInfo)memberInfo, args)
).SetStaticType(memberInfo.MemberType);
}
if (memberInfo is PropertyInfo) {
PropertyInfo propInfo = (PropertyInfo)memberInfo;
if (args.Length > 0) {
if (memberInfo.Name != "Item")
throw new DebuggerException("Arguments expected only for the Item property");
return new IndexerExpression(
target,
AddExplicitTypes(propInfo.GetGetMethod() ?? propInfo.GetSetMethod(), args)
).SetStaticType(memberInfo.MemberType);
} else {
return new MemberReferenceExpression(target, memberInfo.Name).SetStaticType(memberInfo.MemberType);
}
}
throw new DebuggerException("Unknown member type " + memberInfo.GetType().FullName);
}
static List<Expression> AddExplicitTypes(MethodInfo method, Expression[] args)
{
if (args.Length != method.GetParameters().Length)
throw new DebuggerException("Incorrect number of arguments");
List<Expression> typedArgs = new List<Expression>(args.Length);
for(int i = 0; i < args.Length; i++) {
typedArgs.Add(args[i].CastTo((DebugType)method.GetParameters()[i].ParameterType));
}
return typedArgs;
}
public static bool Is<T>(this Type type)
{
return type.FullName == typeof(T).FullName;
}
public static bool CanPromoteTo(this Type type, Type toType)
{
return ((DebugType)type).CanImplicitelyConvertTo(toType);
}
public static string PrettyPrint(this INode code)
{
if (code == null) return string.Empty;
CSharpOutputVisitor csOutVisitor = new CSharpOutputVisitor();
code.AcceptVisitor(csOutVisitor, null);
return csOutVisitor.Text;
}
public static TypeReference GetTypeReference(this Type type)
{
List<int> arrayRanks = new List<int>();
while(type.IsArray) {
// C# uses reverse array order
arrayRanks.Add(type.GetArrayRank() - 1);
type = type.GetElementType();
}
int pointerNest = 0;
while(type.IsPointer) {
pointerNest++;
type = type.GetElementType();
}
if (type.IsArray)
throw new DebuggerException("C# does not support pointers to arrays");
string name = type.Name;
if (name.IndexOf('`') != -1)
name = name.Substring(0, name.IndexOf('`'));
if (!string.IsNullOrEmpty(type.Namespace))
name = type.Namespace + "." + name;
List<Type> genArgs = new List<Type>();
// This inludes the generic arguments of the outter types
genArgs.AddRange(type.GetGenericArguments());
if (type.DeclaringType != null)
genArgs.RemoveRange(0, type.DeclaringType.GetGenericArguments().Length);
List<TypeReference> genTypeRefs = new List<TypeReference>();
foreach(Type genArg in genArgs) {
genTypeRefs.Add(genArg.GetTypeReference());
}
if (type.DeclaringType != null) {
TypeReference outterRef = type.DeclaringType.GetTypeReference();
InnerClassTypeReference innerRef = new InnerClassTypeReference(outterRef, name, genTypeRefs);
innerRef.PointerNestingLevel = pointerNest;
innerRef.RankSpecifier = arrayRanks.ToArray();
return innerRef.SetStaticType((DebugType)type);
} else {
return new TypeReference(name, pointerNest, arrayRanks.ToArray(), genTypeRefs).SetStaticType((DebugType)type);
}
}
/// <summary>
/// Converts tree into nested TypeReference/InnerClassTypeReference.
/// Dotted names are split into separate nodes.
/// It does not normalize generic arguments.
/// </summary>
static TypeReference NormalizeTypeReference(this INode expr)
{
if (expr is IdentifierExpression) {
return new TypeReference(
((IdentifierExpression)expr).Identifier,
((IdentifierExpression)expr).TypeArguments
);
} else if (expr is MemberReferenceExpression) {
TypeReference outter = NormalizeTypeReference(((MemberReferenceExpression)expr).TargetObject);
return new InnerClassTypeReference(
outter,
((MemberReferenceExpression)expr).MemberName,
((MemberReferenceExpression)expr).TypeArguments
);
} else if (expr is TypeReferenceExpression) {
return NormalizeTypeReference(((TypeReferenceExpression)expr).TypeReference);
} else if (expr is InnerClassTypeReference) { // Frist - it is also TypeReference
InnerClassTypeReference typeRef = (InnerClassTypeReference)expr;
string[] names = typeRef.Type.Split('.');
TypeReference newRef = NormalizeTypeReference(typeRef.BaseType);
foreach(string name in names) {
newRef = new InnerClassTypeReference(newRef, name, new List<TypeReference>());
}
newRef.GenericTypes.AddRange(typeRef.GenericTypes);
newRef.PointerNestingLevel = typeRef.PointerNestingLevel;
newRef.RankSpecifier = typeRef.RankSpecifier;
return newRef;
} else if (expr is TypeReference) {
TypeReference typeRef = (TypeReference)expr;
string[] names = typeRef.Type.Split('.');
if (names.Length == 1)
return typeRef;
TypeReference newRef = null;
foreach(string name in names) {
if (newRef == null) {
newRef = new TypeReference(name, new List<TypeReference>());
} else {
newRef = new InnerClassTypeReference(newRef, name, new List<TypeReference>());
}
}
newRef.GenericTypes.AddRange(typeRef.GenericTypes);
newRef.PointerNestingLevel = typeRef.PointerNestingLevel;
newRef.RankSpecifier = typeRef.RankSpecifier;
return newRef;
} else {
throw new EvaluateException(expr, "Type expected. {0} seen.", expr.GetType().FullName);
}
}
static string GetNameWithArgCounts(TypeReference typeRef)
{
string name = typeRef.Type;
if (typeRef.GenericTypes.Count > 0)
name += "`" + typeRef.GenericTypes.Count.ToString();
if (typeRef is InnerClassTypeReference) {
return GetNameWithArgCounts(((InnerClassTypeReference)typeRef).BaseType) + "." + name;
} else {
return name;
}
}
public static DebugType ResolveType(this INode expr, Debugger.AppDomain appDomain)
{
if (expr is TypeReference && expr.GetStaticType() != null)
return expr.GetStaticType();
if (expr is TypeReferenceExpression && ((TypeReferenceExpression)expr).TypeReference.GetStaticType() != null)
return ((TypeReferenceExpression)expr).TypeReference.GetStaticType();
appDomain.Process.TraceMessage("Resolving {0}", expr.PrettyPrint());
TypeReference typeRef = NormalizeTypeReference(expr);
List<TypeReference> genTypeRefs;
if (typeRef is InnerClassTypeReference) {
genTypeRefs = ((InnerClassTypeReference)typeRef).CombineToNormalTypeReference().GenericTypes;
} else {
genTypeRefs = typeRef.GenericTypes;
}
List<DebugType> genArgs = new List<DebugType>();
foreach(TypeReference genTypeRef in genTypeRefs) {
genArgs.Add(ResolveType(genTypeRef, appDomain));
}
return ResolveTypeInternal(typeRef, genArgs.ToArray(), appDomain);
}
/// <summary>
/// For performance this is separate method.
/// 'genArgs' should hold type for each generic parameter in 'typeRef'.
/// </summary>
static DebugType ResolveTypeInternal(TypeReference typeRef, DebugType[] genArgs, Debugger.AppDomain appDomain)
{
DebugType type = null;
// Try to construct non-nested type
// If there are generic types up in the tree, it must be nested type
if (genArgs.Length == typeRef.GenericTypes.Count) {
string name = GetNameWithArgCounts(typeRef);
type = DebugType.CreateFromNameOrNull(appDomain, name, null, genArgs);
}
// Try to construct nested type
if (type == null && typeRef is InnerClassTypeReference) {
DebugType[] outterGenArgs = genArgs;
// Do not pass our generic arguments to outter type
Array.Resize(ref outterGenArgs, genArgs.Length - typeRef.GenericTypes.Count);
DebugType outter = ResolveTypeInternal(((InnerClassTypeReference)typeRef).BaseType, outterGenArgs, appDomain);
string nestedName = typeRef.GenericTypes.Count == 0 ? typeRef.Type : typeRef.Type + "`" + typeRef.GenericTypes.Count;
type = DebugType.CreateFromNameOrNull(appDomain, nestedName, outter, genArgs);
}
if (type == null)
throw new GetValueException("Can not resolve " + typeRef.PrettyPrint());
for(int i = 0; i < typeRef.PointerNestingLevel; i++) {
type = (DebugType)type.MakePointerType();
}
if (typeRef.RankSpecifier != null) {
for(int i = typeRef.RankSpecifier.Length - 1; i >= 0; i--) {
type = (DebugType)type.MakeArrayType(typeRef.RankSpecifier[i] + 1);
}
}
return type;
}
}
}

17
src/AddIns/Debugger/Debugger.AddIn/Pads/ConsolePad.cs

@ -53,17 +53,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -53,17 +53,12 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
if (frame == null)
return "No current execution frame";
throw new NotImplementedException("");
// try {
// object data = ((WindowsDebugger)DebuggerService.CurrentDebugger).debuggerDecompilerService.GetLocalVariableIndex(frame.MethodInfo.DeclaringType.MetadataToken,
// frame.MethodInfo.MetadataToken,
// code);
// Value val = ExpressionEvaluator.Evaluate(code, SelectedLanguage, frame, data);
// return ExpressionEvaluator.FormatValue(WindowsDebugger.EvalThread, val);
// } catch (GetValueException e) {
// return e.Message;
// }
try {
var val = WindowsDebugger.Evaluate(code);
return ExpressionEvaluationVisitor.FormatValue(WindowsDebugger.EvalThread, val);
} catch (GetValueException e) {
return e.Message;
}
}
protected override string Prompt {

12
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs

@ -3,6 +3,7 @@ @@ -3,6 +3,7 @@
using System;
using System.Linq;
using System.Threading;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
@ -85,12 +86,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -85,12 +86,11 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
{
LoggingService.Info("Evaluating watch: " + name);
TreeNode node = null;
#warning reimplement this!
// try {
// node = new ValueNode(null, name, () => ExpressionEvaluator.Evaluate(name, SupportedLanguage.CSharp, WindowsDebugger.CurrentStackFrame));
// } catch (GetValueException e) {
// node = new TreeNode("Icons.16x16.Error", name, e.Message, string.Empty, null);
// }
try {
node = new ValueNode(null, name, () => WindowsDebugger.Evaluate(name));
} catch (GetValueException e) {
node = new TreeNode("Icons.16x16.Error", name, e.Message, string.Empty, null);
}
node.CanDelete = true;
node.CanSetName = true;
node.PropertyChanged += (s, e) => { if (e.PropertyName == "Name") WindowsDebugger.RefreshPads(); };

58
src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt)
using System;
using System.Collections;
using System.Diagnostics;
using System.Drawing;
using System.IO;
@ -10,7 +11,6 @@ using System.Runtime.InteropServices; @@ -10,7 +11,6 @@ using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Windows.Forms;
using Debugger;
using Debugger.AddIn;
using Debugger.AddIn.TreeModel;
@ -19,6 +19,7 @@ using Debugger.MetaData; @@ -19,6 +19,7 @@ using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.Core.WinForms;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor;
@ -319,20 +320,6 @@ namespace ICSharpCode.SharpDevelop.Services @@ -319,20 +320,6 @@ namespace ICSharpCode.SharpDevelop.Services
}
}
/// <summary>
/// Gets variable of given name.
/// Returns null if unsuccessful. Can throw GetValueException.
/// <exception cref="GetValueException">Thrown when evaluation fails. Exception message explains reason.</exception>
/// </summary>
public Value GetValueFromName(string variableName)
{
#warning if (CurrentStackFrame != null) {
// object data = debuggerDecompilerService.GetLocalVariableIndex(CurrentStackFrame.MethodInfo.DeclaringType.MetadataToken, CurrentStackFrame.MethodInfo.MetadataToken, variableName);
// return ExpressionEvaluator.Evaluate(variableName, SupportedLanguage.CSharp, CurrentStackFrame, data);
// }
return null;
}
public bool IsManaged(int processId)
{
corPublish = new CorpubPublishClass();
@ -345,21 +332,6 @@ namespace ICSharpCode.SharpDevelop.Services @@ -345,21 +332,6 @@ namespace ICSharpCode.SharpDevelop.Services
return false;
}
/// <summary>
/// Gets the current value of the variable as string that can be displayed in tooltips.
/// Returns null if unsuccessful.
/// </summary>
public string GetValueAsString(string variableName)
{
try {
Value val = GetValueFromName(variableName);
if (val == null) return null;
return val.AsString();
} catch (GetValueException) {
return null;
}
}
public bool SetInstructionPointer(string filename, int line, int column, bool dryRun)
{
if (CurrentStackFrame != null) {
@ -475,15 +447,15 @@ namespace ICSharpCode.SharpDevelop.Services @@ -475,15 +447,15 @@ namespace ICSharpCode.SharpDevelop.Services
bookmark.IsEnabledChanged += delegate { breakpoint.IsEnabled = bookmark.IsEnabled; };
}
bool Evaluate(string code, string language)
bool EvaluateCondition(string code)
{
try {
#warning SupportedLanguage supportedLanguage = (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), language, true);
// Value val = ExpressionEvaluator.Evaluate(code, supportedLanguage, CurrentStackFrame);
//
// if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool)
// return (bool)val.PrimitiveValue;
// else
if (CurrentStackFrame == null || CurrentStackFrame.NextStatement == null)
return false;
var val = Evaluate(code);
if (val != null && val.Type.IsPrimitive && val.PrimitiveValue is bool)
return (bool)val.PrimitiveValue;
else
return false;
} catch (GetValueException e) {
string errorMessage = "Error while evaluating breakpoint condition " + code + ":\n" + e.Message + "\n";
@ -553,7 +525,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -553,7 +525,7 @@ namespace ICSharpCode.SharpDevelop.Services
case BreakpointAction.Break:
break;
case BreakpointAction.Condition:
if (Evaluate(bookmark.Condition, bookmark.ScriptLanguage))
if (EvaluateCondition(bookmark.Condition))
DebuggerService.PrintDebugMessage(string.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Conditional.Breakpoints.BreakpointHitAtBecause}") + "\n", bookmark.LineNumber, bookmark.FileName, bookmark.Condition));
else
CurrentProcess.AsyncContinue();
@ -623,6 +595,16 @@ namespace ICSharpCode.SharpDevelop.Services @@ -623,6 +595,16 @@ namespace ICSharpCode.SharpDevelop.Services
return true;
}
public static Value Evaluate(string code)
{
if (CurrentStackFrame == null || CurrentStackFrame.NextStatement == null)
throw new GetValueException("no stackframe available!");
var location = CurrentStackFrame.NextStatement;
var fileName = new FileName(location.Filename);
var rr = SD.ParserService.ResolveSnippet(fileName, new TextLocation(location.StartLine, location.StartColumn), new ParseableFileContentFinder().Create(fileName), code, CurrentStackFrame.MethodInfo.DebugModule.Assembly.Compilation, System.Threading.CancellationToken.None);
return new ExpressionEvaluationVisitor(CurrentStackFrame, EvalThread, CurrentStackFrame.MethodInfo.DebugModule.Assembly.Compilation).Convert(rr);
}
public void JumpToCurrentLine()
{
if (CurrentThread == null)

41
src/AddIns/Debugger/Debugger.Core/Eval.cs

@ -55,16 +55,16 @@ namespace Debugger @@ -55,16 +55,16 @@ namespace Debugger
get { return (ICorDebugEval2)corEval; }
}
/// <exception cref="GetValueException">Evaluating...</exception>
public Value Result {
/// <exception cref="GetValueException">Evaluating...</exception>
public Value Result {
get {
switch(this.State) {
case EvalState.Evaluating: throw new GetValueException("Evaluating...");
case EvalState.EvaluatedSuccessfully: return result;
case EvalState.EvaluatedException: return result;
case EvalState.EvaluatedNoResult: return null;
case EvalState.EvaluatedTimeOut: throw new GetValueException("Timeout");
default: throw new DebuggerException("Unknown state");
case EvalState.Evaluating: throw new GetValueException("Evaluating...");
case EvalState.EvaluatedSuccessfully: return result;
case EvalState.EvaluatedException: return result;
case EvalState.EvaluatedNoResult: return null;
case EvalState.EvaluatedTimeOut: throw new GetValueException("Timeout");
default: throw new DebuggerException("Unknown state");
}
}
}
@ -76,9 +76,9 @@ namespace Debugger @@ -76,9 +76,9 @@ namespace Debugger
public bool Evaluated {
get {
return state == EvalState.EvaluatedSuccessfully ||
state == EvalState.EvaluatedException ||
state == EvalState.EvaluatedNoResult ||
state == EvalState.EvaluatedTimeOut;
state == EvalState.EvaluatedException ||
state == EvalState.EvaluatedNoResult ||
state == EvalState.EvaluatedTimeOut;
}
}
@ -125,9 +125,9 @@ namespace Debugger @@ -125,9 +125,9 @@ namespace Debugger
throw new GetValueException("Func eval cannot work. Bad starting point.");
} else {
#if DEBUG
throw; // Expose for more diagnostics
throw; // Expose for more diagnostics
#else
throw new GetValueException(e.Message);
throw new GetValueException(e.Message);
#endif
}
}
@ -141,9 +141,9 @@ namespace Debugger @@ -141,9 +141,9 @@ namespace Debugger
}
}
/// <exception cref="DebuggerException">Evaluation can not be stopped</exception>
/// <exception cref="GetValueException">Process exited</exception>
Value WaitForResult()
/// <exception cref="DebuggerException">Evaluation can not be stopped</exception>
/// <exception cref="GetValueException">Process exited</exception>
Value WaitForResult()
{
// Note that aborting is not supported for suspended threads
try {
@ -170,7 +170,7 @@ namespace Debugger @@ -170,7 +170,7 @@ namespace Debugger
}
}
internal void NotifyEvaluationComplete(bool successful)
internal void NotifyEvaluationComplete(bool successful)
{
// Eval result should be ICorDebugHandleValue so it should survive Continue()
if (state == EvalState.EvaluatedTimeOut) {
@ -225,7 +225,7 @@ namespace Debugger @@ -225,7 +225,7 @@ namespace Debugger
// if (!(thisValue.IsObject)) // eg Can evaluate on array
if (!thisValue.Type.GetDefinition().IsDerivedFrom(method.DeclaringType.GetDefinition())) {
throw new GetValueException(
"Can not evaluate because the object is not of proper type. " +
"Can not evaluate because the object is not of proper type. " +
"Expected: " + method.DeclaringType.FullName + " Seen: " + thisValue.Type.FullName
);
}
@ -350,6 +350,11 @@ namespace Debugger @@ -350,6 +350,11 @@ namespace Debugger
);
}
public static Eval AsyncNewObjectNoConstructor(Thread evalThread, IType type)
{
throw new NotImplementedException();
}
static ICorDebugValue[] ValuesAsCorDebug(Value[] values)
{
ICorDebugValue[] valuesAsCorDebug = new ICorDebugValue[values.Length];

12
src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj

@ -49,7 +49,7 @@ @@ -49,7 +49,7 @@
<Compile Include="Tests\AppDomain_Tests.cs" />
<Compile Include="Tests\ControlFlow_NoBreak.cs" />
<Compile Include="Tests\DynamicCode.cs" />
<Compile Include="Tests\ExpressionEvaluator_Tests.cs" />
<Compile Include="Tests\ExpressionEvaluatorVisitor_Tests.cs" />
<Compile Include="Tests\Breakpoint_Tests.cs" />
<Compile Include="Tests\StackFrame_Callstack.cs" />
<Compile Include="Tests\DebugType_CompilerGeneratedClasses.cs" />
@ -73,9 +73,13 @@ @@ -73,9 +73,13 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Tests" />
<ProjectReference Include="..\..\..\Libraries\NRefactory\Project\NRefactory.csproj">
<Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project>
<Name>NRefactory</Name>
<ProjectReference Include="..\..\..\Libraries\NRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
<ProjectReference Include="..\Debugger.AddIn\Debugger.AddIn.csproj">
<Project>{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}</Project>

9
src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs

@ -118,13 +118,14 @@ namespace Debugger.Tests @@ -118,13 +118,14 @@ namespace Debugger.Tests
}
protected void EndTest()
protected void EndTest(bool hasXml = true)
{
if (!process.HasExited) {
process.AsyncContinue();
process.WaitForExit();
}
CheckXmlOutput();
if (hasXml)
CheckXmlOutput();
}
protected void CheckXmlOutput()
@ -219,7 +220,7 @@ namespace Debugger.Tests @@ -219,7 +220,7 @@ namespace Debugger.Tests
msg.Append("Could not intercept: ");
msg.Append(e.ExceptionThrown.ToString());
}
LogEvent("ExceptionThrown", msg.ToString());
LogEvent("ExceptionThrown", msg.ToString());
}
LogEvent("Paused", CurrentStackFrame != null ? CurrentStackFrame.NextStatement.ToString() : string.Empty);
};
@ -422,7 +423,7 @@ namespace Debugger.Tests @@ -422,7 +423,7 @@ namespace Debugger.Tests
}
}
string GetResource(string filename)
protected string GetResource(string filename)
{
string resourcePrefix = "Debugger.Tests.Tests.";

6
src/AddIns/Debugger/Debugger.Tests/Tests/DebugType_CompilerGeneratedClasses.cs

@ -74,9 +74,9 @@ namespace Debugger.Tests { @@ -74,9 +74,9 @@ namespace Debugger.Tests {
DumpLocalVariables("OutterDelegateLocalVariables");
process.Continue();
DumpLocalVariables("InnterDelegateLocalVariables");
Eval("nestedDelegArg");
Eval("instanceField");
Eval("staticField");
Evaluate(CurrentStackFrame, EvalThread, "nestedDelegArg", GetResource("DebugType_CompilerGeneratedClasses.cs"));
Evaluate(CurrentStackFrame, EvalThread, "instanceField", GetResource("DebugType_CompilerGeneratedClasses.cs"));
Evaluate(CurrentStackFrame, EvalThread, "staticField", GetResource("DebugType_CompilerGeneratedClasses.cs"));
EndTest();
}
}

328
src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluatorVisitor_Tests.cs

@ -0,0 +1,328 @@ @@ -0,0 +1,328 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace Debugger.Tests
{
public class ExpressionEvaluatorVisitor_Tests
{
public class BaseClass
{
string name = "base name";
public string Name {
get { return name; }
}
public static string StaticField = "base static field";
public string Foo(int i)
{
return "base Foo - int";
}
public string Foo(double d)
{
return "base Foo - double";
}
public string this[long i] {
get {
return "base indexer - long";
}
}
}
public struct DBBool
{
// The three possible DBBool values.
public static readonly DBBool Null = new DBBool(0);
public static readonly DBBool False = new DBBool(-1);
public static readonly DBBool True = new DBBool(1);
// Private field that stores –1, 0, 1 for False, Null, True.
sbyte value;
// Private instance constructor. The value parameter must be –1, 0, or 1.
DBBool(int value) {
this.value = (sbyte)value;
}
// Properties to examine the value of a DBBool. Return true if this
// DBBool has the given value, false otherwise.
public bool IsNull { get { return value == 0; } }
public bool IsFalse { get { return value < 0; } }
public bool IsTrue { get { return value > 0; } }
// Implicit conversion from bool to DBBool. Maps true to DBBool.True and
// false to DBBool.False.
public static implicit operator DBBool(bool x) {
return x? True: False;
}
// Explicit conversion from DBBool to bool. Throws an exception if the
// given DBBool is Null, otherwise returns true or false.
public static explicit operator bool(DBBool x) {
if (x.value == 0) throw new InvalidOperationException();
return x.value > 0;
}
// Equality operator. Returns Null if either operand is Null, otherwise
// returns True or False.
public static DBBool operator ==(DBBool x, DBBool y) {
if (x.value == 0 || y.value == 0) return Null;
return x.value == y.value? True: False;
}
// Inequality operator. Returns Null if either operand is Null, otherwise
// returns True or False.
public static DBBool operator !=(DBBool x, DBBool y) {
if (x.value == 0 || y.value == 0) return Null;
return x.value != y.value? True: False;
}
// Logical negation operator. Returns True if the operand is False, Null
// if the operand is Null, or False if the operand is True.
public static DBBool operator !(DBBool x) {
return new DBBool(-x.value);
}
// Logical AND operator. Returns False if either operand is False,
// otherwise Null if either operand is Null, otherwise True.
public static DBBool operator &(DBBool x, DBBool y) {
return new DBBool(x.value < y.value? x.value: y.value);
}
// Logical OR operator. Returns True if either operand is True, otherwise
// Null if either operand is Null, otherwise False.
public static DBBool operator |(DBBool x, DBBool y) {
return new DBBool(x.value > y.value? x.value: y.value);
}
// Definitely true operator. Returns true if the operand is True, false
// otherwise.
public static bool operator true(DBBool x) {
return x.value > 0;
}
// Definitely false operator. Returns true if the operand is False, false
// otherwise.
public static bool operator false(DBBool x) {
return x.value < 0;
}
public override string ToString() {
if (value > 0) return "DBBool.True";
if (value < 0) return "DBBool.False";
return "DBBool.Null";
}
}
public class DerivedClass: BaseClass
{
string name = "derived name";
new public string Name {
get { return name; }
}
public char SetterOnlyProperty { set { ; } }
new public static string StaticField = "derived static field";
public const int ConstInt = 42;
public const string ConstString = "const string";
public const object ConstNull = null;
public const MyEnum ConstEnum = MyEnum.B;
public static string StaticProperty {
get {
return "static property";
}
}
public static string StaticMethod()
{
return "static method";
}
public string Foo(object o)
{
return "derived Foo - object";
}
new public string Foo(int i)
{
return "derived Foo - int";
}
public string Foo(string s)
{
return "derived Foo - string";
}
public string this[double d] {
get {
return "derived indexer - double";
}
}
public string this[string s] {
get {
return "derived indexer - string";
}
}
public string Convert(string s, double d)
{
return "converted to " + s + " and " + d;
}
}
public enum MyEnum { A = 3, B = 6 };
string instanceField = "instance field value";
static string staticField = "static field value";
public class A<T> {
public class B {
public class C<U> {
}
}
}
public static void Main()
{
new ExpressionEvaluatorVisitor_Tests().Fun("function argument");
}
static bool WorkerThreadMoved = false;
public unsafe void Fun(string arg)
{
bool flag = true;
byte b = 1;
int i = 4;
int* iPtr = &i;
float pi = 3.14f;
string hi = "hi";
string emptyString = "";
char[] array = "Hello".ToCharArray();
char[] array2 = "world".ToCharArray();
char[][] arrays = new char[][] {array, array2};
List<char> list = new List<char>(array);
DerivedClass myClass = new DerivedClass();
BaseClass myClass2 = myClass;
int*[][,] complexType1 = new int*[][,] { new int*[,] { { (int*)0xDA1D } } };
A<int>.B.C<char>[][,] complexType2 = new A<int>.B.C<char>[0][,];
// System.Threading.Thread bgWork = new System.Threading.Thread(
// delegate() { WorkerThreadMoved = true; }
// );
//
// System.Diagnostics.Debugger.Break();
// bgWork.Start();
// System.Threading.Thread.Sleep(100);
System.Diagnostics.Debugger.Break();
i++;
}
}
}
#if TEST_CODE
namespace Debugger.Tests
{
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Services;
using NUnit.Framework;
using Debugger.AddIn;
using ICSharpCode.NRefactory.CSharp.Resolver;
/// <summary>
/// Description of ExpressionEvaluatorVisitor_Tests.
/// </summary>
public partial class DebuggerTests
{
[Test]
public void ExpressionEvaluatorVisitor_Tests()
{
StartTest();
AssertEval("i", "4");
AssertEval("pi", "3.14f");
AssertEval("hi", "\"hi\"");
AssertEval("i is int", "true");
AssertEval("i is string", "false");
// AssertEval("hi + i", "\"hi4\"");
// AssertEval("hi + 1", "\"hi1\"");
AssertEval("i > 2 ? i : i * 2", "4");
AssertEval("i < 2 ? i : i * 2", "8");
AssertEval("DBBool.True.IsTrue", "true");
// AssertEval("i < 2 ? i : i * 2", "8");
EndTest(false);
}
void AssertEval(string expression, string expected)
{
NUnit.Framework.Assert.AreEqual(expected, ExpressionEvaluationVisitor.FormatValue(EvalThread, Evaluate(CurrentStackFrame, EvalThread, expression, GetResource("ExpressionEvaluatorVisitor_Tests.cs"))));
}
static ResolveResult ResolveSnippet(string fileName, TextLocation location, string contextCode, string codeSnippet, ICompilation compilation)
{
CSharpParser contextParser = new CSharpParser();
var cu = contextParser.Parse(contextCode, fileName);
CSharpAstResolver contextResolver = new CSharpAstResolver(compilation, cu);
var node = cu.GetNodeAt(location);
CSharpResolver context;
if (node != null)
context = contextResolver.GetResolverStateAfter(node, CancellationToken.None);
else
context = new CSharpResolver(compilation);
CSharpParser parser = new CSharpParser();
var expr = parser.ParseExpression(new StringReader(codeSnippet));
Assert.IsFalse(parser.HasErrors);
CSharpAstResolver snippetResolver = new CSharpAstResolver(context, expr);
return snippetResolver.Resolve(expr, CancellationToken.None);
}
static Value Evaluate(StackFrame frame, Thread evalThread, string code, string contextCode)
{
if (frame == null || frame.NextStatement == null)
throw new GetValueException("no stackframe available!");
var location = frame.NextStatement;
var rr = ResolveSnippet(location.Filename, new TextLocation(location.StartLine, location.StartColumn), contextCode, code, frame.MethodInfo.DebugModule.Assembly.Compilation);
return new ExpressionEvaluationVisitor(frame, evalThread, frame.MethodInfo.DebugModule.Assembly.Compilation).Convert(rr);
}
}
}
#endif

459
src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluator_Tests.cs

@ -1,459 +0,0 @@ @@ -1,459 +0,0 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
namespace Debugger.Tests
{
public class ExpressionEvaluator_Tests
{
public class BaseClass
{
string name = "base name";
public string Name {
get { return name; }
}
public static string StaticField = "base static field";
public string Foo(int i)
{
return "base Foo - int";
}
public string Foo(double d)
{
return "base Foo - double";
}
public string this[long i] {
get {
return "base indexer - long";
}
}
}
public class DerivedClass: BaseClass
{
string name = "derived name";
new public string Name {
get { return name; }
}
public char SetterOnlyProperty { set { ; } }
new public static string StaticField = "derived static field";
public const int ConstInt = 42;
public const string ConstString = "const string";
public const object ConstNull = null;
public const MyEnum ConstEnum = MyEnum.B;
public static string StaticProperty {
get {
return "static property";
}
}
public static string StaticMethod()
{
return "static method";
}
public string Foo(object o)
{
return "derived Foo - object";
}
new public string Foo(int i)
{
return "derived Foo - int";
}
public string Foo(string s)
{
return "derived Foo - string";
}
public string this[double d] {
get {
return "derived indexer - double";
}
}
public string this[string s] {
get {
return "derived indexer - string";
}
}
public string Convert(string s, double d)
{
return "converted to " + s + " and " + d;
}
}
public enum MyEnum { A = 3, B = 6 };
string instanceField = "instance field value";
static string staticField = "static field value";
public class A<T> {
public class B {
public class C<U> {
}
}
}
public static void Main()
{
new ExpressionEvaluator_Tests().Fun("function argument");
}
static bool WorkerThreadMoved = false;
public unsafe void Fun(string arg)
{
bool flag = true;
byte b = 1;
int i = 4;
int* iPtr = &i;
float pi = 3.14f;
string hi = "hi";
string emptyString = "";
char[] array = "Hello".ToCharArray();
char[] array2 = "world".ToCharArray();
char[][] arrays = new char[][] {array, array2};
List<char> list = new List<char>(array);
DerivedClass myClass = new DerivedClass();
BaseClass myClass2 = myClass;
int*[][,] complexType1 = new int*[][,] { new int*[,] { { (int*)0xDA1D } } };
A<int>.B.C<char>[][,] complexType2 = new A<int>.B.C<char>[0][,];
System.Threading.Thread bgWork = new System.Threading.Thread(
delegate() { WorkerThreadMoved = true; }
);
System.Diagnostics.Debugger.Break();
bgWork.Start();
System.Threading.Thread.Sleep(100);
System.Diagnostics.Debugger.Break();
}
}
}
#if TEST_CODE
namespace Debugger.Tests {
using Debugger.MetaData;
using System.Reflection;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using NUnit.Framework;
public partial class DebuggerTests
{
string expressionsInput = @"
b; i; *i; *iPtr; pi
pi - 3; pi + b; i + b; (uint)2 - 3; ((uint)2 - 3).GetType() ; (ulong)2 - 3 ; (b + b).GetType()
1 << 4; 7 << -1; 1 << (uint)2; 1.0 & 2.0; System.Int32.MaxValue + 1; (uint)2 - (uint)3; 1 / 0
hi + hi; hi + ''#''; hi + pi; hi + null; emptyString; ''''
hi + ''#'' == ''hi#''; hi + ''#'' == (object) ''hi#''; hi == (string)null; hi == null; hi == 1; null == null
(5 + 6) % (1 + 2); 3 % 2 == 1
15 & 255; 15 && 255; (ulong)1 + (long)1 /* invalid */
b + 3 == i; b + 4 == i
true == true; true == false
i = 10; -i; ++i; i++; +i; i += 1; ~i; i = 4
-(byte)1; (-(byte)1).GetType(); -(uint)1; (-(uint)1).GetType(); -(ulong)1 /* invalid */
-2147483648 /* int.MinValue */; (-2147483648).GetType(); -(-2147483648)
-9223372036854775808 /* long.MinValue */; (-9223372036854775808).GetType(); -(-9223372036854775808)
-1.0; ~1.0; !1; flag; !flag
arg; instanceField; staticField
array; arrays; array[1]; array[i]; array[i - 1]
new char[3]
new char[b] {'a'}
new char[3] {'a', 'b', 'c'}
new char[] {'a', 'b', 'c'}
new char[][] { new char[] { 'a', 'b' }, new char[] { 'c', 'd' } }
new char[5] {'a', 'b', 'c'}
new char[1,2]
new char[pi]
list; list[1]; list[i]; hi[1]; ''abcd''[2]
list.Add((char)42); list.Add((char)52); list
list = new System.Collections.Generic.List<char>(array2); list
(Debugger.Tests.ExpressionEvaluator_Tests.BaseClass)myClass
(Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass)myClass2
(string)i
(string)hi
(int)hi
";
[NUnit.Framework.Test]
[NUnit.Framework.Ignore("Test fails randomly (race condition)")]
public void ExpressionEvaluator_Tests()
{
StartTest();
this.CurrentStackFrame.StepOver();
this.CurrentStackFrame.StepOver(); // Start worker thread
EvalAll(expressionsInput);
// Test member hiding / overloading
Value myClass = this.CurrentStackFrame.GetLocalVariableValue("myClass").GetPermanentReference(this.EvalThread);
Expression myClassExpr = this.CurrentStackFrame.MethodInfo.GetLocalVariable(this.CurrentStackFrame.IP, "myClass").GetExpression();
List<Expression> expressions = new List<Expression>();
foreach(MemberInfo memberInfo in myClass.Type.GetFieldsAndNonIndexedProperties(DebugType.BindingFlagsAll)) {
expressions.Add(myClassExpr.AppendMemberReference((IDebugMemberInfo)memberInfo));
}
expressions.Add(myClassExpr.AppendMemberReference((DebugMethodInfo)myClass.Type.GetMethod("StaticMethod")));
expressions.Add(myClassExpr.AppendMemberReference((DebugMethodInfo)((DebugType)myClass.Type.BaseType).GetMethod("Foo", new string[] { "i" }), new PrimitiveExpression(1)));
expressions.Add(myClassExpr.AppendMemberReference((DebugMethodInfo)myClass.Type.GetMethod("Foo", new string[] { "i" }), new PrimitiveExpression(1)));
expressions.Add(myClassExpr.AppendMemberReference((DebugMethodInfo)myClass.Type.GetMethod("Foo", new string[] { "s" }), new PrimitiveExpression("a")));
foreach(Expression expr in expressions) {
Eval(expr.PrettyPrint());
}
string input2 = @"
myClass.Foo(1.0)
myClass.Foo(myClass)
myClass.Foo(1)
myClass.Foo(''abc'')
myClass[1]
myClass[(long)1]
myClass[1.0]
myClass[''abc'']
myClass.Convert(1, 2)
myClass.Convert(''abc'', 2)
";
EvalAll(input2);
// Test type round tripping
foreach(DebugLocalVariableInfo locVar in this.CurrentStackFrame.MethodInfo.GetLocalVariables()) {
if (locVar.Name.StartsWith("complexType")) {
TypeReference complexTypeRef = locVar.LocalType.GetTypeReference();
string code = "typeof(" + complexTypeRef.PrettyPrint() + ")";
TypeOfExpression complexTypeRefRT = (TypeOfExpression)ExpressionEvaluator.Parse(code, SupportedLanguage.CSharp);
DebugType type = complexTypeRefRT.TypeReference.ResolveType(this.CurrentStackFrame.AppDomain);
string status = locVar.LocalType.FullName == type.FullName ? "ok" : "fail";
ObjectDumpToString("TypeResulution", string.Format(" {0} = {1} ({2})", code, type.FullName, status));
}
}
// Type equality
DebugLocalVariableInfo loc = this.CurrentStackFrame.MethodInfo.GetLocalVariable(this.CurrentStackFrame.IP, "list");
Type locType = loc.LocalType;
Type valType = loc.GetValue(this.CurrentStackFrame).Type;
ObjectDump("TypesIdentitcal", object.ReferenceEquals(locType, valType));
ObjectDump("TypesEqual", locType == valType);
ObjectDump("WorkerThreadMoved", this.CurrentStackFrame.GetThisValue().GetMemberValue(this.EvalThread, "WorkerThreadMoved").AsString());
process.Continue();
ObjectDump("WorkerThreadMoved", this.CurrentStackFrame.GetThisValue().GetMemberValue(this.EvalThread, "WorkerThreadMoved").AsString());
EndTest();
}
void EvalAll(string exprs)
{
exprs = exprs.Replace("''", "\"");
foreach(string line in exprs.Split('\n', ';')) {
Eval(line.Trim());
}
}
void Eval(string expr)
{
string restultFmted;
if (string.IsNullOrEmpty(expr)) {
restultFmted = null;
} else {
try {
Value result = ICSharpCode.NRefactory.Visitors.ExpressionEvaluator.Evaluate(expr, SupportedLanguage.CSharp, this.CurrentStackFrame);
restultFmted = ICSharpCode.NRefactory.Visitors.ExpressionEvaluator.FormatValue(this.EvalThread, result);
} catch (GetValueException e) {
restultFmted = e.Message;
}
}
if (restultFmted != null) {
restultFmted = restultFmted.Replace("\0", "\\0");
ObjectDump("Eval", " " + expr + " = " + restultFmted + " ");
} else {
ObjectDump("Eval", " " + expr);
}
}
}
}
#endif
#if EXPECTED_OUTPUT
<?xml version="1.0" encoding="utf-8"?>
<DebuggerTests>
<Test
name="ExpressionEvaluator_Tests.cs">
<ProcessStarted />
<ModuleLoaded>mscorlib.dll (No symbols)</ModuleLoaded>
<ModuleLoaded>ExpressionEvaluator_Tests.exe (Has symbols)</ModuleLoaded>
<DebuggingPaused>Break ExpressionEvaluator_Tests.cs:143,4-143,40</DebuggingPaused>
<DebuggingPaused>StepComplete ExpressionEvaluator_Tests.cs:144,4-144,19</DebuggingPaused>
<DebuggingPaused>StepComplete ExpressionEvaluator_Tests.cs:145,4-145,39</DebuggingPaused>
<Eval> </Eval>
<Eval> b = 1 </Eval>
<Eval> i = 4 </Eval>
<Eval> *i = Target object is not a pointer </Eval>
<Eval> *iPtr = 4 </Eval>
<Eval> pi = 3.14 </Eval>
<Eval> pi - 3 = 0.1400001 </Eval>
<Eval> pi + b = 4.14 </Eval>
<Eval> i + b = 5 </Eval>
<Eval> (uint)2 - 3 = -1 </Eval>
<Eval> ((uint)2 - 3).GetType() = System.Int64 </Eval>
<Eval> (ulong)2 - 3 = Can not use the binary operator Subtract on types System.UInt64 and System.Int32 </Eval>
<Eval> (b + b).GetType() = System.Int32 </Eval>
<Eval> 1 &lt;&lt; 4 = 16 </Eval>
<Eval> 7 &lt;&lt; -1 = -2147483648 </Eval>
<Eval> 1 &lt;&lt; (uint)2 = Can not use the binary operator ShiftLeft on types System.Int32 and System.UInt32 </Eval>
<Eval> 1.0 &amp; 2.0 = Can not use the binary operator BitwiseAnd on types System.Double and System.Double </Eval>
<Eval> System.Int32.MaxValue + 1 = Arithmetic operation resulted in an overflow. </Eval>
<Eval> (uint)2 - (uint)3 = Arithmetic operation resulted in an overflow. </Eval>
<Eval> 1 / 0 = Attempted to divide by zero. </Eval>
<Eval> hi + hi = "hihi" </Eval>
<Eval> hi + "#" = "hi#" </Eval>
<Eval> hi + pi = "hi3.14" </Eval>
<Eval> hi + null = "hi" </Eval>
<Eval> emptyString = "" </Eval>
<Eval> "" = "" </Eval>
<Eval> hi + "#" == "hi#" = True </Eval>
<Eval> hi + "#" == (object) "hi#" = False </Eval>
<Eval> hi == (string)null = False </Eval>
<Eval> hi == null = False </Eval>
<Eval> hi == 1 = Can not use the binary operator Equality on types System.String and System.Int32 </Eval>
<Eval> null == null = True </Eval>
<Eval> </Eval>
<Eval> (5 + 6) % (1 + 2) = 2 </Eval>
<Eval> 3 % 2 == 1 = True </Eval>
<Eval> 15 &amp; 255 = 15 </Eval>
<Eval> 15 &amp;&amp; 255 = Can not use the binary operator LogicalAnd on types System.Int32 and System.Int32 </Eval>
<Eval> (ulong)1 + (long)1 /* invalid */ = Can not use the binary operator Add on types System.UInt64 and System.Int64 </Eval>
<Eval> b + 3 == i = True </Eval>
<Eval> b + 4 == i = False </Eval>
<Eval> true == true = True </Eval>
<Eval> true == false = False </Eval>
<Eval> </Eval>
<Eval> i = 10 = 10 </Eval>
<Eval> -i = -10 </Eval>
<Eval> ++i = 11 </Eval>
<Eval> i++ = 11 </Eval>
<Eval> +i = 12 </Eval>
<Eval> i += 1 = 13 </Eval>
<Eval> ~i = -14 </Eval>
<Eval> i = 4 = 4 </Eval>
<Eval> -(byte)1 = -1 </Eval>
<Eval> (-(byte)1).GetType() = System.Int32 </Eval>
<Eval> -(uint)1 = -1 </Eval>
<Eval> (-(uint)1).GetType() = System.Int64 </Eval>
<Eval> -(ulong)1 /* invalid */ = Can not use the unary operator Minus on type System.UInt64 </Eval>
<Eval> -2147483648 /* int.MinValue */ = -2147483648 </Eval>
<Eval> (-2147483648).GetType() = System.Int32 </Eval>
<Eval> -(-2147483648) = Arithmetic operation resulted in an overflow. </Eval>
<Eval> -9223372036854775808 /* long.MinValue */ = -9223372036854775808 </Eval>
<Eval> (-9223372036854775808).GetType() = System.Int64 </Eval>
<Eval> -(-9223372036854775808) = Arithmetic operation resulted in an overflow. </Eval>
<Eval> -1.0 = -1 </Eval>
<Eval> ~1.0 = Can not use the unary operator BitNot on type System.Double </Eval>
<Eval> !1 = Can not use the unary operator Not on type System.Int32 </Eval>
<Eval> flag = True </Eval>
<Eval> !flag = False </Eval>
<Eval> </Eval>
<Eval> arg = "function argument" </Eval>
<Eval> instanceField = "instance field value" </Eval>
<Eval> staticField = "static field value" </Eval>
<Eval> </Eval>
<Eval> array = Char[] {'H', 'e', 'l', 'l', 'o'} </Eval>
<Eval> arrays = Char[][] {Char[] {'H', 'e', 'l', 'l', 'o'}, Char[] {'w', 'o', 'r', 'l', 'd'}} </Eval>
<Eval> array[1] = 'e' </Eval>
<Eval> array[i] = 'o' </Eval>
<Eval> array[i - 1] = 'l' </Eval>
<Eval> new char[3] = Char[] {'\0', '\0', '\0'} </Eval>
<Eval> new char[b] {'a'} = Char[] {'a'} </Eval>
<Eval> new char[3] {'a', 'b', 'c'} = Char[] {'a', 'b', 'c'} </Eval>
<Eval> new char[] {'a', 'b', 'c'} = Char[] {'a', 'b', 'c'} </Eval>
<Eval> new char[][] { new char[] { 'a', 'b' }, new char[] { 'c', 'd' } } = Char[][] {Char[] {'a', 'b'}, Char[] {'c', 'd'}} </Eval>
<Eval> new char[5] {'a', 'b', 'c'} = Incorrect initializer length </Eval>
<Eval> new char[1,2] = Multi-dimensional arrays are not suppored </Eval>
<Eval> new char[pi] = Integer expected </Eval>
<Eval> list = List`1 {'H', 'e', 'l', 'l', 'o'} </Eval>
<Eval> list[1] = 'e' </Eval>
<Eval> list[i] = 'o' </Eval>
<Eval> hi[1] = 'i' </Eval>
<Eval> "abcd"[2] = 'c' </Eval>
<Eval> </Eval>
<Eval> list.Add((char)42)</Eval>
<Eval> list.Add((char)52)</Eval>
<Eval> list = List`1 {'H', 'e', 'l', 'l', 'o', '*', '4'} </Eval>
<Eval> list = new System.Collections.Generic.List&lt;char&gt;(array2) = List`1 {'w', 'o', 'r', 'l', 'd'} </Eval>
<Eval> list = List`1 {'w', 'o', 'r', 'l', 'd'} </Eval>
<Eval> </Eval>
<Eval> (Debugger.Tests.ExpressionEvaluator_Tests.BaseClass)myClass = Debugger.Tests.ExpressionEvaluator_Tests+DerivedClass </Eval>
<Eval> (Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass)myClass2 = Debugger.Tests.ExpressionEvaluator_Tests+DerivedClass </Eval>
<Eval> (string)i = Can not cast System.Int32 to System.String </Eval>
<Eval> (string)hi = "hi" </Eval>
<Eval> (int)hi = Can not cast System.String to System.Int32 </Eval>
<Eval> </Eval>
<Eval> Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass.ConstInt = 42 </Eval>
<Eval> Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass.ConstString = "const string" </Eval>
<Eval> Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass.ConstNull = null </Eval>
<Eval> Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass.ConstEnum = B </Eval>
<Eval> myClass.name = "derived name" </Eval>
<Eval> Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass.StaticField = "derived static field" </Eval>
<Eval> myClass.Name = "derived name" </Eval>
<Eval> Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass.StaticProperty = "static property" </Eval>
<Eval> ((Debugger.Tests.ExpressionEvaluator_Tests.BaseClass)myClass).name = "base name" </Eval>
<Eval> Debugger.Tests.ExpressionEvaluator_Tests.BaseClass.StaticField = "base static field" </Eval>
<Eval> ((Debugger.Tests.ExpressionEvaluator_Tests.BaseClass)myClass).Name = "base name" </Eval>
<Eval> Debugger.Tests.ExpressionEvaluator_Tests.DerivedClass.StaticMethod() = "static method" </Eval>
<Eval> ((Debugger.Tests.ExpressionEvaluator_Tests.BaseClass)myClass).Foo(1) = "base Foo - int" </Eval>
<Eval> myClass.Foo(1) = "derived Foo - int" </Eval>
<Eval> myClass.Foo("a") = "derived Foo - string" </Eval>
<Eval> </Eval>
<Eval> myClass.Foo(1.0) = "base Foo - double" </Eval>
<Eval> myClass.Foo(myClass) = "derived Foo - object" </Eval>
<Eval> myClass.Foo(1) = "derived Foo - int" </Eval>
<Eval> myClass.Foo("abc") = "derived Foo - string" </Eval>
<Eval> myClass[1] = More then one applicable overload found:
String Debugger.Tests.ExpressionEvaluator_Tests+DerivedClass.Item[Double d]
String Debugger.Tests.ExpressionEvaluator_Tests+BaseClass.Item[Int64 i] </Eval>
<Eval> myClass[(long)1] = "base indexer - long" </Eval>
<Eval> myClass[1.0] = "derived indexer - double" </Eval>
<Eval> myClass["abc"] = "derived indexer - string" </Eval>
<Eval> myClass.Convert(1, 2) = Incorrect parameter type for 's'. Excpeted System.String, seen System.Int32 </Eval>
<Eval> myClass.Convert("abc", 2) = "converted to abc and 2" </Eval>
<Eval> </Eval>
<TypeResulution> typeof(System.Int32*[][,]) = System.Int32*[,][] (ok)</TypeResulution>
<TypeResulution> typeof(Debugger.Tests.ExpressionEvaluator_Tests.A&lt;System.Int32&gt;.B.C&lt;System.Char&gt;[][,]) = Debugger.Tests.ExpressionEvaluator_Tests+A`1+B+C`1[System.Int32,System.Char][,][] (ok)</TypeResulution>
<TypesIdentitcal>True</TypesIdentitcal>
<TypesEqual>True</TypesEqual>
<WorkerThreadMoved>False</WorkerThreadMoved>
<DebuggingPaused>Break ExpressionEvaluator_Tests.cs:146,4-146,40</DebuggingPaused>
<WorkerThreadMoved>True</WorkerThreadMoved>
<ProcessExited />
</Test>
</DebuggerTests>
#endif // EXPECTED_OUTPUT

2
src/AddIns/Debugger/Debugger.Tests/Tests/Thread_Tests.cs

@ -22,7 +22,7 @@ namespace Debugger.Tests @@ -22,7 +22,7 @@ namespace Debugger.Tests
namespace Debugger.Tests {
public partial class DebuggerTests
{
[NUnit.Framework.Test]
[NUnit.Framework.Test, NUnit.Framework.Ignore]
public void Thread_Tests()
{
StartTest();

8
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -1007,6 +1007,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1007,6 +1007,14 @@ namespace ICSharpCode.NRefactory.CSharp
EndNode(primitiveExpression);
}
public static string PrintPrimitiveValue(object val)
{
StringWriter writer = new StringWriter();
CSharpOutputVisitor visitor = new CSharpOutputVisitor(writer, new CSharpFormattingOptions());
visitor.WritePrimitiveValue(val);
return writer.ToString();
}
void WritePrimitiveValue(object val)
{
if (val == null) {

11
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs

@ -155,7 +155,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -155,7 +155,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return Conversion.NullLiteralConversion;
if (ImplicitReferenceConversion(fromType, toType, 0))
return Conversion.ImplicitReferenceConversion;
if (BoxingConversion(fromType, toType))
if (IsBoxingConversion(fromType, toType))
return Conversion.BoxingConversion;
if (fromType.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
@ -184,7 +184,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -184,7 +184,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return true;
if (ImplicitReferenceConversion(fromType, toType, 0))
return true;
if (BoxingConversion(fromType, toType) && !NullableType.IsNullable(fromType))
if (IsBoxingConversion(fromType, toType) && !NullableType.IsNullable(fromType))
return true;
if (ImplicitTypeParameterConversion(fromType, toType))
return true;
@ -398,6 +398,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -398,6 +398,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region Implicit Reference Conversion
public bool IsImplicitReferenceConversion(IType fromType, IType toType)
{
return ImplicitReferenceConversion(fromType, toType, 0);
}
bool ImplicitReferenceConversion(IType fromType, IType toType, int subtypeCheckNestingDepth)
{
// C# 4.0 spec: §6.1.6
@ -510,7 +515,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -510,7 +515,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region Boxing Conversions
bool BoxingConversion(IType fromType, IType toType)
public bool IsBoxingConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.7
fromType = NullableType.GetUnderlyingType(fromType);

21
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -2204,6 +2204,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2204,6 +2204,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return Convert(input, boolean, c);
}
/// <summary>
/// Converts the negated input to <c>bool</c> using the rules for boolean expressions.
/// Computes <c>!(bool)input</c> if the implicit cast to bool is valid; otherwise
/// computes <c>input.operator false()</c>.
/// </summary>
public ResolveResult ResolveConditionFalse(ResolveResult input)
{
if (input == null)
throw new ArgumentNullException("input");
IType boolean = compilation.FindType(KnownTypeCode.Boolean);
Conversion c = conversions.ImplicitConversion(input, boolean);
if (!c.IsValid) {
var opFalse = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_False").FirstOrDefault();
if (opFalse != null) {
c = Conversion.UserDefinedImplicitConversion(opFalse, false);
return Convert(input, boolean, c);
}
}
return ResolveUnaryOperator(UnaryOperatorType.Not, Convert(input, boolean, c));
}
public ResolveResult ResolveConditional(ResolveResult condition, ResolveResult trueExpression, ResolveResult falseExpression)
{
// C# 4.0 spec §7.14: Conditional operator

10
src/Libraries/NRefactory/ICSharpCode.NRefactory/Semantics/ErrorResolveResult.cs

@ -35,8 +35,18 @@ namespace ICSharpCode.NRefactory.Semantics @@ -35,8 +35,18 @@ namespace ICSharpCode.NRefactory.Semantics
{
}
public ErrorResolveResult(IType type, string message, TextLocation location) : base(type)
{
this.Message = message;
this.Location = location;
}
public override bool IsError {
get { return true; }
}
public string Message { get; private set; }
public TextLocation Location { get; private set; }
}
}

2
src/Main/Base/Project/Src/Services/ParserService/IParser.cs

@ -60,6 +60,8 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -60,6 +60,8 @@ namespace ICSharpCode.SharpDevelop.Parser
ResolveResult Resolve(ParseInformation parseInfo, TextLocation location, ICompilation compilation, CancellationToken cancellationToken);
ResolveResult ResolveSnippet(ParseInformation parseInfo, TextLocation location, string codeSnippet, ICompilation compilation, CancellationToken cancellationToken);
void FindLocalReferences(ParseInformation parseInfo, ITextSource fileContent, IVariable variable, ICompilation compilation, Action<Reference> callback, CancellationToken cancellationToken);
/// <summary>

4
src/Main/Base/Project/Src/Services/ParserService/IParserService.cs

@ -221,6 +221,10 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -221,6 +221,10 @@ namespace ICSharpCode.SharpDevelop.Parser
ITextSource fileContent = null, ICompilation compilation = null,
CancellationToken cancellationToken = default(CancellationToken));
ResolveResult ResolveSnippet(FileName fileName, TextLocation fileLocation,
ITextSource fileContent, string codeSnippet, ICompilation compilation,
CancellationToken cancellationToken);
Task<ResolveResult> ResolveAsync(FileName fileName, TextLocation location,
ITextSource fileContent = null, ICompilation compilation = null,
CancellationToken cancellationToken = default(CancellationToken));

16
src/Main/SharpDevelop/Parser/ParserService.cs

@ -273,6 +273,22 @@ namespace ICSharpCode.SharpDevelop.Parser @@ -273,6 +273,22 @@ namespace ICSharpCode.SharpDevelop.Parser
return rr;
}
public ResolveResult ResolveSnippet(FileName fileName, TextLocation fileLocation, ITextSource fileContent, string codeSnippet, ICompilation compilation, CancellationToken cancellationToken)
{
var entry = GetFileEntry(fileName, true);
if (entry.parser == null)
return ErrorResolveResult.UnknownError;
IProject project = compilation != null ? compilation.GetProject() : null;
var parseInfo = entry.Parse(fileContent, project, cancellationToken);
if (parseInfo == null)
return ErrorResolveResult.UnknownError;
if (compilation == null)
compilation = GetCompilationForFile(fileName);
ResolveResult rr = entry.parser.ResolveSnippet(parseInfo, fileLocation, codeSnippet, compilation, cancellationToken);
LoggingService.Debug("Resolved " + fileLocation + " to " + rr);
return rr;
}
public Task<ResolveResult> ResolveAsync(FileName fileName, TextLocation location, ITextSource fileContent, ICompilation compilation, CancellationToken cancellationToken)
{
var entry = GetFileEntry(fileName, true);

Loading…
Cancel
Save