Skip to content

Commit

Permalink
IObjectValueSource.SetValue now throws ValueModificationException if …
Browse files Browse the repository at this point in the history
…modification is failed instead of supressing the exception. This allows to show the error info to user at the call site (e.g. in message box).

ValueReference.SetValue() and ArrayElementGroup.SetValue() implementations unified and moved to ValueModificationUtil.

(cherry picked from commit 316b7cc)
  • Loading branch information
nerzhulart committed Mar 16, 2017
1 parent e1f7852 commit da12417
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 192 deletions.
7 changes: 7 additions & 0 deletions Mono.Debugging/Mono.Debugging.Backend/IObjectValueSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,19 @@

using System;
using Mono.Debugging.Client;
using Mono.Debugging.Evaluation;

namespace Mono.Debugging.Backend
{
public interface IObjectValueSource: IDebuggerBackendObject
{
ObjectValue[] GetChildren (ObjectPath path, int index, int count, EvaluationOptions options);

/// <summary>
/// Updates the value with the result of evaluation of <paramref name="value"/> expression
/// </summary>
/// <exception cref="ValueModificationException" /> call site should catch this exception and show it to user in pretty way (e.g. in message box)
/// All other exceptions indicate error and should be logged
EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options);
ObjectValue GetValue (ObjectPath path, EvaluationOptions options);

Expand Down
33 changes: 7 additions & 26 deletions Mono.Debugging/Mono.Debugging.Evaluation/ArrayElementGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -277,37 +277,18 @@ public static string GetArrayDescription (int[] bounds)

return sb.ToString ();
}
public EvaluationResult SetValue (ObjectPath path, string value, EvaluationOptions options)

EvaluationResult IObjectValueSource.SetValue (ObjectPath path, string value, EvaluationOptions options)
{
if (path.Length != 2)
throw new NotSupportedException ();
throw new InvalidOperationException (string.Format ("ObjectPath for array element is invalid: {0}", path));

int[] idx = StringToIndices (path [1]);

object val;
try {
EvaluationContext cctx = ctx.Clone ();
EvaluationOptions ops = options ?? cctx.Options;
ops.AllowMethodEvaluation = true;
ops.AllowTargetInvoke = true;
cctx.Options = ops;
ValueReference var = ctx.Evaluator.Evaluate (ctx, value, array.ElementType);
val = var.Value;
val = ctx.Adapter.Convert (ctx, val, array.ElementType);
array.SetElement (idx, val);
} catch {
val = array.GetElement (idx);
}
try {
return ctx.Evaluator.TargetObjectToExpression (ctx, val);
} catch (Exception ex) {
ctx.WriteDebuggerError (ex);
return new EvaluationResult ("? (" + ex.Message + ")");
}
var cctx = ctx.WithOptions (options);
return ValueModificationUtil.ModifyValue (cctx, value, array.ElementType, newVal => array.SetElement (idx, newVal));
}
public ObjectValue GetValue (ObjectPath path, EvaluationOptions options)

ObjectValue IObjectValueSource.GetValue (ObjectPath path, EvaluationOptions options)
{
if (path.Length != 2)
throw new NotSupportedException ();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;

namespace Mono.Debugging.Evaluation
{
public class ValueModificationException : Exception
{
public ValueModificationException ()
{
}

public ValueModificationException (string message) : base (message)
{
}

public ValueModificationException (string message, Exception innerException) : base (message, innerException)
{
}
}
}
50 changes: 50 additions & 0 deletions Mono.Debugging/Mono.Debugging.Evaluation/ValueModificationUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using Mono.Debugging.Backend;

namespace Mono.Debugging.Evaluation
{
public static class ValueModificationUtil
{
internal static ValueReference EvaluateRightHandValue (EvaluationContext context, string value, object expectedType)
{
context.Options.AllowMethodEvaluation = true;
context.Options.AllowTargetInvoke = true;
try {
return context.Evaluator.Evaluate (context, value, expectedType);
} catch (Exception e) {
throw new ValueModificationException(string.Format ("Cannot evaluate '{0}': {1}", value, e.Message), e);
}
}

internal static object ConvertRightHandValue (EvaluationContext context, object value, object expectedType)
{
try {
return context.Adapter.Convert (context, value, expectedType);
} catch (Exception e) {
throw new ValueModificationException(string.Format ("Conversion error: {0}", e.Message), e);
}
}

internal static EvaluationResult ModifyValue (EvaluationContext context, string value, object expectedType, Action<object> valueSetter)
{
var rightHandValue = EvaluateRightHandValue (context, value, expectedType);

object val;
try {
val = rightHandValue.Value;
} catch (Exception e) {
throw new ValueModificationException(string.Format ("Cannot get real object of {0}", value), e);
}
var convertedValue = ConvertRightHandValue (context, val, expectedType);
try {
valueSetter (convertedValue);
} catch (Exception e) {
throw new ValueModificationException(string.Format ("Error while assigning new value to object: {0}", e.Message), e);
}
// don't wrap with try-catch it, this call normally should not throw exceptions produced by wrong user input.
// If exception was occured this means something has gone wrong in we have to report it in log
return context.Evaluator.TargetObjectToExpression (context, convertedValue);
}

}
}
26 changes: 3 additions & 23 deletions Mono.Debugging/Mono.Debugging.Evaluation/ValueReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,29 +148,9 @@ ObjectValue IObjectValueSource.GetValue (ObjectPath path, EvaluationOptions opti

EvaluationResult IObjectValueSource.SetValue (ObjectPath path, string value, EvaluationOptions options)
{
try {
Context.WaitRuntimeInvokes ();

var ctx = GetContext (options);
ctx.Options.AllowMethodEvaluation = true;
ctx.Options.AllowTargetInvoke = true;

var vref = ctx.Evaluator.Evaluate (ctx, value, Type);
var newValue = ctx.Adapter.Convert (ctx, vref.Value, Type);
SetValue (ctx, newValue);
} catch (Exception ex) {
Context.WriteDebuggerError (ex);
Context.WriteDebuggerOutput ("Value assignment failed: {0}: {1}\n", ex.GetType (), ex.Message);
}

try {
return Context.Evaluator.TargetObjectToExpression (Context, Value);
} catch (Exception ex) {
Context.WriteDebuggerError (ex);
Context.WriteDebuggerOutput ("Value assignment failed: {0}: {1}\n", ex.GetType (), ex.Message);
}

return null;
Context.WaitRuntimeInvokes ();
var ctx = GetContext (options);
return ValueModificationUtil.ModifyValue (ctx, value, Type, newVal => SetValue (ctx, newVal));
}

object IObjectValueSource.GetRawValue (ObjectPath path, EvaluationOptions options)
Expand Down
Loading

0 comments on commit da12417

Please sign in to comment.