Browse Source

Fix #954: don't use invalid compound assignments on enums

pull/960/head
Daniel Grunwald 8 years ago
parent
commit
248a9ad76f
  1. 6
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.cs
  2. 24
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.il
  3. 23
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.il
  4. 19
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.roslyn.il
  5. 20
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.roslyn.il
  6. 35
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  7. 105
      ICSharpCode.Decompiler/IL/Instructions.cs
  8. 7
      ICSharpCode.Decompiler/IL/Instructions.tt
  9. 4
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  10. 17
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  11. 34
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  12. 22
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

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

@ -410,5 +410,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -410,5 +410,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Item item = CompoundAssignmentTest.GetItem(null);
item.Self = item;
}
void Issue954(ref MyEnum a, MyEnum b)
{
// cannot decompile to: "a %= b;", because the % operator does not apply to enums
a = (MyEnum)((int)a % (int)b);
}
}
}

24
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly w1xcwa3w
.assembly gvvksqgl
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module w1xcwa3w.dll
// MVID: {FAFFB825-2101-4417-8C03-0E0B083653E5}
.module gvvksqgl.dll
// MVID: {50934C05-8B92-4905-A41A-146C5F2392BA}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00D60000
// Image base: 0x00410000
// =============== CLASS MEMBERS DECLARATION ===================
@ -1543,6 +1543,22 @@ @@ -1543,6 +1543,22 @@
IL_000f: ret
} // end of method CompoundAssignmentTest::Issue882
.method private hidebysig instance void
Issue954(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MyEnum& a,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MyEnum b) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.1
IL_0003: ldind.i4
IL_0004: ldarg.2
IL_0005: rem
IL_0006: stind.i4
IL_0007: ret
} // end of method CompoundAssignmentTest::Issue954
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

23
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly pbv15mad
.assembly '20aqunvz'
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module pbv15mad.dll
// MVID: {7F137601-6720-4272-9855-AEC542FD460D}
.module '20aqunvz.dll'
// MVID: {3A9D60C3-9668-4C33-85C8-329DB1EEECE6}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x01300000
// Image base: 0x029E0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -1262,6 +1262,21 @@ @@ -1262,6 +1262,21 @@
IL_000e: ret
} // end of method CompoundAssignmentTest::Issue882
.method private hidebysig instance void
Issue954(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MyEnum& a,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MyEnum b) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.1
IL_0002: ldind.i4
IL_0003: ldarg.2
IL_0004: rem
IL_0005: stind.i4
IL_0006: ret
} // end of method CompoundAssignmentTest::Issue954
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

19
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.opt.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module CompoundAssignmentTest.dll
// MVID: {7FF443A1-4D5C-4B6C-ABE8-2BE60079524D}
// MVID: {8664D95A-CCCF-4302-9678-AEB0491B7A00}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02DC0000
// Image base: 0x02D20000
// =============== CLASS MEMBERS DECLARATION ===================
@ -1268,6 +1268,21 @@ @@ -1268,6 +1268,21 @@
IL_000c: ret
} // end of method CompoundAssignmentTest::Issue882
.method private hidebysig instance void
Issue954(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MyEnum& a,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MyEnum b) cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.1
IL_0001: ldarg.1
IL_0002: ldind.i4
IL_0003: ldarg.2
IL_0004: rem
IL_0005: stind.i4
IL_0006: ret
} // end of method CompoundAssignmentTest::Issue954
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

20
ICSharpCode.Decompiler.Tests/TestCases/Pretty/CompoundAssignmentTest.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module CompoundAssignmentTest.dll
// MVID: {514BA798-3837-4D3D-8485-D675114840C6}
// MVID: {9D118C00-E9E9-446E-9B2F-0C32732A9171}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x01590000
// Image base: 0x02BF0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -1538,6 +1538,22 @@ @@ -1538,6 +1538,22 @@
IL_000f: ret
} // end of method CompoundAssignmentTest::Issue882
.method private hidebysig instance void
Issue954(valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MyEnum& a,
valuetype ICSharpCode.Decompiler.Tests.TestCases.Pretty.CompoundAssignmentTest/MyEnum b) cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.1
IL_0003: ldind.i4
IL_0004: ldarg.2
IL_0005: rem
IL_0006: stind.i4
IL_0007: ret
} // end of method CompoundAssignmentTest::Issue954
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

35
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -127,5 +127,40 @@ namespace ICSharpCode.Decompiler.IL @@ -127,5 +127,40 @@ namespace ICSharpCode.Decompiler.IL
{
return primitiveType.GetStackType().IsIntegerType();
}
/// <summary>
/// Infers the C# type for an IL instruction.
///
/// Returns SpecialType.UnknownType for unsupported instructions.
/// </summary>
public static IType InferType(this ILInstruction inst)
{
switch (inst) {
case NewObj newObj:
return newObj.Method.DeclaringType;
case Call call:
return call.Method.ReturnType;
case CallVirt callVirt:
return callVirt.Method.ReturnType;
case CallIndirect calli:
return calli.ReturnType;
case LdObj ldobj:
return ldobj.Type;
case StObj stobj:
return stobj.Type;
case LdLoc ldloc:
return ldloc.Variable.Type;
case StLoc stloc:
return stloc.Variable.Type;
case LdLoca ldloca:
return new TypeSystem.ByReferenceType(ldloca.Variable.Type);
case LdFlda ldflda:
return new TypeSystem.ByReferenceType(ldflda.Field.Type);
case LdsFlda ldsflda:
return new TypeSystem.ByReferenceType(ldsflda.Field.Type);
default:
return SpecialType.UnknownType;
}
}
}
}

105
ICSharpCode.Decompiler/IL/Instructions.cs

@ -943,9 +943,12 @@ namespace ICSharpCode.Decompiler.IL @@ -943,9 +943,12 @@ namespace ICSharpCode.Decompiler.IL
clone.Value = this.value.Clone();
return clone;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return type.GetStackType(); } }
public override void AcceptVisitor(ILVisitor visitor)
{
@ -2814,9 +2817,12 @@ namespace ICSharpCode.Decompiler.IL @@ -2814,9 +2817,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
@ -3350,9 +3356,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3350,9 +3356,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
@ -3401,9 +3410,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3401,9 +3410,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
@ -3491,9 +3503,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3491,9 +3503,12 @@ namespace ICSharpCode.Decompiler.IL
clone.Target = this.target.Clone();
return clone;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -3617,9 +3632,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3617,9 +3632,12 @@ namespace ICSharpCode.Decompiler.IL
clone.Value = this.value.Clone();
return clone;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -3678,9 +3696,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3678,9 +3696,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return StackType.O; } }
protected override InstructionFlags ComputeFlags()
{
@ -3729,9 +3750,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3729,9 +3750,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return StackType.Ref; } }
protected override InstructionFlags ComputeFlags()
{
@ -3780,9 +3804,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3780,9 +3804,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
@ -3856,9 +3883,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3856,9 +3883,12 @@ namespace ICSharpCode.Decompiler.IL
this.Indices = new InstructionCollection<ILInstruction>(this, 0);
this.Indices.AddRange(indices);
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public static readonly SlotInfo IndicesSlot = new SlotInfo("Indices", canInlineInto: true);
public InstructionCollection<ILInstruction> Indices { get; private set; }
protected sealed override int GetChildCount()
@ -3946,9 +3976,12 @@ namespace ICSharpCode.Decompiler.IL @@ -3946,9 +3976,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return type.GetStackType(); } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
@ -4059,9 +4092,12 @@ namespace ICSharpCode.Decompiler.IL @@ -4059,9 +4092,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return StackType.I4; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
@ -4181,9 +4217,12 @@ namespace ICSharpCode.Decompiler.IL @@ -4181,9 +4217,12 @@ namespace ICSharpCode.Decompiler.IL
this.Indices = new InstructionCollection<ILInstruction>(this, 1);
this.Indices.AddRange(indices);
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public static readonly SlotInfo ArraySlot = new SlotInfo("Array", canInlineInto: true);
ILInstruction array;
public ILInstruction Array {
@ -4468,9 +4507,12 @@ namespace ICSharpCode.Decompiler.IL @@ -4468,9 +4507,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{
@ -4538,9 +4580,12 @@ namespace ICSharpCode.Decompiler.IL @@ -4538,9 +4580,12 @@ namespace ICSharpCode.Decompiler.IL
{
this.type = type;
}
readonly IType type;
IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
public IType Type {
get { return type; }
set { type = value; InvalidateFlags(); }
}
public override StackType ResultType { get { return StackType.Ref; } }
protected override InstructionFlags ComputeFlags()
{

7
ICSharpCode.Decompiler/IL/Instructions.tt

@ -939,12 +939,15 @@ protected override void Disconnected() @@ -939,12 +939,15 @@ protected override void Disconnected()
static Action<OpCode> HasTypeOperand = opCode => {
opCode.ConstructorParameters.Add("IType type");
opCode.Members.Add("readonly IType type;");
opCode.Members.Add("IType type;");
opCode.ConstructorBody.Add("this.type = type;");
opCode.MatchParameters.Add(new MatchParamInfo { TypeName = "IType", Name = "type", FieldName = "Type" });
opCode.PerformMatchConditions.Add("type.Equals(o.type)");
opCode.Members.Add("/// <summary>Returns the type operand.</summary>" + Environment.NewLine
+ "public IType Type { get { return type; } }");
+ "public IType Type {" + Environment.NewLine
+ "\tget { return type; }" + Environment.NewLine
+ "\tset { type = value; InvalidateFlags(); }" + Environment.NewLine
+ "}");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("type.WriteTo(output);");

4
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -85,6 +85,10 @@ namespace ICSharpCode.Decompiler.IL @@ -85,6 +85,10 @@ namespace ICSharpCode.Decompiler.IL
return false;
type = NullableType.GetUnderlyingType(type);
}
if (type.Kind == TypeKind.Enum) {
if (binary.Operator != BinaryNumericOperator.Add && binary.Operator != BinaryNumericOperator.Sub)
return false;
}
if (binary.Sign != Sign.None) {
if (type.GetSign() != binary.Sign)
return false;

17
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -359,18 +359,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -359,18 +359,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!variableType.IsKnownType(KnownTypeCode.Object))
return variableType;
switch (inst) {
case NewObj newObj:
return newObj.Method.DeclaringType;
case Call call:
return call.Method.ReturnType;
case CallVirt callVirt:
return callVirt.Method.ReturnType;
case CallIndirect calli:
return calli.ReturnType;
default:
return context.TypeSystem.Compilation.FindType(inst.ResultType.ToKnownTypeCode());
}
IType inferredType = inst.InferType();
if (inferredType.Kind != TypeKind.Unknown)
return inferredType;
else
return variableType;
}
internal static string GenerateForeachVariableName(ILFunction function, ILInstruction valueContext, ILVariable existingVariable = null)

34
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -16,9 +16,11 @@ @@ -16,9 +16,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.IL.Transforms
{
@ -279,17 +281,29 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -279,17 +281,29 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (inst.Value is BinaryNumericInstruction binary
&& binary.Left.MatchLdObj(out ILInstruction target, out IType t)
&& inst.Target.Match(target).Success
&& SemanticHelper.IsPure(target.Flags)
&& CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, t))
&& binary.Left is LdObj ldobj
&& inst.Target.Match(ldobj.Target).Success
&& SemanticHelper.IsPure(ldobj.Target.Flags))
{
context.Step("compound assignment", inst);
// stobj(target, binary.op(ldobj(target), ...))
// => compound.op(target, ...)
inst.ReplaceWith(new CompoundAssignmentInstruction(
binary, binary.Left, binary.Right,
t, CompoundAssignmentType.EvaluatesToNewValue));
// ldobj.Type may just be 'int' (due to ldind.i4) when we're actually operating on a 'ref MyEnum'.
// Try to determine the real type of the object we're modifying:
IType targetType = ldobj.Target.InferType();
if (targetType.Kind == TypeKind.Pointer || targetType.Kind == TypeKind.ByReference) {
targetType = ((TypeWithElementType)targetType).ElementType;
if (targetType.Kind == TypeKind.Unknown || targetType.GetSize() != ldobj.Type.GetSize()) {
targetType = ldobj.Type;
}
} else {
targetType = ldobj.Type;
}
if (CompoundAssignmentInstruction.IsBinaryCompatibleWithType(binary, targetType)) {
context.Step("compound assignment", inst);
// stobj(target, binary.op(ldobj(target), ...))
// => compound.op(target, ...)
inst.ReplaceWith(new CompoundAssignmentInstruction(
binary, binary.Left, binary.Right,
targetType, CompoundAssignmentType.EvaluatesToNewValue));
}
}
}

22
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -296,29 +296,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -296,29 +296,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case KnownTypeCode.Char:
return !(val >= ushort.MinValue && val <= ushort.MaxValue);
}
} else if (value is LdObj ldobj) {
return IsImplicitTruncation(ldobj.Type, type);
} else if (value is StObj stobj) {
return IsImplicitTruncation(stobj.Type, type);
} else if (value is LdLoc ldloc) {
return IsImplicitTruncation(ldloc.Variable.Type, type);
} else if (value is StLoc stloc) {
return IsImplicitTruncation(stloc.Variable.Type, type);
} else if (value is CallInstruction call) {
return IsImplicitTruncation(call.Method.ReturnType, type);
} else if (value is Conv conv) {
return conv.TargetType != type.ToPrimitiveType();
} else if (value is Comp) {
return false; // comp returns 0 or 1, which always fits
} else {
IType inferredType = value.InferType();
if (inferredType.Kind != TypeKind.Unknown) {
return !(inferredType.GetSize() <= type.GetSize() && inferredType.GetSign() == type.GetSign());
}
}
return true;
}
bool IsImplicitTruncation(IType fromType, IType toType)
{
return !(fromType.GetSize() <= toType.GetSize() && fromType.GetSign() == toType.GetSign());
}
/// <code>
/// stloc s(ldloc l)
/// stloc l(binary.op(ldloc s, ldc.i4 1))

Loading…
Cancel
Save