From 796612209d45f6404cd5c7f41ec6f41a8e468455 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 14 Jul 2018 00:02:51 +0200 Subject: [PATCH] Fix #1147: Use C# 7.3 syntax for ref reassignment. --- .../CSharp/ExpressionBuilder.cs | 12 +++++++++++- .../CSharp/StatementBuilder.cs | 12 +++++++++++- .../CSharp/Transforms/DeclareVariables.cs | 16 +++++++++------- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 0f8574e15..8574f02e8 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -500,7 +500,17 @@ namespace ICSharpCode.Decompiler.CSharp inst.Variable.Type = type; } } - return Assignment(ConvertVariable(inst.Variable).WithoutILInstruction(), translatedValue).WithILInstruction(inst); + var lhs = ConvertVariable(inst.Variable).WithoutILInstruction(); + if (lhs.Expression is DirectionExpression dirExpr && lhs.ResolveResult is ByReferenceResolveResult lhsRefRR) { + // ref (re-)assignment, emit "ref (a = ref b)". + lhs = lhs.UnwrapChild(dirExpr.Expression); + var assign = new AssignmentExpression(lhs.Expression, translatedValue.Expression) + .WithRR(new OperatorResolveResult(lhs.Type, ExpressionType.Assign, lhsRefRR, translatedValue.ResolveResult)); + return new DirectionExpression(FieldDirection.Ref, assign) + .WithoutILInstruction().WithRR(lhsRefRR); + } else { + return Assignment(lhs, translatedValue).WithILInstruction(inst); + } bool IsOtherValueType(IType type) { diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 91189da95..401ea608e 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -65,7 +65,17 @@ namespace ICSharpCode.Decompiler.CSharp { return new ExpressionStatement(exprBuilder.Translate(inst)); } - + + protected internal override Statement VisitStLoc(StLoc 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); + } + protected internal override Statement VisitNop(Nop inst) { var stmt = new EmptyStatement(); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs index 03675f879..b7a603af4 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/DeclareVariables.cs @@ -386,14 +386,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms bool IsMatchingAssignment(VariableToDeclare v, out AssignmentExpression assignment) { - assignment = v.InsertionPoint.nextNode as AssignmentExpression ?? (v.InsertionPoint.nextNode as ExpressionStatement)?.Expression as AssignmentExpression; - Expression expectedExpr = new IdentifierExpression(v.Name); - if (v.Type.Kind == TypeKind.ByReference) { - expectedExpr = new DirectionExpression(FieldDirection.Ref, expectedExpr); + assignment = v.InsertionPoint.nextNode as AssignmentExpression; + if (assignment == null) { + assignment = (v.InsertionPoint.nextNode as ExpressionStatement)?.Expression as AssignmentExpression; + if (assignment == null) + return false; } - if (assignment != null && assignment.Operator == AssignmentOperatorType.Assign && assignment.Left.IsMatch(expectedExpr)) - return true; - return false; + return assignment.Operator == AssignmentOperatorType.Assign + && assignment.Left is IdentifierExpression identExpr + && identExpr.Identifier == v.Name + && identExpr.TypeArguments.Count == 0; } void InsertVariableDeclarations(TransformContext context)