From 2857444c52de4b00a0023f2ffc74fbaa1184f168 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sun, 10 Jun 2012 10:25:41 +0200 Subject: [PATCH] Implement better value conversion in the evaluator. --- .../NRefactory/ExpressionEvaluationVisitor.cs | 55 ++++++++++++++++--- .../Debugger.AddIn/Service/WindowsDebugger.cs | 2 +- .../Debugger.Tests/DebuggerTestsBase.cs | 1 + .../Tests/ExpressionEvaluatorVisitor_Tests.cs | 16 +++++- .../TypeSystem/ICompilation.cs | 1 - 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs index 17539467a5..21650d1229 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs @@ -28,7 +28,29 @@ namespace Debugger.AddIn { public static ResolveResult ToResolveResult(this Value value, StackFrame context) { - return new ConstantResolveResult(value.Type, value.PrimitiveValue); + return new ValueResolveResult(value); + } + } + + public class ValueResolveResult : ResolveResult + { + Value value; + + public ValueResolveResult(Value value) : base(value.Type) + { + this.value = value; + } + + public Value Value { + get { return value; } + } + + public override bool IsCompileTimeConstant { + get { return value.Type.IsKnownType(KnownTypeCode.String) || value.Type.IsPrimitiveType(); } + } + + public override object ConstantValue { + get { return value.PrimitiveValue; } } } @@ -71,6 +93,11 @@ namespace Debugger.AddIn throw new GetValueException("Unsupported language construct: " + result.GetType().Name); } + Value Visit(ValueResolveResult result) + { + return result.Value; + } + Value Visit(ThisResolveResult result) { return context.GetThisValue(true); @@ -195,6 +222,8 @@ namespace Debugger.AddIn 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]).GetPermanentReference(evalThread); + if (result.UserDefinedOperatorMethod != null) + return InvokeMethod(null, result.UserDefinedOperatorMethod, lhs, rhs); var lhsRR = lhs.ToResolveResult(context); var rhsRR = rhs.ToResolveResult(context); CSharpResolver resolver = new CSharpResolver(debuggerTypeSystem).WithCheckForOverflow(checkForOverflow); @@ -206,7 +235,7 @@ namespace Debugger.AddIn 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); + return InvokeMethod(null, method, lhs, rhs); } throw new InvalidOperationException(); } @@ -225,9 +254,7 @@ namespace Debugger.AddIn 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(); + return Convert(val); } /// Convert(rr)).ToArray()); + Value target = null; + if (!usedMethod.IsStatic) + target = Convert(result.TargetResult); + return InvokeMethod(target, usedMethod, result.Arguments.Select(rr => Convert(rr)).ToArray()); } Value Visit(NamespaceResolveResult result) @@ -332,6 +365,14 @@ namespace Debugger.AddIn throw new GetValueException("Namespace not supported!"); } + Value InvokeMethod(Value thisValue, IMethod method, params Value[] arguments) + { + method = debuggerTypeSystem.Import(method); + if (method == null) + throw new GetValueException("Method not found!"); + return Value.InvokeMethod(evalThread, thisValue, method, arguments); + } + public static string FormatValue(Thread evalThread, Value val) { if (val.IsNull) { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs index 6fc0bc1ed2..d15ccfa6de 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs @@ -601,7 +601,7 @@ namespace ICSharpCode.SharpDevelop.Services 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.AppDomain.Compilation, System.Threading.CancellationToken.None); + var rr = SD.ParserService.ResolveSnippet(fileName, new TextLocation(location.StartLine, location.StartColumn), new ParseableFileContentFinder().Create(fileName), code, null, System.Threading.CancellationToken.None); return new ExpressionEvaluationVisitor(CurrentStackFrame, EvalThread, CurrentStackFrame.AppDomain.Compilation).Convert(rr); } diff --git a/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs b/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs index 58f86b4ddd..be8bf6e334 100644 --- a/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs +++ b/src/AddIns/Debugger/Debugger.Tests/DebuggerTestsBase.cs @@ -461,6 +461,7 @@ namespace Debugger.Tests compParams.TreatWarningsAsErrors = false; compParams.IncludeDebugInformation = true; compParams.ReferencedAssemblies.Add("System.dll"); + compParams.ReferencedAssemblies.Add("System.Core.dll"); compParams.OutputAssembly = exeFilename; compParams.CompilerOptions = "/unsafe /platform:x86 /target:winexe"; compParams.ReferencedAssemblies.Add(typeof(TestFixtureAttribute).Assembly.Location); diff --git a/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluatorVisitor_Tests.cs b/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluatorVisitor_Tests.cs index fe6cafff24..79a8fcdfa4 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluatorVisitor_Tests.cs +++ b/src/AddIns/Debugger/Debugger.Tests/Tests/ExpressionEvaluatorVisitor_Tests.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Threading; +using System.Linq; namespace Debugger.Tests { @@ -227,6 +228,7 @@ namespace Debugger.Tests string hi = "hi"; string emptyString = ""; DBBool boo = DBBool.Null; + var enumerable = Enumerable.Empty(); char[] array = "Hello".ToCharArray(); char[] array2 = "world".ToCharArray(); @@ -265,12 +267,15 @@ namespace Debugger.Tests using NUnit.Framework; using Debugger.AddIn; using ICSharpCode.NRefactory.CSharp.Resolver; + using ICSharpCode.NRefactory.TypeSystem.Implementation; + /// /// Description of ExpressionEvaluatorVisitor_Tests. /// public partial class DebuggerTests { + [Test] public void ExpressionEvaluatorVisitor_Tests() { @@ -287,6 +292,12 @@ namespace Debugger.Tests AssertEval("i < 2 ? i : i * 2", "8"); AssertEval("DBBool.True.IsTrue", "true"); AssertEval("i < 2 ? i : i * 2", "8"); + AssertEval("DBBool.True || DBBool.Null", "DBBool.True"); + AssertEval("DBBool.Null || DBBool.True", "DBBool.True"); + AssertEval("DBBool.Null || DBBool.False", "DBBool.Null"); + AssertEval("DBBool.False || DBBool.False", "DBBool.False"); + AssertEval("array", "Char[] {'H', 'e', 'l', 'l', 'o'}"); + AssertEval("array.ToList()", "List {'H', 'e', 'l', 'l', 'o'}"); EndTest(false); } @@ -320,7 +331,10 @@ namespace Debugger.Tests 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.AppDomain.Compilation); + var debuggerTypeSystem = frame.AppDomain.Compilation; + var compilation = new SimpleCompilation(debuggerTypeSystem.MainAssembly.UnresolvedAssembly, debuggerTypeSystem.ReferencedAssemblies.Select(a => a.UnresolvedAssembly)); + var rr = ResolveSnippet(location.Filename, new TextLocation(location.StartLine, location.StartColumn), + contextCode, code, compilation); return new ExpressionEvaluationVisitor(frame, evalThread, frame.AppDomain.Compilation).Convert(rr); } } diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs index d465b4de27..478776aa30 100644 --- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs +++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/TypeSystem/ICompilation.cs @@ -43,7 +43,6 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Gets the referenced assemblies. /// This list does not include the main assembly. /// - [ObsoleteAttribute("Use compilation.Assemblies.Where(asm != compilation.MainAssembly) instead.")] IList ReferencedAssemblies { get; } ///