Browse Source

Fix compound assignments with local variables.

pull/3003/head
Siegfried Pammer 2 years ago
parent
commit
13227e433e
  1. 992
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 25
      ICSharpCode.Decompiler/CSharp/Transforms/PrettifyAssignments.cs

992
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs

File diff suppressed because it is too large Load Diff

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1587,7 +1587,7 @@ namespace ICSharpCode.Decompiler.CSharp
var rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult); var rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
if (rr.IsError || NullableType.GetUnderlyingType(rr.Type).GetStackType() != inst.UnderlyingResultType if (rr.IsError || NullableType.GetUnderlyingType(rr.Type).GetStackType() != inst.UnderlyingResultType
|| !IsCompatibleWithSign(left.Type, inst.Sign) || !IsCompatibleWithSign(right.Type, inst.Sign)) || !IsCompatibleWithSign(rr.Type, inst.Sign))
{ {
// Left and right operands are incompatible, so convert them to a common type // Left and right operands are incompatible, so convert them to a common type
Sign sign = inst.Sign; Sign sign = inst.Sign;

25
ICSharpCode.Decompiler/CSharp/Transforms/PrettifyAssignments.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -44,10 +45,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{ {
base.VisitAssignmentExpression(assignment); base.VisitAssignmentExpression(assignment);
// Combine "x = x op y" into "x op= y" // Combine "x = x op y" into "x op= y"
BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression; // Also supports "x = (T)(x op y)" -> "x op= y", if x.GetType() == T
if (binary != null && assignment.Operator == AssignmentOperatorType.Assign) // and y is implicitly convertible to T.
Expression rhs = assignment.Right;
IType expectedType = null;
if (assignment.Right is CastExpression { Type: var astType } cast)
{ {
if (CanConvertToCompoundAssignment(assignment.Left) && assignment.Left.IsMatch(binary.Left)) rhs = cast.Expression;
expectedType = astType.GetResolveResult().Type;
}
if (rhs is BinaryOperatorExpression binary && assignment.Operator == AssignmentOperatorType.Assign)
{
if (CanConvertToCompoundAssignment(assignment.Left) && assignment.Left.IsMatch(binary.Left)
&& IsImplicitlyConvertible(binary.Right, expectedType))
{ {
assignment.Operator = GetAssignmentOperatorForBinaryOperator(binary.Operator); assignment.Operator = GetAssignmentOperatorForBinaryOperator(binary.Operator);
if (assignment.Operator != AssignmentOperatorType.Assign) if (assignment.Operator != AssignmentOperatorType.Assign)
@ -78,6 +88,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
} }
} }
bool IsImplicitlyConvertible(Expression rhs, IType expectedType)
{
if (expectedType == null)
return true;
var conversions = CSharpConversions.Get(context.TypeSystem);
return conversions.ImplicitConversion(rhs.GetResolveResult(), expectedType).IsImplicit;
}
} }
public static AssignmentOperatorType GetAssignmentOperatorForBinaryOperator(BinaryOperatorType bop) public static AssignmentOperatorType GetAssignmentOperatorForBinaryOperator(BinaryOperatorType bop)

Loading…
Cancel
Save