From 5f324de10bcc9f9ad3144b4030a1a0a27615a8dc Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 16 Jul 2022 15:02:25 +0200 Subject: [PATCH] Add support for ref fields. --- .../CSharp/ExpressionBuilder.cs | 32 +++++++++++++------ .../CSharp/StatementBuilder.cs | 11 +++++++ 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index c354df411..6c1d6f9be 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -357,16 +357,17 @@ namespace ICSharpCode.Decompiler.CSharp mrr = new MemberResolveResult(target.ResolveResult, field); } - if (requireTarget) - { - return new MemberReferenceExpression(target, field.Name) - .WithRR(mrr); - } - else + var expr = requireTarget + ? new MemberReferenceExpression(target, field.Name).WithRR(mrr) + : new IdentifierExpression(field.Name).WithRR(mrr); + + if (field.Type.Kind == TypeKind.ByReference) { - return new IdentifierExpression(field.Name) - .WithRR(mrr); + expr = new DirectionExpression(FieldDirection.Ref, expr) + .WithRR(new ByReferenceResolveResult(mrr, ReferenceKind.Ref)); } + + return expr; } TranslatedExpression IsType(IsInst inst) @@ -2798,7 +2799,20 @@ namespace ICSharpCode.Decompiler.CSharp { value = Translate(inst.Value, typeHint: target.Type); } - return Assignment(target, value).WithILInstruction(inst); + if (target.Expression is DirectionExpression dirExpr && target.ResolveResult is ByReferenceResolveResult lhsRefRR) + { + // ref (re-)assignment, emit "ref (a = ref b)". + target = target.UnwrapChild(dirExpr.Expression); + value = value.ConvertTo(lhsRefRR.Type, this, allowImplicitConversion: true); + var assign = new AssignmentExpression(target.Expression, value.Expression) + .WithRR(new OperatorResolveResult(target.Type, ExpressionType.Assign, lhsRefRR, value.ResolveResult)); + return new DirectionExpression(FieldDirection.Ref, assign) + .WithoutILInstruction().WithRR(lhsRefRR); + } + else + { + return Assignment(target, value).WithILInstruction(inst); + } } private TranslatedExpression UnalignedStObj(StObj inst) diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index daeaafb41..32d46b643 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -120,6 +120,17 @@ namespace ICSharpCode.Decompiler.CSharp return new ExpressionStatement(expr).WithILInstruction(inst); } + protected internal override TranslatedStatement VisitStObj(StObj inst) + { + var expr = exprBuilder.Translate(inst); + // strip top-level ref on ref re-assignment + if (expr.Expression is DirectionExpression dirExpr) + { + expr = expr.UnwrapChild(dirExpr.Expression); + } + return new ExpressionStatement(expr).WithILInstruction(inst); + } + protected internal override TranslatedStatement VisitNop(Nop inst) { var stmt = new EmptyStatement();