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 @@ -1587,7 +1587,7 @@ namespace ICSharpCode.Decompiler.CSharp
var rr = resolverWithOverflowCheck.ResolveBinaryOperator(op, left.ResolveResult, right.ResolveResult);
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
Sign sign = inst.Sign;

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

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.TypeSystem;
@ -44,10 +45,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -44,10 +45,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
base.VisitAssignmentExpression(assignment);
// Combine "x = x op y" into "x op= y"
BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression;
if (binary != null && assignment.Operator == AssignmentOperatorType.Assign)
// Also supports "x = (T)(x op y)" -> "x op= y", if x.GetType() == T
// 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);
if (assignment.Operator != AssignmentOperatorType.Assign)
@ -78,6 +88,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -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)

Loading…
Cancel
Save