Skip to content

[WIP] Revamped expression resolver to have context #251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Mono.Debugging.Soft/SoftDebuggerBacktrace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ DC.StackFrame CreateStackFrame (MDB.StackFrame frame, int frameIndex)
return new SoftDebuggerStackFrame (frame, addressSpace, location, language, external, hasDebugInfo, hidden, typeFQN, typeFullName);
}

protected override EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options)
public override EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options)
{
ValidateStack ();

Expand Down
2 changes: 1 addition & 1 deletion Mono.Debugging.Soft/SoftDebuggerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2372,7 +2372,7 @@ string EvaluateExpression (ThreadMirror thread, string expression, BreakEvent bp

// resolve types...
if (ctx.SourceCodeAvailable)
expression = ctx.Evaluator.Resolve (this, GetSourceLocation (frames[0]), expression);
expression = ctx.Evaluator.Resolve (this, ctx, GetSourceLocation (frames[0]), expression);
}

ValueReference val = ctx.Evaluator.Evaluate (ctx, expression);
Expand Down
2 changes: 1 addition & 1 deletion Mono.Debugging.Win32/CorDebuggerBacktrace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ internal List<CorFrame> FrameList {
}
}

protected override EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options)
public override EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options)
{
var ctx = new CorEvaluationContext (session, this, frameIndex, options);
ctx.Thread = thread;
Expand Down
2 changes: 2 additions & 0 deletions Mono.Debugging/Mono.Debugging.Backend/IBacktrace.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

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

namespace Mono.Debugging.Backend
{
Expand All @@ -12,6 +13,7 @@ public interface IBacktrace: IDebuggerBackendObject
ObjectValue GetThisReference (int frameIndex, EvaluationOptions options);
ExceptionInfo GetException (int frameIndex, EvaluationOptions options);
ObjectValue[] GetAllLocals (int frameIndex, EvaluationOptions options);
EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options);
ObjectValue[] GetExpressionValues (int frameIndex, string[] expressions, EvaluationOptions options);
CompletionData GetExpressionCompletionData (int frameIndex, string exp);
AssemblyLine[] Disassemble (int frameIndex, int firstLine, int count);
Expand Down
12 changes: 6 additions & 6 deletions Mono.Debugging/Mono.Debugging.Client/DebuggerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -890,18 +890,18 @@ public AssemblyLine[] DisassembleFile (string file)
}
}

public string ResolveExpression (string expression, string file, int line, int column, int endLine, int endColumn)
public string ResolveExpression (EvaluationContext ctx, string expression, string file, int line, int column, int endLine, int endColumn)
{
return ResolveExpression (expression, new SourceLocation (null, file, line, column, endLine, endColumn, null, null));
return ResolveExpression (ctx, expression, new SourceLocation (null, file, line, column, endLine, endColumn, null, null));
}

public virtual string ResolveExpression (string expression, SourceLocation location)
public virtual string ResolveExpression (EvaluationContext ctx, string expression, SourceLocation location)
{
var key = expression + " " + location;

if (!resolvedExpressionCache.TryGetValue (key, out var resolved)) {
try {
resolved = OnResolveExpression (expression, location);
resolved = OnResolveExpression (ctx, expression, location);
} catch (Exception ex) {
OnDebuggerOutput (true, "Error while resolving expression: " + ex.Message);
}
Expand Down Expand Up @@ -992,13 +992,13 @@ protected void RaiseStopEvent ()
/// <returns>
/// The resolved expression
/// </returns>
protected virtual string OnResolveExpression (string expression, SourceLocation location)
protected virtual string OnResolveExpression (EvaluationContext ctx, string expression, SourceLocation location)
{
var resolver = defaultResolver;
if (GetExpressionEvaluator != null)
resolver = GetExpressionEvaluator(System.IO.Path.GetExtension(location.FileName))?.Evaluator ?? defaultResolver;

return resolver.Resolve(this, location, expression);
return resolver.Resolve (this, ctx, location, expression);
}

internal protected string ResolveIdentifierAsType (string identifier, SourceLocation location)
Expand Down
23 changes: 16 additions & 7 deletions Mono.Debugging/Mono.Debugging.Client/StackFrame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading;

using Mono.Debugging.Backend;
using Mono.Debugging.Evaluation;

namespace Mono.Debugging.Client
{
Expand Down Expand Up @@ -272,9 +273,9 @@ public ExceptionInfo GetException (EvaluationOptions options)
return value;
}

public string ResolveExpression (string exp)
public string ResolveExpression (EvaluationContext ctx, string expression)
{
return session.ResolveExpression (exp, location);
return session.ResolveExpression (ctx, expression, location);
}

public ObjectValue[] GetExpressionValues (string[] expressions, bool evaluateMethods)
Expand All @@ -297,9 +298,11 @@ public ObjectValue[] GetExpressionValues (string[] expressions, EvaluationOption
}

if (options.UseExternalTypeResolver) {
var ctx = sourceBacktrace.GetEvaluationContext (index, options);

var resolved = new string [expressions.Length];
for (int n = 0; n < expressions.Length; n++)
resolved[n] = ResolveExpression (expressions[n]);
resolved[n] = ResolveExpression (ctx, expressions[n]);

expressions = resolved;
}
Expand All @@ -323,8 +326,11 @@ public ObjectValue GetExpressionValue (string expression, EvaluationOptions opti
return ObjectValue.CreateUnknown (expression);
}

if (options.UseExternalTypeResolver)
expression = ResolveExpression (expression);
if (options.UseExternalTypeResolver) {
var ctx = sourceBacktrace.GetEvaluationContext (index, options);

expression = ResolveExpression (ctx, expression);
}

var values = sourceBacktrace.GetExpressionValues (index, new [] { expression }, options);
ObjectValue.ConnectCallbacks (this, values);
Expand All @@ -344,8 +350,11 @@ public bool ValidateExpression (string expression)
/// </summary>
public ValidationResult ValidateExpression (string expression, EvaluationOptions options)
{
if (options.UseExternalTypeResolver)
expression = ResolveExpression (expression);
if (options.UseExternalTypeResolver) {
var ctx = sourceBacktrace.GetEvaluationContext (index, options);

expression = ResolveExpression (ctx, expression);
}

return sourceBacktrace.ValidateExpression (index, expression, options);
}
Expand Down
2 changes: 1 addition & 1 deletion Mono.Debugging/Mono.Debugging.Evaluation/BaseBacktrace.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected BaseBacktrace (ObjectValueAdaptor adaptor)

public ObjectValueAdaptor Adaptor { get; set; }

protected abstract EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options);
public abstract EvaluationContext GetEvaluationContext (int frameIndex, EvaluationOptions options);

public abstract int FrameCount { get; }

Expand Down
12 changes: 11 additions & 1 deletion Mono.Debugging/Mono.Debugging.Evaluation/ExpressionEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,18 @@ public virtual bool CaseSensitive {
get { return true; }
}

public abstract string Resolve (DebuggerSession session, SourceLocation location, string expression);
public abstract string Resolve (DebuggerSession session, EvaluationContext ctx, SourceLocation location, string expression);

public virtual IEnumerable<ValueReference> GetLocalVariables (EvaluationContext ctx)
{
return ctx.Adapter.GetLocalVariables (ctx);
}

public virtual ValueReference GetLocalVariable (EvaluationContext ctx, string name)
{
return ctx.Adapter.GetLocalVariable (ctx, name);
}

public virtual ValueReference GetThisReference (EvaluationContext ctx)
{
return ctx.Adapter.GetThisReference (ctx);
Expand All @@ -200,6 +205,11 @@ public virtual IEnumerable<ValueReference> GetParameters (EvaluationContext ctx)
return ctx.Adapter.GetParameters (ctx);
}

public virtual ValueReference GetParameter (EvaluationContext ctx, string name)
{
return ctx.Adapter.GetParameter (ctx, name);
}

public virtual ValueReference GetCurrentException (EvaluationContext ctx)
{
return ctx.Adapter.GetCurrentException (ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,36 +83,36 @@ public override ValueReference Evaluate (EvaluationContext ctx, string expressio
return expr.AcceptVisitor (evaluator);
}

public override string Resolve (DebuggerSession session, SourceLocation location, string exp)
public override string Resolve (DebuggerSession session, EvaluationContext ctx, SourceLocation location, string expression)
{
return Resolve (session, location, exp, false);
return Resolve (session, ctx, location, expression, false);
}

string Resolve (DebuggerSession session, SourceLocation location, string expression, bool tryTypeOf)
string Resolve (DebuggerSession session, EvaluationContext ctx, SourceLocation location, string expression, bool tryTypeOf)
{
expression = expression.Trim ();

if (expression.Length > 0 && expression[0] == '?')
return "?" + Resolve (session, location, expression.Substring (1).Trim ());
return "?" + Resolve (session, ctx, location, expression.Substring (1).TrimStart ());

if (expression.Length > 3 && expression.StartsWith ("var", StringComparison.Ordinal) && char.IsWhiteSpace (expression[3]))
return "var " + Resolve (session, location, expression.Substring (4).Trim (' ', '\t'));
return "var " + Resolve (session, ctx, location, expression.Substring (4).TrimStart ());

expression = ReplaceExceptionTag (expression, session.Options.EvaluationOptions.CurrentExceptionTag);

var expr = new CSharpParser ().ParseExpression (expression);
if (expr == null)
return expression;

var resolver = new NRefactoryExpressionResolverVisitor (session, location, expression);
var resolver = new NRefactoryExpressionResolverVisitor (this, session, ctx, location, expression);
expr.AcceptVisitor (resolver);

string resolved = resolver.GetResolvedExpression ();
if (resolved == expression && !tryTypeOf && (expr is BinaryOperatorExpression) && IsTypeName (expression)) {
// This is a hack to be able to parse expressions such as "List<string>". The NRefactory parser
// can parse a single type name, so a solution is to wrap it around a typeof(). We do it if
// the evaluation fails.
string res = Resolve (session, location, "typeof(" + expression + ")", true);
string res = Resolve (session, ctx, location, "typeof(" + expression + ")", true);
return res.Substring (7, res.Length - 8);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
// THE SOFTWARE.

using System;
using System.Linq;
using System.Text;
using System.Collections.Generic;

Expand All @@ -38,8 +39,10 @@ namespace Mono.Debugging.Evaluation
public class NRefactoryExpressionResolverVisitor : DepthFirstAstVisitor
{
readonly List<Replacement> replacements = new List<Replacement> ();
readonly ExpressionEvaluator evaluator;
readonly SourceLocation location;
readonly DebuggerSession session;
readonly EvaluationContext ctx;
readonly string expression;
string parentType;

Expand All @@ -50,11 +53,13 @@ class Replacement
public int Length;
}

public NRefactoryExpressionResolverVisitor (DebuggerSession session, SourceLocation location, string expression)
public NRefactoryExpressionResolverVisitor (ExpressionEvaluator evaluator, DebuggerSession session, EvaluationContext ctx, SourceLocation location, string expression)
{
this.expression = expression.Replace ("\n", "").Replace ("\r", "");
this.evaluator = evaluator;
this.session = session;
this.location = location;
this.ctx = ctx;
}

internal string GetResolvedExpression ()
Expand Down Expand Up @@ -128,8 +133,17 @@ public override void VisitIdentifierExpression (IdentifierExpression identifierE

int length = identifierExpression.IdentifierToken.EndLocation.Column - identifierExpression.IdentifierToken.StartLocation.Column;
int offset = identifierExpression.IdentifierToken.StartLocation.Column - 1;
var name = identifierExpression.Identifier;

ReplaceType (identifierExpression.Identifier, identifierExpression.TypeArguments.Count, offset, length);
// check if the identifier is a local variable or a member variable
if (evaluator.GetLocalVariable (ctx, name) != null)
return;

var thisReference = evaluator.GetThisReference (ctx);
if (thisReference != null && thisReference.GetChild (name, ctx.Options) != null)
return;

ReplaceType (name, identifierExpression.TypeArguments.Count, offset, length);
}

public override void VisitTypeReferenceExpression (TypeReferenceExpression typeReferenceExpression)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ protected virtual ValueReference OnGetLocalVariable (EvaluationContext ctx, stri
return best;
}

public virtual ValueReference GetParameter (EvaluationContext ctx, string name)
public ValueReference GetParameter (EvaluationContext ctx, string name)
{
return OnGetParameter (ctx, name);
}
Expand Down