|
|
@ -336,53 +336,83 @@ namespace ICSharpCode.Decompiler.IL.Transforms |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// <summary>
|
|
|
|
/// if (logic.not(dynamic.isevent (ldloc a))) Block IL_0045 {
|
|
|
|
/// op is either add or remove/subtract:
|
|
|
|
/// dynamic.setmember.compound Setter2(ldloc a, dynamic.binary.operator AddAssign(dynamic.getmember Setter2(ldloc a), ldc.i4 5))
|
|
|
|
/// if (dynamic.isevent (target)) {
|
|
|
|
/// } else Block IL_0144 {
|
|
|
|
/// dynamic.invokemember.invokespecial.discard op_Name(target, value)
|
|
|
|
/// dynamic.invokemember.invokespecial.discard add_Setter2(ldloc a, ldc.i4 5)
|
|
|
|
/// } else {
|
|
|
|
|
|
|
|
/// dynamic.compound.op (dynamic.getmember Name(target), value)
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// =>
|
|
|
|
/// =>
|
|
|
|
/// dynamic.setmember.compound Setter2(ldloc a, dynamic.binary.operator AddAssign(dynamic.getmember Setter2(ldloc a), ldc.i4 5))
|
|
|
|
/// dynamic.compound.op (dynamic.getmember Name(target), value)
|
|
|
|
/// </summary>
|
|
|
|
/// </summary>
|
|
|
|
bool TransformDynamicAddAssignOrRemoveAssign(IfInstruction inst) |
|
|
|
bool TransformDynamicAddAssignOrRemoveAssign(IfInstruction inst) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!inst.Condition.MatchLogicNot(out var possibleIsEvent)) |
|
|
|
if (!inst.MatchIfInstructionPositiveCondition(out var condition, out var trueInst, out var falseInst)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
if (!(possibleIsEvent is DynamicIsEventInstruction isEvent)) |
|
|
|
if (!(condition is DynamicIsEventInstruction isEvent)) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
var trueInst = Block.Unwrap(inst.TrueInst); |
|
|
|
trueInst = Block.Unwrap(trueInst); |
|
|
|
var falseInst = Block.Unwrap(inst.FalseInst); |
|
|
|
falseInst = Block.Unwrap(falseInst); |
|
|
|
if (!(trueInst is DynamicSetMemberInstruction dynamicSetMember |
|
|
|
if (!(falseInst is DynamicCompoundAssign dynamicCompoundAssign)) |
|
|
|
&& dynamicSetMember.BinderFlags.HasFlag(CSharpBinderFlags.ValueFromCompoundAssignment) |
|
|
|
|
|
|
|
&& isEvent.Argument.Match(dynamicSetMember.Target).Success |
|
|
|
|
|
|
|
&& dynamicSetMember.Value is DynamicBinaryOperatorInstruction binaryOp |
|
|
|
|
|
|
|
&& binaryOp.Left is DynamicGetMemberInstruction dynamicGetMember |
|
|
|
|
|
|
|
&& dynamicGetMember.Target.Match(dynamicSetMember.Target).Success |
|
|
|
|
|
|
|
&& dynamicSetMember.Name == dynamicGetMember.Name |
|
|
|
|
|
|
|
&& falseInst is DynamicInvokeMemberInstruction invokeMember |
|
|
|
|
|
|
|
&& invokeMember.BinderFlags.HasFlag(CSharpBinderFlags.InvokeSpecialName) |
|
|
|
|
|
|
|
&& invokeMember.Arguments.Count == 2 && invokeMember.Arguments[0].Match(dynamicGetMember.Target).Success) |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
if (!(dynamicCompoundAssign.Target is DynamicGetMemberInstruction getMember)) |
|
|
|
switch (binaryOp.Operation) { |
|
|
|
return false; |
|
|
|
|
|
|
|
if (!isEvent.Argument.Match(getMember.Target).Success) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
if (!(trueInst is DynamicInvokeMemberInstruction invokeMember)) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
if (!(invokeMember.BinderFlags.HasFlag(CSharpBinderFlags.InvokeSpecialName) && invokeMember.BinderFlags.HasFlag(CSharpBinderFlags.ResultDiscarded))) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
switch (dynamicCompoundAssign.Operation) { |
|
|
|
case ExpressionType.AddAssign: |
|
|
|
case ExpressionType.AddAssign: |
|
|
|
if (invokeMember.Name != "add_" + dynamicGetMember.Name) |
|
|
|
if (invokeMember.Name != "add_" + getMember.Name) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
break; |
|
|
|
break; |
|
|
|
case ExpressionType.SubtractAssign: |
|
|
|
case ExpressionType.SubtractAssign: |
|
|
|
if (invokeMember.Name != "remove_" + dynamicGetMember.Name) |
|
|
|
if (invokeMember.Name != "remove_" + getMember.Name) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
break; |
|
|
|
break; |
|
|
|
default: |
|
|
|
default: |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!binaryOp.Right.Match(invokeMember.Arguments[1]).Success) |
|
|
|
if (!dynamicCompoundAssign.Value.Match(invokeMember.Arguments[1]).Success) |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
inst.ReplaceWith(trueInst); |
|
|
|
if (!invokeMember.Arguments[0].Match(getMember.Target).Success) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
inst.ReplaceWith(dynamicCompoundAssign); |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
|
|
/// dynamic.setmember.compound Name(target, dynamic.binary.operator AddAssign(dynamic.getmember Name(target), value))
|
|
|
|
|
|
|
|
/// =>
|
|
|
|
|
|
|
|
/// dynamic.compound.op (dynamic.getmember Name(target), value)
|
|
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
|
|
protected internal override void VisitDynamicSetMemberInstruction(DynamicSetMemberInstruction inst) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
if (!inst.BinderFlags.HasFlag(CSharpBinderFlags.ValueFromCompoundAssignment)) { |
|
|
|
|
|
|
|
base.VisitDynamicSetMemberInstruction(inst); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!(inst.Value is DynamicBinaryOperatorInstruction binaryOp)) { |
|
|
|
|
|
|
|
base.VisitDynamicSetMemberInstruction(inst); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!(binaryOp.Left is DynamicGetMemberInstruction dynamicGetMember)) { |
|
|
|
|
|
|
|
base.VisitDynamicSetMemberInstruction(inst); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!dynamicGetMember.Target.Match(inst.Target).Success) { |
|
|
|
|
|
|
|
base.VisitDynamicSetMemberInstruction(inst); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (inst.Name != dynamicGetMember.Name || !DynamicCompoundAssign.IsExpressionTypeSupported(binaryOp.Operation)) { |
|
|
|
|
|
|
|
base.VisitDynamicSetMemberInstruction(inst); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
inst.ReplaceWith(new DynamicCompoundAssign(binaryOp.Operation, binaryOp.Left, binaryOp.LeftArgumentInfo, binaryOp.Right, binaryOp.RightArgumentInfo)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
IfInstruction HandleConditionalOperator(IfInstruction inst) |
|
|
|
IfInstruction HandleConditionalOperator(IfInstruction inst) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// if (cond) stloc (A, V1) else stloc (A, V2) --> stloc (A, if (cond) V1 else V2)
|
|
|
|
// if (cond) stloc (A, V1) else stloc (A, V2) --> stloc (A, if (cond) V1 else V2)
|
|
|
|