You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

89 lines
3.7 KiB

  1. // Copyright (c) 2019 Daniel Grunwald
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System.Collections.Generic;
  19. using System.Diagnostics;
  20. using System.Linq;
  21. using ICSharpCode.Decompiler.TypeSystem;
  22. namespace ICSharpCode.Decompiler.IL.Transforms
  23. {
  24. public class FixRemainingIncrements : IILTransform
  25. {
  26. void IILTransform.Run(ILFunction function, ILTransformContext context)
  27. {
  28. var callsToFix = new List<Call>();
  29. foreach (var call in function.Descendants.OfType<Call>())
  30. {
  31. if (!UserDefinedCompoundAssign.IsIncrementOrDecrement(call.Method, context.Settings))
  32. continue;
  33. if (call.Arguments.Count != 1)
  34. continue;
  35. if (call.Method.DeclaringType.IsKnownType(KnownTypeCode.Decimal))
  36. {
  37. // For decimal, legacy csc can optimize "d + 1m" to "op_Increment(d)".
  38. // We can handle these calls in ReplaceMethodCallsWithOperators.
  39. continue;
  40. }
  41. callsToFix.Add(call);
  42. }
  43. foreach (var call in callsToFix)
  44. {
  45. // A user-defined increment/decrement that was not handled by TransformAssignment.
  46. // This can happen because the variable-being-incremented was optimized out by Roslyn,
  47. // e.g.
  48. // public void Issue1552Pre(UserType a, UserType b)
  49. // {
  50. // UserType num = a + b;
  51. // Console.WriteLine(++num);
  52. // }
  53. // can end up being compiled to:
  54. // Console.WriteLine(UserType.op_Increment(a + b));
  55. if (call.SlotInfo == StLoc.ValueSlot && call.Parent.SlotInfo == Block.InstructionSlot)
  56. {
  57. var store = (StLoc)call.Parent;
  58. var block = (Block)store.Parent;
  59. context.Step($"Fix {call.Method.Name} call at 0x{call.StartILOffset:x4} using {store.Variable.Name}", call);
  60. // stloc V(call op_Increment(...))
  61. // ->
  62. // stloc V(...)
  63. // compound.assign op_Increment(V)
  64. call.ReplaceWith(call.Arguments[0]);
  65. block.Instructions.Insert(store.ChildIndex + 1,
  66. new UserDefinedCompoundAssign(call.Method, CompoundEvalMode.EvaluatesToNewValue,
  67. new LdLoca(store.Variable), CompoundTargetKind.Address, new LdcI4(1)).WithILRange(call));
  68. }
  69. else
  70. {
  71. context.Step($"Fix {call.Method.Name} call at 0x{call.StartILOffset:x4} using new local", call);
  72. var newVariable = call.Arguments[0].Extract(context);
  73. if (newVariable == null)
  74. {
  75. Debug.Fail("Failed to extract argument of remaining increment/decrement");
  76. continue;
  77. }
  78. newVariable.Type = call.GetParameter(0).Type;
  79. Debug.Assert(call.Arguments[0].MatchLdLoc(newVariable));
  80. call.ReplaceWith(new UserDefinedCompoundAssign(call.Method, CompoundEvalMode.EvaluatesToNewValue,
  81. new LdLoca(newVariable), CompoundTargetKind.Address, new LdcI4(1)).WithILRange(call));
  82. }
  83. }
  84. }
  85. }
  86. }