Browse Source

Make ILRange field private - introduce public API for IL range manipulation.

pull/1440/head
Siegfried Pammer 7 years ago
parent
commit
c1fca21e8a
  1. 8
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 4
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  3. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 66
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  5. 11
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  6. 6
      ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs
  7. 27
      ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
  8. 18
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  9. 19
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  10. 4
      ICSharpCode.Decompiler/IL/ControlFlow/ExitPoints.cs
  11. 16
      ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs
  12. 4
      ICSharpCode.Decompiler/IL/ControlFlow/SwitchDetection.cs
  13. 38
      ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs
  14. 22
      ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs
  15. 23
      ICSharpCode.Decompiler/IL/ILReader.cs
  16. 82
      ICSharpCode.Decompiler/IL/Instructions.cs
  17. 2
      ICSharpCode.Decompiler/IL/Instructions.tt
  18. 2
      ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs
  19. 6
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  20. 6
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  21. 6
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  22. 6
      ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
  23. 2
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  24. 7
      ICSharpCode.Decompiler/IL/Instructions/Comp.cs
  25. 8
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  26. 2
      ICSharpCode.Decompiler/IL/Instructions/Conv.cs
  27. 24
      ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs
  28. 2
      ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs
  29. 4
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  30. 42
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  31. 2
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  32. 2
      ICSharpCode.Decompiler/IL/Instructions/LdLen.cs
  33. 2
      ICSharpCode.Decompiler/IL/Instructions/Leave.cs
  34. 2
      ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs
  35. 8
      ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs
  36. 2
      ICSharpCode.Decompiler/IL/Instructions/NullCoalescingInstruction.cs
  37. 8
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  38. 2
      ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs
  39. 6
      ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs
  40. 18
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  41. 2
      ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs
  42. 2
      ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs
  43. 4
      ICSharpCode.Decompiler/IL/PointerArithmeticOffset.cs
  44. 8
      ICSharpCode.Decompiler/IL/Transforms/CombineExitsTransform.cs
  45. 4
      ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs
  46. 24
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  47. 6
      ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs
  48. 34
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  49. 6
      ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs
  50. 12
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  51. 8
      ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs
  52. 29
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  53. 81
      ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs
  54. 6
      ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs
  55. 4
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs
  56. 22
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
  57. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
  58. 4
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs
  59. 15
      ICSharpCode.Decompiler/IL/Transforms/UserDefinedLogicTransform.cs
  60. 2
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

8
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2917,8 +2917,8 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context) protected internal override TranslatedExpression VisitInvalidBranch(InvalidBranch inst, TranslationContext context)
{ {
string message = "Error"; string message = "Error";
if (inst.ILRange.Start != 0) { if (inst.StartILOffset != 0) {
message += $" near IL_{inst.ILRange.Start:x4}"; message += $" near IL_{inst.StartILOffset:x4}";
} }
if (!string.IsNullOrEmpty(inst.Message)) { if (!string.IsNullOrEmpty(inst.Message)) {
message += ": " + inst.Message; message += ": " + inst.Message;
@ -2929,8 +2929,8 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitInvalidExpression(InvalidExpression inst, TranslationContext context) protected internal override TranslatedExpression VisitInvalidExpression(InvalidExpression inst, TranslationContext context)
{ {
string message = "Error"; string message = "Error";
if (inst.ILRange.Start != 0) { if (inst.StartILOffset != 0) {
message += $" near IL_{inst.ILRange.Start:x4}"; message += $" near IL_{inst.StartILOffset:x4}";
} }
if (!string.IsNullOrEmpty(inst.Message)) { if (!string.IsNullOrEmpty(inst.Message)) {
message += ": " + inst.Message; message += ": " + inst.Message;

4
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -256,7 +256,7 @@ namespace ICSharpCode.Decompiler.CSharp
} }
// Add the IL range associated with this instruction to the current sequence point. // Add the IL range associated with this instruction to the current sequence point.
if (HasUsableILRange(inst) && current.Intervals != null) { if (HasUsableILRange(inst) && current.Intervals != null) {
current.Intervals.Add(inst.ILRange); current.Intervals.AddRange(inst.ILRanges);
var function = inst.Parent.Ancestors.OfType<ILFunction>().FirstOrDefault(); var function = inst.Parent.Ancestors.OfType<ILFunction>().FirstOrDefault();
Debug.Assert(current.Function == null || current.Function == function); Debug.Assert(current.Function == null || current.Function == function);
current.Function = function; current.Function = function;
@ -275,7 +275,7 @@ namespace ICSharpCode.Decompiler.CSharp
internal static bool HasUsableILRange(ILInstruction inst) internal static bool HasUsableILRange(ILInstruction inst)
{ {
if (inst.ILRange.IsEmpty) if (inst.HasILRange)
return false; return false;
return !(inst is BlockContainer || inst is Block); return !(inst is BlockContainer || inst is Block);
} }

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -267,6 +267,7 @@
<Compile Include="CSharp\Transforms\AddXmlDocumentationTransform.cs" /> <Compile Include="CSharp\Transforms\AddXmlDocumentationTransform.cs" />
<Compile Include="DecompileRun.cs" /> <Compile Include="DecompileRun.cs" />
<Compile Include="Disassembler\ILParser.cs" /> <Compile Include="Disassembler\ILParser.cs" />
<Compile Include="IL\ILInstructionExtensions.cs" />
<Compile Include="IL\Transforms\CombineExitsTransform.cs" /> <Compile Include="IL\Transforms\CombineExitsTransform.cs" />
<Compile Include="IL\Transforms\ReduceNestingTransform.cs" /> <Compile Include="IL\Transforms\ReduceNestingTransform.cs" />
<Compile Include="IL\Transforms\LocalFunctionDecompiler.cs" /> <Compile Include="IL\Transforms\LocalFunctionDecompiler.cs" />

66
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -56,26 +56,26 @@ namespace ICSharpCode.Decompiler.IL
foreach (var eh in body.ExceptionRegions) { foreach (var eh in body.ExceptionRegions) {
var tryRange = new Interval(eh.TryOffset, eh.TryOffset + eh.TryLength); var tryRange = new Interval(eh.TryOffset, eh.TryOffset + eh.TryLength);
var handlerBlock = new BlockContainer(); var handlerBlock = new BlockContainer();
handlerBlock.ILRange = new Interval(eh.HandlerOffset, eh.HandlerOffset + eh.HandlerLength); handlerBlock.AddILRange(new Interval(eh.HandlerOffset, eh.HandlerOffset + eh.HandlerLength));
handlerBlock.Blocks.Add(new Block()); handlerBlock.Blocks.Add(new Block());
handlerContainers.Add(handlerBlock.ILRange.Start, handlerBlock); handlerContainers.Add(handlerBlock.StartILOffset, handlerBlock);
if (eh.Kind == ExceptionRegionKind.Fault || eh.Kind == ExceptionRegionKind.Finally) { if (eh.Kind == ExceptionRegionKind.Fault || eh.Kind == ExceptionRegionKind.Finally) {
var tryBlock = new BlockContainer(); var tryBlock = new BlockContainer();
tryBlock.ILRange = tryRange; tryBlock.AddILRange(tryRange);
if (eh.Kind == ExceptionRegionKind.Finally) if (eh.Kind == ExceptionRegionKind.Finally)
tryInstructionList.Add(new TryFinally(tryBlock, handlerBlock) { ILRange = tryRange }); tryInstructionList.Add(new TryFinally(tryBlock, handlerBlock).WithILRange(tryRange));
else else
tryInstructionList.Add(new TryFault(tryBlock, handlerBlock) { ILRange = tryRange }); tryInstructionList.Add(new TryFault(tryBlock, handlerBlock).WithILRange(tryRange));
continue; continue;
} }
// //
var tryCatch = tryCatchList.FirstOrDefault(tc => tc.TryBlock.ILRange == tryRange); var tryCatch = tryCatchList.FirstOrDefault(tc => tc.TryBlock.ILRanges.SingleOrDefault() == tryRange);
if (tryCatch == null) { if (tryCatch == null) {
var tryBlock = new BlockContainer(); var tryBlock = new BlockContainer();
tryBlock.ILRange = tryRange; tryBlock.AddILRange(tryRange);
tryCatch = new TryCatch(tryBlock); tryCatch = new TryCatch(tryBlock);
tryCatch.ILRange = tryRange; tryCatch.AddILRange(tryRange);
tryCatchList.Add(tryCatch); tryCatchList.Add(tryCatch);
tryInstructionList.Add(tryCatch); tryInstructionList.Add(tryCatch);
} }
@ -83,22 +83,22 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction filter; ILInstruction filter;
if (eh.Kind == System.Reflection.Metadata.ExceptionRegionKind.Filter) { if (eh.Kind == System.Reflection.Metadata.ExceptionRegionKind.Filter) {
var filterBlock = new BlockContainer(expectedResultType: StackType.I4); var filterBlock = new BlockContainer(expectedResultType: StackType.I4);
filterBlock.ILRange = new Interval(eh.FilterOffset, eh.HandlerOffset); filterBlock.AddILRange(new Interval(eh.FilterOffset, eh.HandlerOffset));
filterBlock.Blocks.Add(new Block()); filterBlock.Blocks.Add(new Block());
handlerContainers.Add(filterBlock.ILRange.Start, filterBlock); handlerContainers.Add(filterBlock.StartILOffset, filterBlock);
filter = filterBlock; filter = filterBlock;
} else { } else {
filter = new LdcI4(1); filter = new LdcI4(1);
} }
var handler = new TryCatchHandler(filter, handlerBlock, variableByExceptionHandler[eh]); var handler = new TryCatchHandler(filter, handlerBlock, variableByExceptionHandler[eh]);
handler.AddILRange(filter.ILRange); handler.AddILRange(filter);
handler.AddILRange(handlerBlock.ILRange); handler.AddILRange(handlerBlock);
tryCatch.Handlers.Add(handler); tryCatch.Handlers.Add(handler);
tryCatch.AddILRange(handler.ILRange); tryCatch.AddILRange(handler);
} }
if (tryInstructionList.Count > 0) { if (tryInstructionList.Count > 0) {
tryInstructionList = tryInstructionList.OrderBy(tc => tc.TryBlock.ILRange.Start).ThenByDescending(tc => tc.TryBlock.ILRange.End).ToList(); tryInstructionList = tryInstructionList.OrderBy(tc => tc.TryBlock.StartILOffset).ThenByDescending(tc => tc.TryBlock.EndILOffset).ToList();
nextTry = tryInstructionList[0]; nextTry = tryInstructionList[0];
} }
} }
@ -113,7 +113,7 @@ namespace ICSharpCode.Decompiler.IL
public void CreateBlocks(BlockContainer mainContainer, List<ILInstruction> instructions, BitArray incomingBranches, CancellationToken cancellationToken) public void CreateBlocks(BlockContainer mainContainer, List<ILInstruction> instructions, BitArray incomingBranches, CancellationToken cancellationToken)
{ {
CreateContainerStructure(); CreateContainerStructure();
mainContainer.ILRange = new Interval(0, body.GetCodeSize()); mainContainer.SetILRange(new Interval(0, body.GetCodeSize()));
currentContainer = mainContainer; currentContainer = mainContainer;
if (instructions.Count == 0) { if (instructions.Count == 0) {
currentContainer.Blocks.Add(new Block { currentContainer.Blocks.Add(new Block {
@ -126,19 +126,19 @@ namespace ICSharpCode.Decompiler.IL
foreach (var inst in instructions) { foreach (var inst in instructions) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
int start = inst.ILRange.Start; int start = inst.StartILOffset;
if (currentBlock == null || (incomingBranches[start] && !IsStackAdjustment(inst))) { if (currentBlock == null || (incomingBranches[start] && !IsStackAdjustment(inst))) {
// Finish up the previous block // Finish up the previous block
FinalizeCurrentBlock(start, fallthrough: true); FinalizeCurrentBlock(start, fallthrough: true);
// Leave nested containers if necessary // Leave nested containers if necessary
while (start >= currentContainer.ILRange.End) { while (start >= currentContainer.EndILOffset) {
currentContainer = containerStack.Pop(); currentContainer = containerStack.Pop();
currentBlock = currentContainer.Blocks.Last(); currentBlock = currentContainer.Blocks.Last();
// this container is skipped (i.e. the loop will execute again) // this container is skipped (i.e. the loop will execute again)
// set ILRange to the last instruction offset inside the block. // set ILRange to the last instruction offset inside the block.
if (start >= currentContainer.ILRange.End) { if (start >= currentContainer.EndILOffset) {
Debug.Assert(currentBlock.ILRange.IsEmpty); Debug.Assert(currentBlock.HasILRange);
currentBlock.ILRange = new Interval(currentBlock.ILRange.Start, start); currentBlock.AddILRange(new Interval(currentBlock.StartILOffset, start));
} }
} }
// Enter a handler if necessary // Enter a handler if necessary
@ -153,30 +153,30 @@ namespace ICSharpCode.Decompiler.IL
currentBlock = new Block(); currentBlock = new Block();
currentContainer.Blocks.Add(currentBlock); currentContainer.Blocks.Add(currentBlock);
} }
currentBlock.ILRange = new Interval(start, start); currentBlock.SetILRange(new Interval(start, start));
} }
while (nextTry != null && start == nextTry.TryBlock.ILRange.Start) { while (nextTry != null && start == nextTry.TryBlock.StartILOffset) {
currentBlock.Instructions.Add(nextTry); currentBlock.Instructions.Add(nextTry);
containerStack.Push(currentContainer); containerStack.Push(currentContainer);
currentContainer = (BlockContainer)nextTry.TryBlock; currentContainer = (BlockContainer)nextTry.TryBlock;
currentBlock = new Block(); currentBlock = new Block();
currentContainer.Blocks.Add(currentBlock); currentContainer.Blocks.Add(currentBlock);
currentBlock.ILRange = new Interval(start, start); currentBlock.SetILRange(new Interval(start, start));
nextTry = tryInstructionList.ElementAtOrDefault(++currentTryIndex); nextTry = tryInstructionList.ElementAtOrDefault(++currentTryIndex);
} }
currentBlock.Instructions.Add(inst); currentBlock.Instructions.Add(inst);
if (inst.HasFlag(InstructionFlags.EndPointUnreachable)) if (inst.HasFlag(InstructionFlags.EndPointUnreachable))
FinalizeCurrentBlock(inst.ILRange.End, fallthrough: false); FinalizeCurrentBlock(inst.EndILOffset, fallthrough: false);
else if (!CreateExtendedBlocks && inst.HasFlag(InstructionFlags.MayBranch)) else if (!CreateExtendedBlocks && inst.HasFlag(InstructionFlags.MayBranch))
FinalizeCurrentBlock(inst.ILRange.End, fallthrough: true); FinalizeCurrentBlock(inst.EndILOffset, fallthrough: true);
} }
FinalizeCurrentBlock(mainContainer.ILRange.End, fallthrough: false); FinalizeCurrentBlock(mainContainer.EndILOffset, fallthrough: false);
// Finish up all containers // Finish up all containers
while (containerStack.Count > 0) { while (containerStack.Count > 0) {
currentContainer = containerStack.Pop(); currentContainer = containerStack.Pop();
currentBlock = currentContainer.Blocks.Last(); currentBlock = currentContainer.Blocks.Last();
FinalizeCurrentBlock(mainContainer.ILRange.End, fallthrough: false); FinalizeCurrentBlock(mainContainer.EndILOffset, fallthrough: false);
} }
ConnectBranches(mainContainer, cancellationToken); ConnectBranches(mainContainer, cancellationToken);
} }
@ -190,8 +190,8 @@ namespace ICSharpCode.Decompiler.IL
{ {
if (currentBlock == null) if (currentBlock == null)
return; return;
Debug.Assert(currentBlock.ILRange.IsEmpty); Debug.Assert(currentBlock.HasILRange);
currentBlock.ILRange = new Interval(currentBlock.ILRange.Start, currentILOffset); currentBlock.SetILRange(new Interval(currentBlock.StartILOffset, currentILOffset));
if (fallthrough) { if (fallthrough) {
if (currentBlock.Instructions.LastOrDefault() is SwitchInstruction switchInst && switchInst.Sections.Last().Body.MatchNop()) { if (currentBlock.Instructions.LastOrDefault() is SwitchInstruction switchInst && switchInst.Sections.Last().Body.MatchNop()) {
// Instead of putting the default branch after the switch instruction // Instead of putting the default branch after the switch instruction
@ -213,9 +213,7 @@ namespace ICSharpCode.Decompiler.IL
branch.TargetBlock = FindBranchTarget(branch.TargetILOffset); branch.TargetBlock = FindBranchTarget(branch.TargetILOffset);
if (branch.TargetBlock == null) { if (branch.TargetBlock == null) {
branch.ReplaceWith(new InvalidBranch("Could not find block for branch target " branch.ReplaceWith(new InvalidBranch("Could not find block for branch target "
+ Disassembler.DisassemblerHelpers.OffsetToString(branch.TargetILOffset)) { + Disassembler.DisassemblerHelpers.OffsetToString(branch.TargetILOffset)).WithILRange(branch));
ILRange = branch.ILRange
});
} }
break; break;
case Leave leave: case Leave leave:
@ -224,7 +222,7 @@ namespace ICSharpCode.Decompiler.IL
if (leave.TargetContainer == null) { if (leave.TargetContainer == null) {
// assign the finally/filter container // assign the finally/filter container
leave.TargetContainer = containerStack.Peek(); leave.TargetContainer = containerStack.Peek();
leave.Value = ILReader.Cast(leave.Value, leave.TargetContainer.ExpectedResultType, null, leave.ILRange.Start); leave.Value = ILReader.Cast(leave.Value, leave.TargetContainer.ExpectedResultType, null, leave.StartILOffset);
} }
break; break;
case BlockContainer container: case BlockContainer container:
@ -249,7 +247,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
foreach (var container in containerStack) { foreach (var container in containerStack) {
foreach (var block in container.Blocks) { foreach (var block in container.Blocks) {
if (block.ILRange.Start == targetILOffset) if (block.StartILOffset == targetILOffset)
return block; return block;
} }
} }

11
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -504,9 +504,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
moveNextFunction.ReleaseRef(); moveNextFunction.ReleaseRef();
foreach (var branch in function.Descendants.OfType<Branch>()) { foreach (var branch in function.Descendants.OfType<Branch>()) {
if (branch.TargetBlock == setResultAndExitBlock) { if (branch.TargetBlock == setResultAndExitBlock) {
branch.ReplaceWith(new Leave((BlockContainer)function.Body, resultVar == null ? null : new LdLoc(resultVar)) { branch.ReplaceWith(new Leave((BlockContainer)function.Body, resultVar == null ? null : new LdLoc(resultVar)).WithILRange(branch));
ILRange = branch.ILRange
});
} }
} }
foreach (var leave in function.Descendants.OfType<Leave>()) { foreach (var leave in function.Descendants.OfType<Leave>()) {
@ -526,9 +524,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
foreach (var leave in function.Descendants.OfType<Leave>()) { foreach (var leave in function.Descendants.OfType<Leave>()) {
if (moveNextLeaves.Contains(leave)) { if (moveNextLeaves.Contains(leave)) {
leave.ReplaceWith(new InvalidBranch { leave.ReplaceWith(new InvalidBranch {
Message = "leave MoveNext - await not detected correctly", Message = "leave MoveNext - await not detected correctly"
ILRange = leave.ILRange }.WithILRange(leave));
});
} }
} }
// Delete dead loads of the state cache variable: // Delete dead loads of the state cache variable:
@ -951,7 +948,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
// if there's any remaining loads (there shouldn't be), replace them with the constant 1 // if there's any remaining loads (there shouldn't be), replace them with the constant 1
foreach (LdLoc load in doFinallyBodies.LoadInstructions.ToArray()) { foreach (LdLoc load in doFinallyBodies.LoadInstructions.ToArray()) {
load.ReplaceWith(new LdcI4(1) { ILRange = load.ILRange }); load.ReplaceWith(new LdcI4(1).WithILRange(load));
} }
context.StepEndGroup(keepIfEmpty: true); context.StepEndGroup(keepIfEmpty: true);
} }

6
ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs

@ -268,7 +268,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
var outer = BlockContainer.FindClosestContainer(container.Parent); var outer = BlockContainer.FindClosestContainer(container.Parent);
if (outer != null) changedContainers.Add(outer); if (outer != null) changedContainers.Add(outer);
finallyContainer.Blocks.Add(entryPointOfFinally); finallyContainer.Blocks.Add(entryPointOfFinally);
finallyContainer.ILRange = entryPointOfFinally.ILRange; finallyContainer.AddILRange(entryPointOfFinally);
exitOfFinally.Instructions.RemoveRange(tempStore.ChildIndex, 3); exitOfFinally.Instructions.RemoveRange(tempStore.ChildIndex, 3);
exitOfFinally.Instructions.Add(new Leave(finallyContainer)); exitOfFinally.Instructions.Add(new Leave(finallyContainer));
foreach (var branchToFinally in container.Descendants.OfType<Branch>()) { foreach (var branchToFinally in container.Descendants.OfType<Branch>()) {
@ -278,9 +278,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
foreach (var newBlock in additionalBlocksInFinally) { foreach (var newBlock in additionalBlocksInFinally) {
newBlock.Remove(); newBlock.Remove();
finallyContainer.Blocks.Add(newBlock); finallyContainer.Blocks.Add(newBlock);
finallyContainer.AddILRange(newBlock.ILRange); finallyContainer.AddILRange(newBlock);
} }
tryCatch.ReplaceWith(new TryFinally(tryCatch.TryBlock, finallyContainer) {ILRange = tryCatch.TryBlock.ILRange}); tryCatch.ReplaceWith(new TryFinally(tryCatch.TryBlock, finallyContainer).WithILRange(tryCatch.TryBlock));
} }
// clean up all modified containers // clean up all modified containers

27
ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs

@ -109,7 +109,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (DetectExitPoints.CompatibleExitInstruction(ifInst.TrueInst, exitInst)) { if (DetectExitPoints.CompatibleExitInstruction(ifInst.TrueInst, exitInst)) {
// if (...) exitInst; exitInst; // if (...) exitInst; exitInst;
context.Step("Use empty block as then-branch", ifInst.TrueInst); context.Step("Use empty block as then-branch", ifInst.TrueInst);
ifInst.TrueInst = new Nop() { ILRange = ifInst.TrueInst.ILRange }; ifInst.TrueInst = new Nop().WithILRange(ifInst.TrueInst);
// false, because we didn't inline a real block // false, because we didn't inline a real block
// this will cause HandleIfInstruction() to attempt to inline the exitInst. // this will cause HandleIfInstruction() to attempt to inline the exitInst.
return false; return false;
@ -231,7 +231,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// -> if (...) { ... } else { ... } blockExit; // -> if (...) { ... } else { ... } blockExit;
context.Step("Remove redundant 'goto blockExit;' in then-branch", ifInst); context.Step("Remove redundant 'goto blockExit;' in then-branch", ifInst);
if (!(ifInst.TrueInst is Block trueBlock) || trueBlock.Instructions.Count == 1) if (!(ifInst.TrueInst is Block trueBlock) || trueBlock.Instructions.Count == 1)
ifInst.TrueInst = new Nop { ILRange = ifInst.TrueInst.ILRange }; ifInst.TrueInst = new Nop().WithILRange(ifInst.TrueInst);
else else
trueBlock.Instructions.RemoveAt(trueBlock.Instructions.Count - 1); trueBlock.Instructions.RemoveAt(trueBlock.Instructions.Count - 1);
@ -396,7 +396,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.Step("Swap empty then-branch with else-branch", ifInst); context.Step("Swap empty then-branch with else-branch", ifInst);
var oldTrue = ifInst.TrueInst; var oldTrue = ifInst.TrueInst;
ifInst.TrueInst = ifInst.FalseInst; ifInst.TrueInst = ifInst.FalseInst;
ifInst.FalseInst = new Nop { ILRange = oldTrue.ILRange }; ifInst.FalseInst = new Nop().WithILRange(oldTrue);
ifInst.Condition = Comp.LogicNot(ifInst.Condition); ifInst.Condition = Comp.LogicNot(ifInst.Condition);
} }
@ -425,7 +425,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
/// </summary> /// </summary>
private void OrderIfBlocks(IfInstruction ifInst) private void OrderIfBlocks(IfInstruction ifInst)
{ {
if (IsEmpty(ifInst.FalseInst) || GetILRange(ifInst.TrueInst).Start <= GetILRange(ifInst.FalseInst).Start) if (IsEmpty(ifInst.FalseInst) || GetStartILOffset(ifInst.TrueInst, out _) <= GetStartILOffset(ifInst.FalseInst, out _))
return; return;
context.Step("Swap then-branch with else-branch to match IL order", ifInst); context.Step("Swap then-branch with else-branch to match IL order", ifInst);
@ -437,14 +437,17 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
ifInst.Condition = Comp.LogicNot(ifInst.Condition); ifInst.Condition = Comp.LogicNot(ifInst.Condition);
} }
public static Interval GetILRange(ILInstruction inst) public static int GetStartILOffset(ILInstruction inst, out bool isEmpty)
{ {
// some compilers merge the leave instructions for different arguments using stack variables // some compilers merge the leave instructions for different arguments using stack variables
// these get split and inlined, but the ILRange of the value remains a better indicator of the actual location // these get split and inlined, but the ILRange of the value remains a better indicator of the actual location
if (inst is Leave leave && !leave.Value.MatchNop()) if (inst is Leave leave && !leave.Value.MatchNop()) {
return leave.Value.ILRange; isEmpty = leave.Value.HasILRange;
return leave.Value.StartILOffset;
}
return inst.ILRange; isEmpty = inst.HasILRange;
return inst.StartILOffset;
} }
/// <summary> /// <summary>
@ -524,13 +527,13 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// prefer arranging stuff in IL order // prefer arranging stuff in IL order
if (exit1.MatchBranch(out var block1) && exit2.MatchBranch(out var block2)) if (exit1.MatchBranch(out var block1) && exit2.MatchBranch(out var block2))
return block1.ILRange.Start.CompareTo(block2.ILRange.Start); return block1.StartILOffset.CompareTo(block2.StartILOffset);
// use the IL offsets of the arguments of leave instructions instead of the leaves themselves if possible // use the IL offsets of the arguments of leave instructions instead of the leaves themselves if possible
if (exit1.MatchLeave(out var _, out var arg1) && exit2.MatchLeave(out var _, out var arg2)) if (exit1.MatchLeave(out var _, out var arg1) && exit2.MatchLeave(out var _, out var arg2))
return arg1.ILRange.Start.CompareTo(arg2.ILRange.Start); return arg1.StartILOffset.CompareTo(arg2.StartILOffset);
return exit1.ILRange.Start.CompareTo(exit2.ILRange.Start); return exit1.StartILOffset.CompareTo(exit2.StartILOffset);
} }
/// <summary> /// <summary>
@ -630,7 +633,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
for (int i = startIndex; i < endIndex; i++) { for (int i = startIndex; i < endIndex; i++) {
var inst = block.Instructions[i]; var inst = block.Instructions[i];
extractedBlock.Instructions.Add(inst); extractedBlock.Instructions.Add(inst);
extractedBlock.AddILRange(inst.ILRange); extractedBlock.AddILRange(inst);
} }
block.Instructions.RemoveRange(startIndex, endIndex - startIndex); block.Instructions.RemoveRange(startIndex, endIndex - startIndex);

18
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -60,7 +60,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// Move ILRanges of special nop instructions to the previous non-nop instruction. // Move ILRanges of special nop instructions to the previous non-nop instruction.
for (int i = block.Instructions.Count - 1; i > 0; i--) { for (int i = block.Instructions.Count - 1; i > 0; i--) {
if (block.Instructions[i] is Nop nop && nop.Kind == NopKind.Pop) { if (block.Instructions[i] is Nop nop && nop.Kind == NopKind.Pop) {
block.Instructions[i - 1].AddILRange(nop.ILRange); block.Instructions[i - 1].AddILRange(nop);
} }
} }
@ -82,8 +82,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (value.MatchLdLoc(out ILVariable v) if (value.MatchLdLoc(out ILVariable v)
&& v.IsSingleDefinition && v.LoadCount == 1 && block.Instructions[0].MatchStLoc(v, out ILInstruction inst)) { && v.IsSingleDefinition && v.LoadCount == 1 && block.Instructions[0].MatchStLoc(v, out ILInstruction inst)) {
context.Step("Inline variable in return block", block); context.Step("Inline variable in return block", block);
inst.AddILRange(ret.Value.ILRange); inst.AddILRange(ret.Value);
inst.AddILRange(block.Instructions[0].ILRange); inst.AddILRange(block.Instructions[0]);
ret.Value = inst; ret.Value = inst;
block.Instructions.RemoveAt(0); block.Instructions.RemoveAt(0);
} }
@ -106,7 +106,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.Step("Simplify branch to branch", branch); context.Step("Simplify branch to branch", branch);
var nextBranch = (Branch)targetBlock.Instructions[0]; var nextBranch = (Branch)targetBlock.Instructions[0];
branch.TargetBlock = nextBranch.TargetBlock; branch.TargetBlock = nextBranch.TargetBlock;
branch.AddILRange(nextBranch.ILRange); branch.AddILRange(nextBranch);
if (targetBlock.IncomingEdgeCount == 0) if (targetBlock.IncomingEdgeCount == 0)
targetBlock.Instructions.Clear(); // mark the block for deletion targetBlock.Instructions.Clear(); // mark the block for deletion
targetBlock = branch.TargetBlock; targetBlock = branch.TargetBlock;
@ -133,8 +133,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
context.Step("Replace branch to leave with leave", branch); context.Step("Replace branch to leave with leave", branch);
// Replace branches to 'leave' instruction with the leave instruction // Replace branches to 'leave' instruction with the leave instruction
var leave2 = leave.Clone(); var leave2 = leave.Clone();
if (!branch.ILRange.IsEmpty) // use the ILRange of the branch if possible if (!branch.HasILRange) // use the ILRange of the branch if possible
leave2.ILRange = branch.ILRange; leave2.AddILRange(branch);
branch.ReplaceWith(leave2); branch.ReplaceWith(leave2);
} }
if (targetBlock.IncomingEdgeCount == 0) if (targetBlock.IncomingEdgeCount == 0)
@ -186,13 +186,13 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return false; // don't inline block into itself return false; // don't inline block into itself
context.Step("CombineBlockWithNextBlock", br); context.Step("CombineBlockWithNextBlock", br);
var targetBlock = br.TargetBlock; var targetBlock = br.TargetBlock;
if (targetBlock.ILRange.Start < block.ILRange.Start && IsDeadTrueStore(block)) { if (targetBlock.StartILOffset < block.StartILOffset && IsDeadTrueStore(block)) {
// The C# compiler generates a dead store for the condition of while (true) loops. // The C# compiler generates a dead store for the condition of while (true) loops.
block.Instructions.RemoveRange(block.Instructions.Count - 3, 2); block.Instructions.RemoveRange(block.Instructions.Count - 3, 2);
} }
if (block.ILRange.IsEmpty) if (block.HasILRange)
block.ILRange = targetBlock.ILRange; block.AddILRange(targetBlock);
block.Instructions.Remove(br); block.Instructions.Remove(br);
block.Instructions.AddRange(targetBlock.Instructions); block.Instructions.AddRange(targetBlock.Instructions);

19
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -102,7 +102,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
for (int k = j + 1; k < block.Instructions.Count; k++) { for (int k = j + 1; k < block.Instructions.Count; k++) {
newBlock.Instructions.Add(block.Instructions[k]); newBlock.Instructions.Add(block.Instructions[k]);
} }
newBlock.ILRange = newBlock.Instructions[0].ILRange; newBlock.AddILRange(newBlock.Instructions[0]);
block.Instructions.RemoveRange(j + 1, newBlock.Instructions.Count); block.Instructions.RemoveRange(j + 1, newBlock.Instructions.Count);
block.Instructions.Add(new Branch(newBlock)); block.Instructions.Add(new Branch(newBlock));
container.Blocks.Insert(i + 1, newBlock); container.Blocks.Insert(i + 1, newBlock);
@ -147,9 +147,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (p.StackType != StackType.Ref) { if (p.StackType != StackType.Ref) {
arrayToPointer = new Conv(arrayToPointer, p.StackType.ToPrimitiveType(), false, Sign.None); arrayToPointer = new Conv(arrayToPointer, p.StackType.ToPrimitiveType(), false, Sign.None);
} }
block.Instructions[block.Instructions.Count - 2] = new StLoc(p, arrayToPointer) { block.Instructions[block.Instructions.Count - 2] = new StLoc(p, arrayToPointer)
ILRange = block.Instructions[block.Instructions.Count - 2].ILRange .WithILRange(block.Instructions[block.Instructions.Count - 2]);
};
((Branch)block.Instructions.Last()).TargetBlock = targetBlock; ((Branch)block.Instructions.Last()).TargetBlock = targetBlock;
modified = true; modified = true;
} }
@ -356,7 +355,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
} }
var pinnedRegion = new PinnedRegion(stLoc.Variable, stLoc.Value, body) { ILRange = stLoc.ILRange }; var pinnedRegion = new PinnedRegion(stLoc.Variable, stLoc.Value, body).WithILRange(stLoc);
stLoc.ReplaceWith(pinnedRegion); stLoc.ReplaceWith(pinnedRegion);
block.Instructions.RemoveAt(block.Instructions.Count - 1); // remove branch into body block.Instructions.RemoveAt(block.Instructions.Count - 1); // remove branch into body
ProcessPinnedRegion(pinnedRegion); ProcessPinnedRegion(pinnedRegion);
@ -414,7 +413,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
foreach (var block in body.Blocks) foreach (var block in body.Blocks)
DetectPinnedRegion(block); DetectPinnedRegion(block);
body.Blocks.RemoveAll(b => b.Instructions.Count == 0); // remove dummy blocks body.Blocks.RemoveAll(b => b.Instructions.Count == 0); // remove dummy blocks
body.ILRange = body.EntryPoint.ILRange; body.SetILRange(body.EntryPoint);
} }
private void MoveArrayToPointerToPinnedRegionInit(PinnedRegion pinnedRegion) private void MoveArrayToPointerToPinnedRegionInit(PinnedRegion pinnedRegion)
@ -447,8 +446,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
newVar.HasGeneratedName = oldVar.HasGeneratedName; newVar.HasGeneratedName = oldVar.HasGeneratedName;
oldVar.Function.Variables.Add(newVar); oldVar.Function.Variables.Add(newVar);
pinnedRegion.Variable = newVar; pinnedRegion.Variable = newVar;
pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init) { ILRange = arrayToPointer.ILRange }; pinnedRegion.Init = new ArrayToPointer(pinnedRegion.Init).WithILRange(arrayToPointer);
conv.ReplaceWith(new LdLoc(newVar) { ILRange = conv.ILRange }); conv.ReplaceWith(new LdLoc(newVar).WithILRange(conv));
} }
void ReplacePinnedVar(ILVariable oldVar, ILVariable newVar, ILInstruction inst) void ReplacePinnedVar(ILVariable oldVar, ILVariable newVar, ILInstruction inst)
@ -457,8 +456,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (inst is Conv conv && conv.Kind == ConversionKind.StopGCTracking && conv.Argument.MatchLdLoc(oldVar) && conv.ResultType == newVar.StackType) { if (inst is Conv conv && conv.Kind == ConversionKind.StopGCTracking && conv.Argument.MatchLdLoc(oldVar) && conv.ResultType == newVar.StackType) {
// conv ref->i (ldloc oldVar) // conv ref->i (ldloc oldVar)
// => ldloc newVar // => ldloc newVar
conv.AddILRange(conv.Argument.ILRange); conv.AddILRange(conv.Argument);
conv.ReplaceWith(new LdLoc(newVar) { ILRange = conv.ILRange }); conv.ReplaceWith(new LdLoc(newVar).WithILRange(conv));
return; return;
} }
if (inst is IInstructionWithVariableOperand iwvo && iwvo.Variable == oldVar) { if (inst is IInstructionWithVariableOperand iwvo && iwvo.Variable == oldVar) {

4
ICSharpCode.Decompiler/IL/ControlFlow/ExitPoints.cs

@ -166,7 +166,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
currentExit = ChooseExit(potentialExits); currentExit = ChooseExit(potentialExits);
foreach (var exit in potentialExits) { foreach (var exit in potentialExits) {
if (CompatibleExitInstruction(currentExit, exit)) { if (CompatibleExitInstruction(currentExit, exit)) {
exit.ReplaceWith(new Leave(currentContainer) { ILRange = exit.ILRange }); exit.ReplaceWith(new Leave(currentContainer).WithILRange(exit));
} }
} }
Debug.Assert(!currentExit.MatchLeave(currentContainer)); Debug.Assert(!currentExit.MatchLeave(currentContainer));
@ -222,7 +222,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (currentExit == ExitNotYetDetermined && CanIntroduceAsExit(inst)) { if (currentExit == ExitNotYetDetermined && CanIntroduceAsExit(inst)) {
potentialExits.Add(inst); potentialExits.Add(inst);
} else if (CompatibleExitInstruction(inst, currentExit)) { } else if (CompatibleExitInstruction(inst, currentExit)) {
inst.ReplaceWith(new Leave(currentContainer) { ILRange = inst.ILRange }); inst.ReplaceWith(new Leave(currentContainer).WithILRange(inst));
} }
} }

16
ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs

@ -425,7 +425,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return; return;
Block block = (Block)node.UserData; Block block = (Block)node.UserData;
if (block.ILRange.Start > exitPointILOffset if (block.StartILOffset > exitPointILOffset
&& !HasReachableExit(node) && !HasReachableExit(node)
&& ((Block)node.UserData).Parent == currentBlockContainer) && ((Block)node.UserData).Parent == currentBlockContainer)
{ {
@ -440,7 +440,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// that prevents us from finding a nice exit for the inner loops, causing // that prevents us from finding a nice exit for the inner loops, causing
// unnecessary gotos. // unnecessary gotos.
exitPoint = node; exitPoint = node;
exitPointILOffset = block.ILRange.Start; exitPointILOffset = block.StartILOffset;
return; // don't visit children, they are likely to have even later IL offsets and we'd end up return; // don't visit children, they are likely to have even later IL offsets and we'd end up
// moving almost all of the code into the loop. // moving almost all of the code into the loop.
} }
@ -641,12 +641,12 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// Move contents of oldEntryPoint to newEntryPoint // Move contents of oldEntryPoint to newEntryPoint
// (we can't move the block itself because it might be the target of branch instructions outside the loop) // (we can't move the block itself because it might be the target of branch instructions outside the loop)
newEntryPoint.Instructions.ReplaceList(oldEntryPoint.Instructions); newEntryPoint.Instructions.ReplaceList(oldEntryPoint.Instructions);
newEntryPoint.ILRange = oldEntryPoint.ILRange; newEntryPoint.AddILRange(oldEntryPoint);
oldEntryPoint.Instructions.ReplaceList(new[] { loopContainer }); oldEntryPoint.Instructions.ReplaceList(new[] { loopContainer });
if (exitTargetBlock != null) if (exitTargetBlock != null)
oldEntryPoint.Instructions.Add(new Branch(exitTargetBlock)); oldEntryPoint.Instructions.Add(new Branch(exitTargetBlock));
loopContainer.ILRange = newEntryPoint.ILRange; loopContainer.AddILRange(newEntryPoint);
MoveBlocksIntoContainer(loop, loopContainer); MoveBlocksIntoContainer(loop, loopContainer);
// Rewrite branches within the loop from oldEntryPoint to newEntryPoint: // Rewrite branches within the loop from oldEntryPoint to newEntryPoint:
@ -654,7 +654,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (branch.TargetBlock == oldEntryPoint) { if (branch.TargetBlock == oldEntryPoint) {
branch.TargetBlock = newEntryPoint; branch.TargetBlock = newEntryPoint;
} else if (branch.TargetBlock == exitTargetBlock) { } else if (branch.TargetBlock == exitTargetBlock) {
branch.ReplaceWith(new Leave(loopContainer) { ILRange = branch.ILRange }); branch.ReplaceWith(new Leave(loopContainer).WithILRange(branch));
} }
} }
} }
@ -723,7 +723,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
BlockContainer switchContainer = new BlockContainer(ContainerKind.Switch); BlockContainer switchContainer = new BlockContainer(ContainerKind.Switch);
Block newEntryPoint = new Block(); Block newEntryPoint = new Block();
newEntryPoint.ILRange = switchInst.ILRange; newEntryPoint.AddILRange(switchInst);
switchContainer.Blocks.Add(newEntryPoint); switchContainer.Blocks.Add(newEntryPoint);
newEntryPoint.Instructions.Add(switchInst); newEntryPoint.Instructions.Add(switchInst);
block.Instructions[block.Instructions.Count - 1] = switchContainer; block.Instructions[block.Instructions.Count - 1] = switchContainer;
@ -733,13 +733,13 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
block.Instructions.Add(new Branch(exitTargetBlock)); block.Instructions.Add(new Branch(exitTargetBlock));
} }
switchContainer.ILRange = newEntryPoint.ILRange; switchContainer.AddILRange(newEntryPoint);
MoveBlocksIntoContainer(nodesInSwitch, switchContainer); MoveBlocksIntoContainer(nodesInSwitch, switchContainer);
// Rewrite branches within the loop from oldEntryPoint to newEntryPoint: // Rewrite branches within the loop from oldEntryPoint to newEntryPoint:
foreach (var branch in switchContainer.Descendants.OfType<Branch>()) { foreach (var branch in switchContainer.Descendants.OfType<Branch>()) {
if (branch.TargetBlock == exitTargetBlock) { if (branch.TargetBlock == exitTargetBlock) {
branch.ReplaceWith(new Leave(switchContainer) { ILRange = branch.ILRange }); branch.ReplaceWith(new Leave(switchContainer).WithILRange(branch));
} }
} }

4
ICSharpCode.Decompiler/IL/ControlFlow/SwitchDetection.cs

@ -180,7 +180,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// Remove branch/leave after if; it's getting moved into a section. // Remove branch/leave after if; it's getting moved into a section.
block.Instructions.RemoveAt(block.Instructions.Count - 1); block.Instructions.RemoveAt(block.Instructions.Count - 1);
} }
sw.ILRange = block.Instructions[block.Instructions.Count - 1].ILRange; sw.AddILRange(block.Instructions[block.Instructions.Count - 1]);
block.Instructions[block.Instructions.Count - 1] = sw; block.Instructions[block.Instructions.Count - 1] = sw;
// mark all inner blocks that were converted to the switch statement for deletion // mark all inner blocks that were converted to the switch statement for deletion
@ -317,7 +317,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// The switch has a single break target and there is one more hint // The switch has a single break target and there is one more hint
// The break target cannot be inlined, and should have the highest IL offset of everything targetted by the switch // The break target cannot be inlined, and should have the highest IL offset of everything targetted by the switch
return breakBlock.ILRange.Start >= analysis.Sections.Select(s => s.Value.MatchBranch(out var b) ? b.ILRange.Start : -1).Max(); return breakBlock.StartILOffset >= analysis.Sections.Select(s => s.Value.MatchBranch(out var b) ? b.StartILOffset : -1).Max();
} }
/// <summary> /// <summary>

38
ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs

@ -649,10 +649,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
private BlockContainer ConvertBody(BlockContainer oldBody, StateRangeAnalysis rangeAnalysis) private BlockContainer ConvertBody(BlockContainer oldBody, StateRangeAnalysis rangeAnalysis)
{ {
var blockStateMap = rangeAnalysis.GetBlockStateSetMapping(oldBody); var blockStateMap = rangeAnalysis.GetBlockStateSetMapping(oldBody);
BlockContainer newBody = new BlockContainer() { ILRange = oldBody.ILRange }; BlockContainer newBody = new BlockContainer().WithILRange(oldBody);
// create all new blocks so that they can be referenced by gotos // create all new blocks so that they can be referenced by gotos
for (int blockIndex = 0; blockIndex < oldBody.Blocks.Count; blockIndex++) { for (int blockIndex = 0; blockIndex < oldBody.Blocks.Count; blockIndex++) {
newBody.Blocks.Add(new Block { ILRange = oldBody.Blocks[blockIndex].ILRange }); newBody.Blocks.Add(new Block().WithILRange(oldBody.Blocks[blockIndex]));
} }
// convert contents of blocks // convert contents of blocks
@ -670,14 +670,12 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// We keep the state-changing instruction around (as first instruction of the new block) // We keep the state-changing instruction around (as first instruction of the new block)
// for reconstructing the try-finallys. // for reconstructing the try-finallys.
} else { } else {
newBlock.Instructions.Add(new InvalidExpression("Assigned non-constant to iterator.state field") { newBlock.Instructions.Add(new InvalidExpression("Assigned non-constant to iterator.state field").WithILRange(oldInst));
ILRange = oldInst.ILRange
});
continue; // don't copy over this instruction, but continue with the basic block continue; // don't copy over this instruction, but continue with the basic block
} }
} else if (field.MemberDefinition.Equals(currentField)) { } else if (field.MemberDefinition.Equals(currentField)) {
// create yield return // create yield return
newBlock.Instructions.Add(new YieldReturn(value) { ILRange = oldInst.ILRange }); newBlock.Instructions.Add(new YieldReturn(value).WithILRange(oldInst));
ConvertBranchAfterYieldReturn(newBlock, oldBlock, oldInst.ChildIndex + 1); ConvertBranchAfterYieldReturn(newBlock, oldBlock, oldInst.ChildIndex + 1);
break; // we're done with this basic block break; // we're done with this basic block
} }
@ -696,7 +694,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
// copy over the instruction to the new block // copy over the instruction to the new block
newBlock.Instructions.Add(oldInst); newBlock.Instructions.Add(oldInst);
newBlock.AddILRange(oldInst.ILRange); newBlock.AddILRange(oldInst);
UpdateBranchTargets(oldInst); UpdateBranchTargets(oldInst);
} }
} }
@ -781,7 +779,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{ {
if (newBlock.Instructions.Count > 0) { if (newBlock.Instructions.Count > 0) {
var newBlock2 = new Block(); var newBlock2 = new Block();
newBlock2.ILRange = new Interval(oldInst.ILRange.Start, oldInst.ILRange.Start); newBlock2.AddILRange(new Interval(oldInst.StartILOffset, oldInst.StartILOffset));
newBody.Blocks.Add(newBlock2); newBody.Blocks.Add(newBlock2);
newBlock.Instructions.Add(new Branch(newBlock2)); newBlock.Instructions.Add(new Branch(newBlock2));
newBlock = newBlock2; newBlock = newBlock2;
@ -821,9 +819,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
if (value.MatchLdcI4(0)) { if (value.MatchLdcI4(0)) {
// yield break // yield break
leave.ReplaceWith(new Leave(newBody) { ILRange = leave.ILRange }); leave.ReplaceWith(new Leave(newBody).WithILRange(leave));
} else { } else {
leave.ReplaceWith(new InvalidBranch("Unexpected return in MoveNext()") { ILRange = leave.ILRange }); leave.ReplaceWith(new InvalidBranch("Unexpected return in MoveNext()").WithILRange(leave));
} }
} else { } else {
if (leave.TargetContainer == oldBody) { if (leave.TargetContainer == oldBody) {
@ -861,25 +859,25 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
if (v.StackType == StackType.Ref) { if (v.StackType == StackType.Ref) {
Debug.Assert(v.Kind == VariableKind.Parameter && v.Index < 0); // this pointer Debug.Assert(v.Kind == VariableKind.Parameter && v.Index < 0); // this pointer
inst.ReplaceWith(new LdLoc(v) { ILRange = inst.ILRange }); inst.ReplaceWith(new LdLoc(v).WithILRange(inst));
} else { } else {
inst.ReplaceWith(new LdLoca(v) { ILRange = inst.ILRange }); inst.ReplaceWith(new LdLoca(v).WithILRange(inst));
} }
} else if (!isCompiledWithMono && inst.MatchLdThis()) { } else if (!isCompiledWithMono && inst.MatchLdThis()) {
inst.ReplaceWith(new InvalidExpression("stateMachine") { ExpectedResultType = inst.ResultType, ILRange = inst.ILRange }); inst.ReplaceWith(new InvalidExpression("stateMachine") { ExpectedResultType = inst.ResultType }.WithILRange(inst));
} else { } else {
foreach (var child in inst.Children) { foreach (var child in inst.Children) {
TranslateFieldsToLocalAccess(function, child, fieldToVariableMap, isCompiledWithMono); TranslateFieldsToLocalAccess(function, child, fieldToVariableMap, isCompiledWithMono);
} }
if (inst is LdObj ldobj && ldobj.Target is LdLoca ldloca && ldloca.Variable.StateMachineField != null) { if (inst is LdObj ldobj && ldobj.Target is LdLoca ldloca && ldloca.Variable.StateMachineField != null) {
LdLoc ldloc = new LdLoc(ldloca.Variable); LdLoc ldloc = new LdLoc(ldloca.Variable);
ldloc.AddILRange(ldobj.ILRange); ldloc.AddILRange(ldobj);
ldloc.AddILRange(ldloca.ILRange); ldloc.AddILRange(ldloca);
inst.ReplaceWith(ldloc); inst.ReplaceWith(ldloc);
} else if (inst is StObj stobj && stobj.Target is LdLoca ldloca2 && ldloca2.Variable.StateMachineField != null) { } else if (inst is StObj stobj && stobj.Target is LdLoca ldloca2 && ldloca2.Variable.StateMachineField != null) {
StLoc stloc = new StLoc(ldloca2.Variable, stobj.Value); StLoc stloc = new StLoc(ldloca2.Variable, stobj.Value);
stloc.AddILRange(stobj.ILRange); stloc.AddILRange(stobj);
stloc.AddILRange(ldloca2.ILRange); stloc.AddILRange(ldloca2);
inst.ReplaceWith(stloc); inst.ReplaceWith(stloc);
} }
} }
@ -988,11 +986,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
finallyMethodToStateRange.Remove(finallyMethod); finallyMethodToStateRange.Remove(finallyMethod);
var tryBlock = new Block(); var tryBlock = new Block();
tryBlock.ILRange = block.ILRange; tryBlock.AddILRange(block);
tryBlock.Instructions.AddRange(block.Instructions); tryBlock.Instructions.AddRange(block.Instructions);
var tryBlockContainer = new BlockContainer(); var tryBlockContainer = new BlockContainer();
tryBlockContainer.Blocks.Add(tryBlock); tryBlockContainer.Blocks.Add(tryBlock);
tryBlockContainer.ILRange = tryBlock.ILRange; tryBlockContainer.AddILRange(tryBlock);
stateToContainer.Add(state, tryBlockContainer); stateToContainer.Add(state, tryBlockContainer);
ILInstruction finallyBlock; ILInstruction finallyBlock;
@ -1006,7 +1004,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
block.Instructions.Clear(); block.Instructions.Clear();
block.Instructions.Add(new TryFinally(tryBlockContainer, finallyBlock) { ILRange = tryBlockContainer.ILRange}); block.Instructions.Add(new TryFinally(tryBlockContainer, finallyBlock).WithILRange(tryBlockContainer));
} }
IMethod FindFinallyMethod(int state) IMethod FindFinallyMethod(int state)

22
ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Text;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL
{
internal static class ILInstructionExtensions
{
public static T WithILRange<T>(this T target, ILInstruction sourceInstruction) where T : ILInstruction
{
target.AddILRange(sourceInstruction);
return target;
}
public static T WithILRange<T>(this T target, Interval range) where T : ILInstruction
{
target.AddILRange(range);
return target;
}
}
}

23
ICSharpCode.Decompiler/IL/ILReader.cs

@ -389,8 +389,8 @@ namespace ICSharpCode.Decompiler.IL
Warn("Unknown result type (might be due to invalid IL or missing references)"); Warn("Unknown result type (might be due to invalid IL or missing references)");
decodedInstruction.CheckInvariant(ILPhase.InILReader); decodedInstruction.CheckInvariant(ILPhase.InILReader);
int end = reader.Offset; int end = reader.Offset;
decodedInstruction.ILRange = new Interval(start, end); decodedInstruction.AddILRange(new Interval(start, end));
UnpackPush(decodedInstruction).ILRange = decodedInstruction.ILRange; UnpackPush(decodedInstruction).AddILRange(decodedInstruction);
instructionBuilder.Add(decodedInstruction); instructionBuilder.Add(decodedInstruction);
if (decodedInstruction.HasDirectFlag(InstructionFlags.EndPointUnreachable)) { if (decodedInstruction.HasDirectFlag(InstructionFlags.EndPointUnreachable)) {
if (!stackByOffset.TryGetValue(end, out currentStack)) { if (!stackByOffset.TryGetValue(end, out currentStack)) {
@ -429,8 +429,7 @@ namespace ICSharpCode.Decompiler.IL
value = new Conv(value, additionalVar.StackType.ToPrimitiveType(), false, Sign.Signed); value = new Conv(value, additionalVar.StackType.ToPrimitiveType(), false, Sign.Signed);
newInstructions.Add(new StLoc(additionalVar, value) { newInstructions.Add(new StLoc(additionalVar, value) {
IsStackAdjustment = true, IsStackAdjustment = true,
ILRange = inst.ILRange }.WithILRange(inst));
});
} }
} }
} }
@ -454,7 +453,7 @@ namespace ICSharpCode.Decompiler.IL
} }
output.Write(" ["); output.Write(" [");
bool isFirstElement = true; bool isFirstElement = true;
foreach (var element in stackByOffset[inst.ILRange.Start]) { foreach (var element in stackByOffset[inst.StartILOffset]) {
if (isFirstElement) if (isFirstElement)
isFirstElement = false; isFirstElement = false;
else else
@ -465,11 +464,11 @@ namespace ICSharpCode.Decompiler.IL
} }
output.Write(']'); output.Write(']');
output.WriteLine(); output.WriteLine();
if (isBranchTarget[inst.ILRange.Start]) if (isBranchTarget[inst.StartILOffset])
output.Write('*'); output.Write('*');
else else
output.Write(' '); output.Write(' ');
output.WriteLocalReference("IL_" + inst.ILRange.Start.ToString("x4"), inst.ILRange.Start, isDefinition: true); output.WriteLocalReference("IL_" + inst.StartILOffset.ToString("x4"), inst.StartILOffset, isDefinition: true);
output.Write(": "); output.Write(": ");
inst.WriteTo(output, new ILAstWritingOptions()); inst.WriteTo(output, new ILAstWritingOptions());
output.WriteLine(); output.WriteLine();
@ -1033,7 +1032,7 @@ namespace ICSharpCode.Decompiler.IL
var variable = unionFind.Find(inst.Variable); var variable = unionFind.Find(inst.Variable);
if (variables.Add(variable)) if (variables.Add(variable))
variable.Name = "S_" + (variables.Count - 1); variable.Name = "S_" + (variables.Count - 1);
return new LdLoc(variable) { ILRange = inst.ILRange }; return new LdLoc(variable).WithILRange(inst);
} }
return inst; return inst;
} }
@ -1045,7 +1044,7 @@ namespace ICSharpCode.Decompiler.IL
var variable = unionFind.Find(inst.Variable); var variable = unionFind.Find(inst.Variable);
if (variables.Add(variable)) if (variables.Add(variable))
variable.Name = "S_" + (variables.Count - 1); variable.Name = "S_" + (variables.Count - 1);
return new StLoc(variable, inst.Value) { ILRange = inst.ILRange }; return new StLoc(variable, inst.Value).WithILRange(inst);
} }
return inst; return inst;
} }
@ -1064,7 +1063,7 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction Peek() ILInstruction Peek()
{ {
if (currentStack.IsEmpty) { if (currentStack.IsEmpty) {
return new InvalidExpression("Stack underflow") { ILRange = new Interval(reader.Offset, reader.Offset) }; return new InvalidExpression("Stack underflow").WithILRange(new Interval(reader.Offset, reader.Offset));
} }
return new LdLoc(currentStack.Peek()); return new LdLoc(currentStack.Peek());
} }
@ -1072,7 +1071,7 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction Pop() ILInstruction Pop()
{ {
if (currentStack.IsEmpty) { if (currentStack.IsEmpty) {
return new InvalidExpression("Stack underflow") { ILRange = new Interval(reader.Offset, reader.Offset) }; return new InvalidExpression("Stack underflow").WithILRange(new Interval(reader.Offset, reader.Offset));
} }
ILVariable v; ILVariable v;
currentStack = currentStack.Pop(out v); currentStack = currentStack.Pop(out v);
@ -1490,7 +1489,7 @@ namespace ICSharpCode.Decompiler.IL
int start = reader.Offset - 1; // opCode is always one byte in this case int start = reader.Offset - 1; // opCode is always one byte in this case
int target = ILParser.DecodeBranchTarget(ref reader, opCode); int target = ILParser.DecodeBranchTarget(ref reader, opCode);
var condition = Comparison(kind, un); var condition = Comparison(kind, un);
condition.ILRange = new Interval(start, reader.Offset); condition.AddILRange(new Interval(start, reader.Offset));
if (!IsInvalidBranch(target)) { if (!IsInvalidBranch(target)) {
MarkBranchTarget(target); MarkBranchTarget(target);
return new IfInstruction(condition, new Branch(target)); return new IfInstruction(condition, new Branch(target));

82
ICSharpCode.Decompiler/IL/Instructions.cs

@ -346,7 +346,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
this.argument.WriteTo(output, options); this.argument.WriteTo(output, options);
@ -439,7 +439,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
this.left.WriteTo(output, options); this.left.WriteTo(output, options);
@ -596,7 +596,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
this.target.WriteTo(output, options); this.target.WriteTo(output, options);
@ -971,7 +971,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
variable.WriteTo(output); variable.WriteTo(output);
@ -2282,7 +2282,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
variable.WriteTo(output); variable.WriteTo(output);
@ -2357,7 +2357,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
variable.WriteTo(output); variable.WriteTo(output);
@ -2490,7 +2490,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
variable.WriteTo(output); variable.WriteTo(output);
@ -2585,7 +2585,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
this.value.WriteTo(output, options); this.value.WriteTo(output, options);
@ -2748,7 +2748,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2785,7 +2785,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.I4; } } public override StackType ResultType { get { return StackType.I4; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2822,7 +2822,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.I8; } } public override StackType ResultType { get { return StackType.I8; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2859,7 +2859,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.F4; } } public override StackType ResultType { get { return StackType.F4; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2896,7 +2896,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.F8; } } public override StackType ResultType { get { return StackType.F8; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -2933,7 +2933,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
@ -3000,7 +3000,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.I; } } public override StackType ResultType { get { return StackType.I; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
method.WriteTo(output); method.WriteTo(output);
@ -3048,7 +3048,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
method.WriteTo(output); method.WriteTo(output);
@ -3093,7 +3093,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -3132,7 +3132,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
member.WriteTo(output); member.WriteTo(output);
@ -3220,7 +3220,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -3355,7 +3355,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (IsVolatile) if (IsVolatile)
output.Write("volatile."); output.Write("volatile.");
if (UnalignedPrefix > 0) if (UnalignedPrefix > 0)
@ -3503,7 +3503,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (IsVolatile) if (IsVolatile)
output.Write("volatile."); output.Write("volatile.");
if (UnalignedPrefix > 0) if (UnalignedPrefix > 0)
@ -3616,7 +3616,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (DelayExceptions) if (DelayExceptions)
output.Write("delayex."); output.Write("delayex.");
output.Write(OpCode); output.Write(OpCode);
@ -3660,7 +3660,7 @@ namespace ICSharpCode.Decompiler.IL
public IField Field { get { return field; } } public IField Field { get { return field; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
field.WriteTo(output); field.WriteTo(output);
@ -3711,7 +3711,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -3756,7 +3756,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -3862,7 +3862,7 @@ namespace ICSharpCode.Decompiler.IL
} }
void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options) void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (IsVolatile) if (IsVolatile)
output.Write("volatile."); output.Write("volatile.");
if (UnalignedPrefix > 0) if (UnalignedPrefix > 0)
@ -3996,7 +3996,7 @@ namespace ICSharpCode.Decompiler.IL
} }
void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options) void OriginalWriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (IsVolatile) if (IsVolatile)
output.Write("volatile."); output.Write("volatile.");
if (UnalignedPrefix > 0) if (UnalignedPrefix > 0)
@ -4062,7 +4062,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -4116,7 +4116,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -4170,7 +4170,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -4284,7 +4284,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -4333,7 +4333,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return type.GetStackType(); } } public override StackType ResultType { get { return type.GetStackType(); } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -4449,7 +4449,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.I4; } } public override StackType ResultType { get { return StackType.I4; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -4643,7 +4643,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (DelayExceptions) if (DelayExceptions)
output.Write("delayex."); output.Write("delayex.");
if (IsReadOnly) if (IsReadOnly)
@ -4747,7 +4747,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
this.array.WriteTo(output, options); this.array.WriteTo(output, options);
@ -4984,7 +4984,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
method.WriteTo(output); method.WriteTo(output);
@ -5999,7 +5999,7 @@ namespace ICSharpCode.Decompiler.IL
public override StackType ResultType { get { return StackType.O; } } public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -6081,7 +6081,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
type.WriteTo(output); type.WriteTo(output);
@ -6176,7 +6176,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
this.value.WriteTo(output, options); this.value.WriteTo(output, options);
@ -6269,7 +6269,7 @@ namespace ICSharpCode.Decompiler.IL
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
this.value.WriteTo(output, options); this.value.WriteTo(output, options);
@ -6331,7 +6331,7 @@ namespace ICSharpCode.Decompiler.IL.Patterns
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('('); output.Write('(');
output.Write(')'); output.Write(')');

2
ICSharpCode.Decompiler/IL/Instructions.tt

@ -595,7 +595,7 @@ namespace ICSharpCode.Decompiler.IL
public IEnumerable<string> WriteToBody { public IEnumerable<string> WriteToBody {
get { get {
yield return "ILRange.WriteTo(output, options);"; yield return "WriteILRange(output, options);";
foreach (string line in WriteOpCodePrefix) foreach (string line in WriteOpCodePrefix)
yield return line; yield return line;
yield return "output.Write(OpCode);"; yield return "output.Write(OpCode);";

2
ICSharpCode.Decompiler/IL/Instructions/BinaryNumericInstruction.cs

@ -177,7 +177,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write("." + GetOperatorName(Operator)); output.Write("." + GetOperatorName(Operator));
if (CheckForOverflow) { if (CheckForOverflow) {

6
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -95,7 +95,7 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone() public override ILInstruction Clone()
{ {
Block clone = new Block(Kind); Block clone = new Block(Kind);
clone.ILRange = this.ILRange; clone.AddILRange(this);
clone.Instructions.AddRange(this.Instructions.Select(inst => inst.Clone())); clone.Instructions.AddRange(this.Instructions.Select(inst => inst.Clone()));
clone.FinalInstruction = this.FinalInstruction.Clone(); clone.FinalInstruction = this.FinalInstruction.Clone();
return clone; return clone;
@ -145,12 +145,12 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public string Label public string Label
{ {
get { return Disassembler.DisassemblerHelpers.OffsetToString(this.ILRange.Start); } get { return Disassembler.DisassemblerHelpers.OffsetToString(this.StartILOffset); }
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("Block "); output.Write("Block ");
output.WriteLocalReference(Label, this, isDefinition: true); output.WriteLocalReference(Label, this, isDefinition: true);
if (Kind != BlockKind.ControlFlow) if (Kind != BlockKind.ControlFlow)

6
ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs

@ -81,7 +81,7 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone() public override ILInstruction Clone()
{ {
BlockContainer clone = new BlockContainer(); BlockContainer clone = new BlockContainer();
clone.ILRange = this.ILRange; clone.AddILRange(this);
clone.Blocks.AddRange(this.Blocks.Select(block => (Block)block.Clone())); clone.Blocks.AddRange(this.Blocks.Select(block => (Block)block.Clone()));
// Adjust branch instructions to point to the new container // Adjust branch instructions to point to the new container
foreach (var branch in clone.Descendants.OfType<Branch>()) { foreach (var branch in clone.Descendants.OfType<Branch>()) {
@ -117,7 +117,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.WriteLocalReference("BlockContainer", this, isDefinition: true); output.WriteLocalReference("BlockContainer", this, isDefinition: true);
output.Write(' '); output.Write(' ');
switch (Kind) { switch (Kind) {
@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.IL
base.CheckInvariant(phase); base.CheckInvariant(phase);
Debug.Assert(Blocks.Count > 0 && EntryPoint == Blocks[0]); Debug.Assert(Blocks.Count > 0 && EntryPoint == Blocks[0]);
Debug.Assert(!IsConnected || EntryPoint?.IncomingEdgeCount >= 1); Debug.Assert(!IsConnected || EntryPoint?.IncomingEdgeCount >= 1);
Debug.Assert(EntryPoint == null || Parent is ILFunction || !ILRange.IsEmpty); Debug.Assert(EntryPoint == null || Parent is ILFunction || !HasILRange);
Debug.Assert(Blocks.All(b => b.HasFlag(InstructionFlags.EndPointUnreachable))); Debug.Assert(Blocks.All(b => b.HasFlag(InstructionFlags.EndPointUnreachable)));
Debug.Assert(Blocks.All(b => b.Kind == BlockKind.ControlFlow)); // this also implies that the blocks don't use FinalInstruction Debug.Assert(Blocks.All(b => b.Kind == BlockKind.ControlFlow)); // this also implies that the blocks don't use FinalInstruction
Block bodyStartBlock; Block bodyStartBlock;

6
ICSharpCode.Decompiler/IL/Instructions/Branch.cs

@ -40,11 +40,11 @@ namespace ICSharpCode.Decompiler.IL
public Branch(Block targetBlock) : base(OpCode.Branch) public Branch(Block targetBlock) : base(OpCode.Branch)
{ {
this.targetBlock = targetBlock ?? throw new ArgumentNullException(nameof(targetBlock)); this.targetBlock = targetBlock ?? throw new ArgumentNullException(nameof(targetBlock));
this.targetILOffset = targetBlock.ILRange.Start; this.targetILOffset = targetBlock.StartILOffset;
} }
public int TargetILOffset { public int TargetILOffset {
get { return targetBlock != null ? targetBlock.ILRange.Start : targetILOffset; } get { return targetBlock != null ? targetBlock.StartILOffset : targetILOffset; }
} }
public Block TargetBlock { public Block TargetBlock {
@ -113,7 +113,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
output.WriteLocalReference(TargetLabel, (object)targetBlock ?? TargetILOffset); output.WriteLocalReference(TargetLabel, (object)targetBlock ?? TargetILOffset);

6
ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs

@ -76,9 +76,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
return new CallIndirect(CallingConvention, ReturnType, ParameterTypes, return new CallIndirect(CallingConvention, ReturnType, ParameterTypes,
this.Arguments.Select(inst => inst.Clone()), functionPointer.Clone() this.Arguments.Select(inst => inst.Clone()), functionPointer.Clone()
) { ).WithILRange(this);
ILRange = this.ILRange
};
} }
public override StackType ResultType => ReturnType.GetStackType(); public override StackType ResultType => ReturnType.GetStackType();
@ -91,7 +89,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("call.indirect "); output.Write("call.indirect ");
ReturnType.WriteTo(output); ReturnType.WriteTo(output);
output.Write('('); output.Write('(');

2
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -132,7 +132,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (ConstrainedTo != null) { if (ConstrainedTo != null) {
output.Write("constrained["); output.Write("constrained[");
ConstrainedTo.WriteTo(output, ILNameSyntax.ShortTypeName); ConstrainedTo.WriteTo(output, ILNameSyntax.ShortTypeName);

7
ICSharpCode.Decompiler/IL/Instructions/Comp.cs

@ -175,7 +175,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (options.UseLogicOperationSugar && MatchLogicNot(out var arg)) { if (options.UseLogicOperationSugar && MatchLogicNot(out var arg)) {
output.Write("logic.not("); output.Write("logic.not(");
arg.WriteTo(output, options); arg.WriteTo(output, options);
@ -214,11 +214,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
return new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0)); return new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0));
} }
public static Comp LogicNot(ILInstruction arg, Interval ilrange)
{
return new Comp(ComparisonKind.Equality, Sign.None, arg, new LdcI4(0)) { ILRange = ilrange };
}
} }
} }

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

@ -94,7 +94,7 @@ namespace ICSharpCode.Decompiler.IL
this.Operator = binary.Operator; this.Operator = binary.Operator;
this.IsLifted = binary.IsLifted; this.IsLifted = binary.IsLifted;
this.type = type; this.type = type;
this.ILRange = binary.ILRange; this.AddILRange(binary);
Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub)); Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub));
Debug.Assert(IsValidCompoundAssignmentTarget(Target)); Debug.Assert(IsValidCompoundAssignmentTarget(Target));
} }
@ -172,7 +172,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write("." + BinaryNumericInstruction.GetOperatorName(Operator)); output.Write("." + BinaryNumericInstruction.GetOperatorName(Operator));
if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue) if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue)
@ -216,7 +216,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue) if (CompoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue)
@ -253,7 +253,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write("." + Operation.ToString().ToLower()); output.Write("." + Operation.ToString().ToLower());
DynamicInstruction.WriteBinderFlags(BinderFlags, output, options); DynamicInstruction.WriteBinderFlags(BinderFlags, output, options);

2
ICSharpCode.Decompiler/IL/Instructions/Conv.cs

@ -305,7 +305,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (CheckForOverflow) { if (CheckForOverflow) {
output.Write(".ovf"); output.Write(".ovf");

24
ICSharpCode.Decompiler/IL/Instructions/DynamicInstructions.cs

@ -128,7 +128,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -180,7 +180,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -224,7 +224,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -260,7 +260,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -297,7 +297,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -329,7 +329,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -361,7 +361,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -397,7 +397,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -438,7 +438,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -484,7 +484,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -529,7 +529,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');
@ -559,7 +559,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
WriteBinderFlags(output, options); WriteBinderFlags(output, options);
output.Write(' '); output.Write(' ');

2
ICSharpCode.Decompiler/IL/Instructions/ExpressionTreeCast.cs

@ -18,7 +18,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (IsChecked) output.Write(".checked"); if (IsChecked) output.Write(".checked");
output.Write(' '); output.Write(' ');

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

@ -121,7 +121,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (Method != null) { if (Method != null) {
output.Write(' '); output.Write(' ');
@ -183,7 +183,7 @@ namespace ICSharpCode.Decompiler.IL
void MarkUsedILRanges(ILInstruction inst) void MarkUsedILRanges(ILInstruction inst)
{ {
if (CSharp.SequencePointBuilder.HasUsableILRange(inst)) { if (CSharp.SequencePointBuilder.HasUsableILRange(inst)) {
usedILRanges.Add(new LongInterval(inst.ILRange.Start, inst.ILRange.End)); usedILRanges.Add(new LongInterval(inst.StartILOffset, inst.EndILOffset));
} }
if (!(inst is ILFunction)) { if (!(inst is ILFunction)) {
foreach (var child in inst.Children) { foreach (var child in inst.Children) {

42
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -206,19 +206,19 @@ namespace ICSharpCode.Decompiler.IL
/// <summary> /// <summary>
/// Gets the ILRange for this instruction alone, ignoring the operands. /// Gets the ILRange for this instruction alone, ignoring the operands.
/// </summary> /// </summary>
public Interval ILRange; private Interval ILRange;
public void AddILRange(Interval newRange) public void AddILRange(Interval newRange)
{ {
if (newRange.IsEmpty) {
return;
}
if (this.ILRange.IsEmpty) { if (this.ILRange.IsEmpty) {
this.ILRange = newRange; this.ILRange = newRange;
return; return;
} }
if (newRange.Start <= this.ILRange.Start) { if (newRange.IsEmpty) {
if (newRange.End < this.ILRange.Start) { return;
}
if (newRange.Start <= this.StartILOffset) {
if (newRange.End < this.StartILOffset) {
this.ILRange = newRange; // use the earlier range this.ILRange = newRange; // use the earlier range
} else { } else {
// join overlapping ranges // join overlapping ranges
@ -226,10 +226,38 @@ namespace ICSharpCode.Decompiler.IL
} }
} else if (newRange.Start <= this.ILRange.End) { } else if (newRange.Start <= this.ILRange.End) {
// join overlapping ranges // join overlapping ranges
this.ILRange = new Interval(this.ILRange.Start, Math.Max(newRange.End, this.ILRange.End)); this.ILRange = new Interval(this.StartILOffset, Math.Max(newRange.End, this.ILRange.End));
} }
} }
public void AddILRange(ILInstruction sourceInstruction)
{
AddILRange(sourceInstruction.ILRange);
}
public void SetILRange(ILInstruction sourceInstruction)
{
ILRange = sourceInstruction.ILRange;
}
public void SetILRange(Interval range)
{
ILRange = range;
}
public int StartILOffset => ILRange.Start;
public int EndILOffset => ILRange.End;
public bool HasILRange => ILRange.IsEmpty;
public IEnumerable<Interval> ILRanges => new[] { ILRange };
public void WriteILRange(ITextOutput output, ILAstWritingOptions options)
{
ILRange.WriteTo(output, options);
}
/// <summary> /// <summary>
/// Writes the ILAst to the text output. /// Writes the ILAst to the text output.
/// </summary> /// </summary>

2
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -83,7 +83,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
if (options.UseLogicOperationSugar) { if (options.UseLogicOperationSugar) {
if (MatchLogicAnd(out var lhs, out var rhs)) { if (MatchLogicAnd(out var lhs, out var rhs)) {
output.Write("logic.and("); output.Write("logic.and(");

2
ICSharpCode.Decompiler/IL/Instructions/LdLen.cs

@ -40,7 +40,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write('.'); output.Write('.');
output.Write(resultType); output.Write(resultType);

2
ICSharpCode.Decompiler/IL/Instructions/Leave.cs

@ -111,7 +111,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (targetContainer != null) { if (targetContainer != null) {
output.Write(' '); output.Write(' ');

2
ICSharpCode.Decompiler/IL/Instructions/LockInstruction.cs

@ -28,7 +28,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("lock ("); output.Write("lock (");
OnExpression.WriteTo(output, options); OnExpression.WriteTo(output, options);
output.WriteLine(") {"); output.WriteLine(") {");

8
ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
if (options.UseFieldSugar) { if (options.UseFieldSugar) {
if (this.MatchLdFld(out var target, out var field)) { if (this.MatchLdFld(out var target, out var field)) {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("ldfld "); output.Write("ldfld ");
field.WriteTo(output); field.WriteTo(output);
output.Write('('); output.Write('(');
@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')'); output.Write(')');
return; return;
} else if (this.MatchLdsFld(out field)) { } else if (this.MatchLdsFld(out field)) {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("ldsfld "); output.Write("ldsfld ");
field.WriteTo(output); field.WriteTo(output);
return; return;
@ -65,7 +65,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
if (options.UseFieldSugar) { if (options.UseFieldSugar) {
if (this.MatchStFld(out var target, out var field, out var value)) { if (this.MatchStFld(out var target, out var field, out var value)) {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("stfld "); output.Write("stfld ");
field.WriteTo(output); field.WriteTo(output);
output.Write('('); output.Write('(');
@ -75,7 +75,7 @@ namespace ICSharpCode.Decompiler.IL
output.Write(')'); output.Write(')');
return; return;
} else if (this.MatchStsFld(out field, out value)) { } else if (this.MatchStsFld(out field, out value)) {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("stsfld "); output.Write("stsfld ");
field.WriteTo(output); field.WriteTo(output);
output.Write('('); output.Write('(');

2
ICSharpCode.Decompiler/IL/Instructions/NullCoalescingInstruction.cs

@ -91,7 +91,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
output.Write("("); output.Write("(");
valueInst.WriteTo(output, options); valueInst.WriteTo(output, options);

8
ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs

@ -26,7 +26,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
// the non-custom WriteTo would add useless parentheses // the non-custom WriteTo would add useless parentheses
} }
@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (Kind != NopKind.Normal) { if (Kind != NopKind.Normal) {
output.Write("." + Kind.ToString().ToLowerInvariant()); output.Write("." + Kind.ToString().ToLowerInvariant());
@ -73,7 +73,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (!string.IsNullOrEmpty(Message)) { if (!string.IsNullOrEmpty(Message)) {
output.Write("(\""); output.Write("(\"");
@ -100,7 +100,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (!string.IsNullOrEmpty(Message)) { if (!string.IsNullOrEmpty(Message)) {
output.Write("(\""); output.Write("(\"");

2
ICSharpCode.Decompiler/IL/Instructions/StringToInt.cs

@ -48,7 +48,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("string.to.int ("); output.Write("string.to.int (");
Argument.WriteTo(output, options); Argument.WriteTo(output, options);
output.Write(", { "); output.Write(", { ");

6
ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs

@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("switch"); output.Write("switch");
if (IsLifted) if (IsLifted)
output.Write(".lifted"); output.Write(".lifted");
@ -125,7 +125,7 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone() public override ILInstruction Clone()
{ {
var clone = new SwitchInstruction(value.Clone()); var clone = new SwitchInstruction(value.Clone());
clone.ILRange = this.ILRange; clone.AddILRange(this);
clone.Value = value.Clone(); clone.Value = value.Clone();
clone.Sections.AddRange(this.Sections.Select(h => (SwitchSection)h.Clone())); clone.Sections.AddRange(this.Sections.Select(h => (SwitchSection)h.Clone()));
return clone; return clone;
@ -182,7 +182,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.WriteLocalReference("case", this, isDefinition: true); output.WriteLocalReference("case", this, isDefinition: true);
output.Write(' '); output.Write(' ');
if (HasNullLabel) { if (HasNullLabel) {

18
ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs

@ -60,14 +60,14 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone() public override ILInstruction Clone()
{ {
var clone = new TryCatch(TryBlock.Clone()); var clone = new TryCatch(TryBlock.Clone());
clone.ILRange = this.ILRange; clone.AddILRange(this);
clone.Handlers.AddRange(this.Handlers.Select(h => (TryCatchHandler)h.Clone())); clone.Handlers.AddRange(this.Handlers.Select(h => (TryCatchHandler)h.Clone()));
return clone; return clone;
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(".try "); output.Write(".try ");
TryBlock.WriteTo(output, options); TryBlock.WriteTo(output, options);
foreach (var handler in Handlers) { foreach (var handler in Handlers) {
@ -162,7 +162,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("catch "); output.Write("catch ");
if (variable != null) { if (variable != null) {
output.WriteLocalReference(variable.Name, variable, isDefinition: true); output.WriteLocalReference(variable.Name, variable, isDefinition: true);
@ -197,14 +197,12 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone() public override ILInstruction Clone()
{ {
return new TryFinally(TryBlock.Clone(), finallyBlock.Clone()) { return new TryFinally(TryBlock.Clone(), finallyBlock.Clone()).WithILRange(this);
ILRange = this.ILRange
};
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(".try "); output.Write(".try ");
TryBlock.WriteTo(output, options); TryBlock.WriteTo(output, options);
output.Write(" finally "); output.Write(" finally ");
@ -293,14 +291,12 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone() public override ILInstruction Clone()
{ {
return new TryFault(TryBlock.Clone(), faultBlock.Clone()) { return new TryFault(TryBlock.Clone(), faultBlock.Clone()).WithILRange(this);
ILRange = this.ILRange
};
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(".try "); output.Write(".try ");
TryBlock.WriteTo(output, options); TryBlock.WriteTo(output, options);
output.Write(" fault "); output.Write(" fault ");

2
ICSharpCode.Decompiler/IL/Instructions/UnaryInstruction.cs

@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write(OpCode); output.Write(OpCode);
if (IsLifted) { if (IsLifted) {
output.Write(".lifted"); output.Write(".lifted");

2
ICSharpCode.Decompiler/IL/Instructions/UsingInstruction.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.Decompiler.IL
{ {
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
{ {
ILRange.WriteTo(output, options); WriteILRange(output, options);
output.Write("using ("); output.Write("using (");
Variable.WriteTo(output); Variable.WriteTo(output);
output.Write(" = "); output.Write(" = ");

4
ICSharpCode.Decompiler/IL/PointerArithmeticOffset.cs

@ -44,14 +44,14 @@ namespace ICSharpCode.Decompiler.IL
return countOffsetInst; return countOffsetInst;
} }
} else if (byteOffsetInst.UnwrapConv(ConversionKind.SignExtend) is SizeOf sizeOf && sizeOf.Type.Equals(pointerType.ElementType)) { } else if (byteOffsetInst.UnwrapConv(ConversionKind.SignExtend) is SizeOf sizeOf && sizeOf.Type.Equals(pointerType.ElementType)) {
return new LdcI4(1) { ILRange = byteOffsetInst.ILRange }; return new LdcI4(1).WithILRange(byteOffsetInst);
} else if (byteOffsetInst.MatchLdcI(out long val)) { } else if (byteOffsetInst.MatchLdcI(out long val)) {
// If the offset is a constant, it's possible that the compiler // If the offset is a constant, it's possible that the compiler
// constant-folded the multiplication. // constant-folded the multiplication.
if (elementSize > 0 && (val % elementSize == 0) && val > 0) { if (elementSize > 0 && (val % elementSize == 0) && val > 0) {
val /= elementSize.Value; val /= elementSize.Value;
if (val <= int.MaxValue) { if (val <= int.MaxValue) {
return new LdcI4((int)val) { ILRange = byteOffsetInst.ILRange }; return new LdcI4((int)val).WithILRange(byteOffsetInst);
} }
} }
} }

8
ICSharpCode.Decompiler/IL/Transforms/CombineExitsTransform.cs

@ -41,9 +41,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// leave (elseValue) // leave (elseValue)
// => // =>
// leave (if (cond) value else elseValue) // leave (if (cond) value else elseValue)
IfInstruction value = new IfInstruction(ifInst.Condition, leave.Value, leaveElse.Value) { ILRange = ifInst.ILRange }; IfInstruction value = new IfInstruction(ifInst.Condition, leave.Value, leaveElse.Value);
Leave combinedLeave = new Leave(leave.TargetContainer, value) { ILRange = leaveElse.ILRange }; value.AddILRange(ifInst);
combinedLeave.AddILRange(leave.ILRange); Leave combinedLeave = new Leave(leave.TargetContainer, value);
combinedLeave.AddILRange(leaveElse);
combinedLeave.AddILRange(leave);
ifInst.ReplaceWith(combinedLeave); ifInst.ReplaceWith(combinedLeave);
block.Instructions.RemoveAt(combinedLeave.ChildIndex + 1); block.Instructions.RemoveAt(combinedLeave.ChildIndex + 1);
} }

4
ICSharpCode.Decompiler/IL/Transforms/CopyPropagation.cs

@ -56,7 +56,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else { } else {
// evaluate the value for its side-effects // evaluate the value for its side-effects
context.Step("remove dead store to stack: evaluate the value for its side-effects", block.Instructions[i]); context.Step("remove dead store to stack: evaluate the value for its side-effects", block.Instructions[i]);
copiedExpr.AddILRange(block.Instructions[i].ILRange); copiedExpr.AddILRange(block.Instructions[i]);
block.Instructions[i] = copiedExpr; block.Instructions[i] = copiedExpr;
} }
} else if (v.IsSingleDefinition && CanPerformCopyPropagation(v, copiedExpr)) { } else if (v.IsSingleDefinition && CanPerformCopyPropagation(v, copiedExpr)) {
@ -111,7 +111,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var arg = copiedExpr.Children[j]; var arg = copiedExpr.Children[j];
var type = context.TypeSystem.FindType(arg.ResultType.ToKnownTypeCode()); var type = context.TypeSystem.FindType(arg.ResultType.ToKnownTypeCode());
uninlinedArgs[j] = new ILVariable(VariableKind.StackSlot, type, arg.ResultType) { uninlinedArgs[j] = new ILVariable(VariableKind.StackSlot, type, arg.ResultType) {
Name = "C_" + arg.ILRange.Start, Name = "C_" + arg.StartILOffset,
HasGeneratedName = true, HasGeneratedName = true,
}; };
block.Instructions.Insert(i++, new StLoc(uninlinedArgs[j], arg)); block.Instructions.Insert(i++, new StLoc(uninlinedArgs[j], arg));

24
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
foreach (var inst in function.Descendants) { foreach (var inst in function.Descendants) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
if (inst is NewObj call) { if (inst is NewObj call) {
context.StepStartGroup($"TransformDelegateConstruction {call.ILRange}", call); context.StepStartGroup($"TransformDelegateConstruction {call.StartILOffset}", call);
ILFunction f = TransformDelegateConstruction(call, out ILInstruction target); ILFunction f = TransformDelegateConstruction(call, out ILInstruction target);
if (f != null && target is IInstructionWithVariableOperand instWithVar) { if (f != null && target is IInstructionWithVariableOperand instWithVar) {
if (instWithVar.Variable.Kind == VariableKind.Local) { if (instWithVar.Variable.Kind == VariableKind.Local) {
@ -65,7 +65,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
} }
} }
foreach (var target in targetsToReplace.OrderByDescending(t => ((ILInstruction)t).ILRange.Start)) { foreach (var target in targetsToReplace.OrderByDescending(t => ((ILInstruction)t).StartILOffset)) {
context.Step($"TransformDisplayClassUsages {target.Variable}", (ILInstruction)target); context.Step($"TransformDisplayClassUsages {target.Variable}", (ILInstruction)target);
function.AcceptVisitor(new TransformDisplayClassUsages(function, target, target.Variable.CaptureScope, orphanedVariableInits, translatedDisplayClasses)); function.AcceptVisitor(new TransformDisplayClassUsages(function, target, target.Variable.CaptureScope, orphanedVariableInits, translatedDisplayClasses));
} }
@ -204,9 +204,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
nestedContext.StepStartGroup("DelegateConstruction (nested lambdas)", function); nestedContext.StepStartGroup("DelegateConstruction (nested lambdas)", function);
((IILTransform)new DelegateConstruction()).Run(function, nestedContext); ((IILTransform)new DelegateConstruction()).Run(function, nestedContext);
nestedContext.StepEndGroup(); nestedContext.StepEndGroup();
function.AddILRange(target.ILRange); function.AddILRange(target);
function.AddILRange(value.ILRange); function.AddILRange(value);
function.AddILRange(value.Arguments[1].ILRange); function.AddILRange(value.Arguments[1]);
return function; return function;
} }
@ -322,7 +322,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
field = (IField)field.MemberDefinition; field = (IField)field.MemberDefinition;
ILInstruction value; ILInstruction value;
if (initValues.TryGetValue(field, out DisplayClassVariable info)) { if (initValues.TryGetValue(field, out DisplayClassVariable info)) {
inst.ReplaceWith(new StLoc(info.variable, inst.Value) { ILRange = inst.ILRange }); inst.ReplaceWith(new StLoc(info.variable, inst.Value).WithILRange(inst));
} else { } else {
if (inst.Value.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter && currentFunction == v.Function) { if (inst.Value.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter && currentFunction == v.Function) {
// special case for parameters: remove copies of parameter values. // special case for parameters: remove copies of parameter values.
@ -333,7 +333,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return; return;
v = currentFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name); v = currentFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name);
v.CaptureScope = captureScope; v.CaptureScope = captureScope;
inst.ReplaceWith(new StLoc(v, inst.Value) { ILRange = inst.ILRange }); inst.ReplaceWith(new StLoc(v, inst.Value).WithILRange(inst));
value = new LdLoc(v); value = new LdLoc(v);
} }
initValues.Add(field, new DisplayClassVariable { value = value, variable = v }); initValues.Add(field, new DisplayClassVariable { value = value, variable = v });
@ -348,7 +348,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!initValues.TryGetValue((IField)field.MemberDefinition, out DisplayClassVariable info)) if (!initValues.TryGetValue((IField)field.MemberDefinition, out DisplayClassVariable info))
return; return;
var replacement = info.value.Clone(); var replacement = info.value.Clone();
replacement.ILRange = inst.ILRange; replacement.SetILRange(inst);
inst.ReplaceWith(replacement); inst.ReplaceWith(replacement);
} }
@ -358,7 +358,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (inst.Target.MatchLdThis() && inst.Field.Name == "$this" if (inst.Target.MatchLdThis() && inst.Field.Name == "$this"
&& inst.Field.MemberDefinition.ReflectionName.Contains("c__Iterator")) { && inst.Field.MemberDefinition.ReflectionName.Contains("c__Iterator")) {
var variable = currentFunction.Variables.First((f) => f.Index == -1); var variable = currentFunction.Variables.First((f) => f.Index == -1);
inst.ReplaceWith(new LdLoca(variable) { ILRange = inst.ILRange }); inst.ReplaceWith(new LdLoca(variable).WithILRange(inst));
} }
if (inst.Parent is LdObj || inst.Parent is StObj) if (inst.Parent is LdObj || inst.Parent is StObj)
return; return;
@ -370,11 +370,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return; return;
var v = currentFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name); var v = currentFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name);
v.CaptureScope = captureScope; v.CaptureScope = captureScope;
inst.ReplaceWith(new LdLoca(v) { ILRange = inst.ILRange }); inst.ReplaceWith(new LdLoca(v).WithILRange(inst));
var value = new LdLoc(v); var value = new LdLoc(v);
initValues.Add(field, new DisplayClassVariable { value = value, variable = v }); initValues.Add(field, new DisplayClassVariable { value = value, variable = v });
} else if (info.value is LdLoc l) { } else if (info.value is LdLoc l) {
inst.ReplaceWith(new LdLoca(l.Variable) { ILRange = inst.ILRange }); inst.ReplaceWith(new LdLoca(l.Variable).WithILRange(inst));
} else { } else {
Debug.Fail("LdFlda pattern not supported!"); Debug.Fail("LdFlda pattern not supported!");
} }
@ -384,7 +384,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
base.VisitNumericCompoundAssign(inst); base.VisitNumericCompoundAssign(inst);
if (inst.Target.MatchLdLoc(out var v)) { if (inst.Target.MatchLdLoc(out var v)) {
inst.ReplaceWith(new StLoc(v, new BinaryNumericInstruction(inst.Operator, inst.Target, inst.Value, inst.CheckForOverflow, inst.Sign) { ILRange = inst.ILRange })); inst.ReplaceWith(new StLoc(v, new BinaryNumericInstruction(inst.Operator, inst.Target, inst.Value, inst.CheckForOverflow, inst.Sign).WithILRange(inst)));
} }
} }
} }

6
ICSharpCode.Decompiler/IL/Transforms/EarlyExpressionTransforms.cs

@ -57,7 +57,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
&& !inst.IsVolatile) && !inst.IsVolatile)
{ {
context.Step($"stobj(ldloca {v.Name}, ...) => stloc {v.Name}(...)", inst); context.Step($"stobj(ldloca {v.Name}, ...) => stloc {v.Name}(...)", inst);
inst.ReplaceWith(new StLoc(v, inst.Value) { ILRange = inst.ILRange }); inst.ReplaceWith(new StLoc(v, inst.Value).WithILRange(inst));
return true; return true;
} }
return false; return false;
@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
&& !inst.IsVolatile) && !inst.IsVolatile)
{ {
context.Step($"ldobj(ldloca {v.Name}) => ldloc {v.Name}", inst); context.Step($"ldobj(ldloca {v.Name}) => ldloc {v.Name}", inst);
inst.ReplaceWith(new LdLoc(v) { ILRange = inst.ILRange }); inst.ReplaceWith(new LdLoc(v).WithILRange(inst));
return true; return true;
} }
return false; return false;
@ -102,7 +102,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// call(ref, ...) // call(ref, ...)
// => stobj(ref, newobj(...)) // => stobj(ref, newobj(...))
var newObj = new NewObj(inst.Method); var newObj = new NewObj(inst.Method);
newObj.ILRange = inst.ILRange; newObj.AddILRange(inst);
newObj.Arguments.AddRange(inst.Arguments.Skip(1)); newObj.Arguments.AddRange(inst.Arguments.Skip(1));
newObj.ILStackWasEmpty = inst.ILStackWasEmpty; newObj.ILStackWasEmpty = inst.ILStackWasEmpty;
var expr = new StObj(inst.Arguments[0], newObj, inst.Method.DeclaringType); var expr = new StObj(inst.Arguments[0], newObj, inst.Method.DeclaringType);

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

@ -78,7 +78,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// if (comp(x != 0)) ==> if (x) // if (comp(x != 0)) ==> if (x)
// comp(comp(...) != 0) => comp(...) // comp(comp(...) != 0) => comp(...)
context.Step("Remove redundant comp(... != 0)", inst); context.Step("Remove redundant comp(... != 0)", inst);
inst.Left.AddILRange(inst.ILRange); inst.Left.AddILRange(inst);
inst.ReplaceWith(inst.Left); inst.ReplaceWith(inst.Left);
inst.Left.AcceptVisitor(this); inst.Left.AcceptVisitor(this);
return; return;
@ -129,7 +129,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// This is a special case where the C# compiler doesn't generate conv.i4 after ldlen. // This is a special case where the C# compiler doesn't generate conv.i4 after ldlen.
context.Step("comp(ldlen.i4 array == ldc.i4 0)", inst); context.Step("comp(ldlen.i4 array == ldc.i4 0)", inst);
inst.InputType = StackType.I4; inst.InputType = StackType.I4;
inst.Left.ReplaceWith(new LdLen(StackType.I4, array) { ILRange = inst.Left.ILRange }); inst.Left.ReplaceWith(new LdLen(StackType.I4, array).WithILRange(inst.Left));
inst.Right = rightWithoutConv; inst.Right = rightWithoutConv;
} else if (inst.Left is Conv conv && conv.TargetType == PrimitiveType.I && conv.Argument.ResultType == StackType.O) { } else if (inst.Left is Conv conv && conv.TargetType == PrimitiveType.I && conv.Argument.ResultType == StackType.O) {
// C++/CLI sometimes uses this weird comparison with null: // C++/CLI sometimes uses this weird comparison with null:
@ -137,8 +137,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// -> comp(ldloc obj == ldnull) // -> comp(ldloc obj == ldnull)
inst.InputType = StackType.O; inst.InputType = StackType.O;
inst.Left = conv.Argument; inst.Left = conv.Argument;
inst.Right = new LdNull { ILRange = inst.Right.ILRange }; inst.Right = new LdNull().WithILRange(inst.Right);
inst.Right.AddILRange(rightWithoutConv.ILRange); inst.Right.AddILRange(rightWithoutConv);
} }
} }
@ -161,8 +161,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
&& (!inst.CheckForOverflow || context.Settings.AssumeArrayLengthFitsIntoInt32)) && (!inst.CheckForOverflow || context.Settings.AssumeArrayLengthFitsIntoInt32))
{ {
context.Step("conv.i4(ldlen array) => ldlen.i4(array)", inst); context.Step("conv.i4(ldlen array) => ldlen.i4(array)", inst);
inst.AddILRange(inst.Argument.ILRange); inst.AddILRange(inst.Argument);
inst.ReplaceWith(new LdLen(inst.TargetType.GetStackType(), array) { ILRange = inst.ILRange }); inst.ReplaceWith(new LdLen(inst.TargetType.GetStackType(), array).WithILRange(inst));
} }
} }
@ -172,7 +172,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (inst.Type.IsReferenceType == true && inst.Argument.ResultType == inst.ResultType) { if (inst.Type.IsReferenceType == true && inst.Argument.ResultType == inst.ResultType) {
// For reference types, box is a no-op. // For reference types, box is a no-op.
context.Step("box ref-type(arg) => arg", inst); context.Step("box ref-type(arg) => arg", inst);
inst.Argument.AddILRange(inst.ILRange); inst.Argument.AddILRange(inst);
inst.ReplaceWith(inst.Argument); inst.ReplaceWith(inst.Argument);
} }
} }
@ -209,7 +209,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if ((!comp.InputType.IsFloatType() && !comp.IsLifted) || comp.Kind.IsEqualityOrInequality()) { if ((!comp.InputType.IsFloatType() && !comp.IsLifted) || comp.Kind.IsEqualityOrInequality()) {
context.Step("push negation into comparison", inst); context.Step("push negation into comparison", inst);
comp.Kind = comp.Kind.Negate(); comp.Kind = comp.Kind.Negate();
comp.AddILRange(inst.ILRange); comp.AddILRange(inst);
inst.ReplaceWith(comp); inst.ReplaceWith(comp);
} }
comp.AcceptVisitor(this); comp.AcceptVisitor(this);
@ -220,9 +220,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IfInstruction ifInst = (IfInstruction)arg; IfInstruction ifInst = (IfInstruction)arg;
var ldc0 = ifInst.FalseInst; var ldc0 = ifInst.FalseInst;
Debug.Assert(ldc0.MatchLdcI4(0)); Debug.Assert(ldc0.MatchLdcI4(0));
ifInst.Condition = Comp.LogicNot(lhs, inst.ILRange); ifInst.Condition = Comp.LogicNot(lhs).WithILRange(inst);
ifInst.TrueInst = new LdcI4(1) { ILRange = ldc0.ILRange }; ifInst.TrueInst = new LdcI4(1).WithILRange(ldc0);
ifInst.FalseInst = Comp.LogicNot(rhs, inst.ILRange); ifInst.FalseInst = Comp.LogicNot(rhs).WithILRange(inst);
inst.ReplaceWith(ifInst); inst.ReplaceWith(ifInst);
ifInst.AcceptVisitor(this); ifInst.AcceptVisitor(this);
} else if (arg.MatchLogicOr(out lhs, out rhs)) { } else if (arg.MatchLogicOr(out lhs, out rhs)) {
@ -232,9 +232,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IfInstruction ifInst = (IfInstruction)arg; IfInstruction ifInst = (IfInstruction)arg;
var ldc1 = ifInst.TrueInst; var ldc1 = ifInst.TrueInst;
Debug.Assert(ldc1.MatchLdcI4(1)); Debug.Assert(ldc1.MatchLdcI4(1));
ifInst.Condition = Comp.LogicNot(lhs, inst.ILRange); ifInst.Condition = Comp.LogicNot(lhs).WithILRange(inst);
ifInst.TrueInst = Comp.LogicNot(rhs, inst.ILRange); ifInst.TrueInst = Comp.LogicNot(rhs).WithILRange(inst);
ifInst.FalseInst = new LdcI4(0) { ILRange = ldc1.ILRange }; ifInst.FalseInst = new LdcI4(0).WithILRange(ldc1);
inst.ReplaceWith(ifInst); inst.ReplaceWith(ifInst);
ifInst.AcceptVisitor(this); ifInst.AcceptVisitor(this);
} else { } else {
@ -324,7 +324,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var newVariable = initializerVariable.Function.RegisterVariable(VariableKind.InitializerTarget, type); var newVariable = initializerVariable.Function.RegisterVariable(VariableKind.InitializerTarget, type);
foreach (var load in initializerVariable.LoadInstructions.ToArray()) { foreach (var load in initializerVariable.LoadInstructions.ToArray()) {
ILInstruction newInst = new LdLoc(newVariable); ILInstruction newInst = new LdLoc(newVariable);
newInst.AddILRange(load.ILRange); newInst.AddILRange(load);
if (load.Parent != initializer) if (load.Parent != initializer)
newInst = new Conv(newInst, PrimitiveType.I, false, Sign.None); newInst = new Conv(newInst, PrimitiveType.I, false, Sign.None);
load.ReplaceWith(newInst); load.ReplaceWith(newInst);
@ -425,7 +425,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
if (transformed != null) { if (transformed != null) {
context.Step("User-defined short-circuiting logic operator (roslyn pattern)", condition); context.Step("User-defined short-circuiting logic operator (roslyn pattern)", condition);
transformed.AddILRange(inst.ILRange); transformed.AddILRange(inst);
inst.ReplaceWith(transformed); inst.ReplaceWith(transformed);
return; return;
} }
@ -552,7 +552,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (trueInst.Instructions[0].MatchStLoc(out v, out value1) && falseInst.Instructions[0].MatchStLoc(v, out value2)) { if (trueInst.Instructions[0].MatchStLoc(out v, out value1) && falseInst.Instructions[0].MatchStLoc(v, out value2)) {
context.Step("conditional operator", inst); context.Step("conditional operator", inst);
var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1); var newIf = new IfInstruction(Comp.LogicNot(inst.Condition), value2, value1);
newIf.ILRange = inst.ILRange; newIf.AddILRange(inst);
inst.ReplaceWith(new StLoc(v, newIf)); inst.ReplaceWith(new StLoc(v, newIf));
context.RequestRerun(); // trigger potential inlining of the newly created StLoc context.RequestRerun(); // trigger potential inlining of the newly created StLoc
return newIf; return newIf;

6
ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs

@ -186,9 +186,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
// combine all conditions and the exit instruction into one IfInstruction: // combine all conditions and the exit instruction into one IfInstruction:
IfInstruction condition = null; IfInstruction condition = null;
conditionBlock.AddILRange(exit.ILRange); conditionBlock.AddILRange(exit);
foreach (var inst in conditions) { foreach (var inst in conditions) {
conditionBlock.AddILRange(inst.ILRange); conditionBlock.AddILRange(inst);
if (condition == null) { if (condition == null) {
condition = inst; condition = inst;
if (swap) { if (swap) {
@ -414,7 +414,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// move the increment instruction: // move the increment instruction:
newIncremenBlock.Instructions.Add(secondToLast); newIncremenBlock.Instructions.Add(secondToLast);
newIncremenBlock.Instructions.Add(last); newIncremenBlock.Instructions.Add(last);
newIncremenBlock.AddILRange(secondToLast.ILRange); newIncremenBlock.AddILRange(secondToLast);
whileLoopBody.Instructions.RemoveRange(secondToLastIndex, 2); whileLoopBody.Instructions.RemoveRange(secondToLastIndex, 2);
whileLoopBody.Instructions.Add(new Branch(newIncremenBlock)); whileLoopBody.Instructions.Add(new Branch(newIncremenBlock));
// complete transform. // complete transform.

12
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -106,14 +106,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ctorCallStart = function.Descendants.FirstOrDefault(d => d is CallInstruction call && !(call is NewObj) ctorCallStart = function.Descendants.FirstOrDefault(d => d is CallInstruction call && !(call is NewObj)
&& call.Method.IsConstructor && call.Method.IsConstructor
&& call.Method.DeclaringType.IsReferenceType == true && call.Method.DeclaringType.IsReferenceType == true
&& call.Parent is Block)?.ILRange.Start ?? -1; && call.Parent is Block)?.StartILOffset ?? -1;
} }
if (inst.ILRange.InclusiveEnd >= ctorCallStart.GetValueOrDefault()) if (inst.EndILOffset > ctorCallStart.GetValueOrDefault())
return false; return false;
var topLevelInst = inst.Ancestors.LastOrDefault(instr => instr.Parent is Block); var topLevelInst = inst.Ancestors.LastOrDefault(instr => instr.Parent is Block);
if (topLevelInst == null) if (topLevelInst == null)
return false; return false;
return topLevelInst.ILRange.InclusiveEnd < ctorCallStart.GetValueOrDefault(); return topLevelInst.EndILOffset <= ctorCallStart.GetValueOrDefault();
} }
internal static bool IsCatchWhenBlock(Block block) internal static bool IsCatchWhenBlock(Block block)
@ -184,7 +184,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
int pos = stloc.ChildIndex; int pos = stloc.ChildIndex;
if (DoInline(v, stloc.Value, block.Instructions.ElementAtOrDefault(pos + 1), options, context)) { if (DoInline(v, stloc.Value, block.Instructions.ElementAtOrDefault(pos + 1), options, context)) {
// Assign the ranges of the stloc instruction: // Assign the ranges of the stloc instruction:
stloc.Value.AddILRange(stloc.ILRange); stloc.Value.AddILRange(stloc);
// Remove the stloc instruction: // Remove the stloc instruction:
Debug.Assert(block.Instructions[pos] == stloc); Debug.Assert(block.Instructions[pos] == stloc);
block.Instructions.RemoveAt(pos); block.Instructions.RemoveAt(pos);
@ -200,7 +200,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else if (v.Kind == VariableKind.StackSlot) { } else if (v.Kind == VariableKind.StackSlot) {
context.Step("Remove dead store, but keep expression", stloc); context.Step("Remove dead store, but keep expression", stloc);
// Assign the ranges of the stloc instruction: // Assign the ranges of the stloc instruction:
stloc.Value.AddILRange(stloc.ILRange); stloc.Value.AddILRange(stloc);
// Remove the stloc, but keep the inner expression // Remove the stloc, but keep the inner expression
stloc.ReplaceWith(stloc.Value); stloc.ReplaceWith(stloc.Value);
return true; return true;
@ -233,7 +233,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step($"Inline variable '{v.Name}'", inlinedExpression); context.Step($"Inline variable '{v.Name}'", inlinedExpression);
// Assign the ranges of the ldloc instruction: // Assign the ranges of the ldloc instruction:
inlinedExpression.AddILRange(loadInst.ILRange); inlinedExpression.AddILRange(loadInst);
if (loadInst.OpCode == OpCode.LdLoca) { if (loadInst.OpCode == OpCode.LdLoca) {
// it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof' // it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof'

8
ICSharpCode.Decompiler/IL/Transforms/LockTransform.cs

@ -86,7 +86,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step("LockTransformMCS", block); context.Step("LockTransformMCS", block);
block.Instructions.RemoveAt(i - 1); block.Instructions.RemoveAt(i - 1);
block.Instructions.RemoveAt(i - 2); block.Instructions.RemoveAt(i - 2);
body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock) { ILRange = objectStore.ILRange }); body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock).WithILRange(objectStore));
return true; return true;
} }
@ -129,7 +129,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step("LockTransformV2", block); context.Step("LockTransformV2", block);
block.Instructions.RemoveAt(i - 1); block.Instructions.RemoveAt(i - 1);
block.Instructions.RemoveAt(i - 2); block.Instructions.RemoveAt(i - 2);
body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock) { ILRange = objectStore.ILRange }); body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock).WithILRange(objectStore));
return true; return true;
} }
@ -173,7 +173,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step("LockTransformV4", block); context.Step("LockTransformV4", block);
block.Instructions.RemoveAt(i - 1); block.Instructions.RemoveAt(i - 1);
tryContainer.EntryPoint.Instructions.RemoveAt(0); tryContainer.EntryPoint.Instructions.RemoveAt(0);
body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock) { ILRange = objectStore.ILRange }); body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock).WithILRange(objectStore));
return true; return true;
} }
@ -219,7 +219,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
block.Instructions.RemoveAt(i - 1); block.Instructions.RemoveAt(i - 1);
block.Instructions.RemoveAt(i - 2); block.Instructions.RemoveAt(i - 2);
tryContainer.EntryPoint.Instructions.RemoveAt(0); tryContainer.EntryPoint.Instructions.RemoveAt(0);
body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock) { ILRange = objectStore.ILRange }); body.ReplaceWith(new LockInstruction(objectStore.Value, body.TryBlock).WithILRange(objectStore));
return true; return true;
} }

29
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Check if "condition ? trueInst : falseInst" can be simplified using the null-conditional operator. /// Check if "condition ? trueInst : falseInst" can be simplified using the null-conditional operator.
/// Returns the replacement instruction, or null if no replacement is possible. /// Returns the replacement instruction, or null if no replacement is possible.
/// </summary> /// </summary>
internal ILInstruction Run(ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst, Interval ilRange) internal ILInstruction Run(ILInstruction condition, ILInstruction trueInst, ILInstruction falseInst)
{ {
Debug.Assert(context.Settings.NullPropagation); Debug.Assert(context.Settings.NullPropagation);
Debug.Assert(!condition.MatchLogicNot(out _), "Caller should pass in positive condition"); Debug.Assert(!condition.MatchLogicNot(out _), "Caller should pass in positive condition");
@ -80,16 +80,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null; return null;
if (comp.Kind == ComparisonKind.Equality) { if (comp.Kind == ComparisonKind.Equality) {
// testedVar == null ? trueInst : falseInst // testedVar == null ? trueInst : falseInst
return TryNullPropagation(testedVar, falseInst, trueInst, Mode.ReferenceType, ilRange); return TryNullPropagation(testedVar, falseInst, trueInst, Mode.ReferenceType);
} else if (comp.Kind == ComparisonKind.Inequality) { } else if (comp.Kind == ComparisonKind.Inequality) {
return TryNullPropagation(testedVar, trueInst, falseInst, Mode.ReferenceType, ilRange); return TryNullPropagation(testedVar, trueInst, falseInst, Mode.ReferenceType);
} }
} else if (NullableLiftingTransform.MatchHasValueCall(condition, out ILInstruction loadInst)) { } else if (NullableLiftingTransform.MatchHasValueCall(condition, out ILInstruction loadInst)) {
// loadInst.HasValue ? trueInst : falseInst // loadInst.HasValue ? trueInst : falseInst
if (loadInst.MatchLdLoca(out testedVar)) { if (loadInst.MatchLdLoca(out testedVar)) {
return TryNullPropagation(testedVar, trueInst, falseInst, Mode.NullableByValue, ilRange); return TryNullPropagation(testedVar, trueInst, falseInst, Mode.NullableByValue);
} else if (loadInst.MatchLdLoc(out testedVar)) { } else if (loadInst.MatchLdLoc(out testedVar)) {
return TryNullPropagation(testedVar, trueInst, falseInst, Mode.NullableByReference, ilRange); return TryNullPropagation(testedVar, trueInst, falseInst, Mode.NullableByReference);
} }
} }
return null; return null;
@ -99,7 +99,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// testedVar != null ? nonNullInst : nullInst /// testedVar != null ? nonNullInst : nullInst
/// </summary> /// </summary>
ILInstruction TryNullPropagation(ILVariable testedVar, ILInstruction nonNullInst, ILInstruction nullInst, ILInstruction TryNullPropagation(ILVariable testedVar, ILInstruction nonNullInst, ILInstruction nullInst,
Mode mode, Interval ilRange) Mode mode)
{ {
bool removedRewrapOrNullableCtor = false; bool removedRewrapOrNullableCtor = false;
if (NullableLiftingTransform.MatchNullableCtor(nonNullInst, out _, out var arg)) { if (NullableLiftingTransform.MatchNullableCtor(nonNullInst, out _, out var arg)) {
@ -118,13 +118,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// testedVar != null ? testedVar.AccessChain : null // testedVar != null ? testedVar.AccessChain : null
// => testedVar?.AccessChain // => testedVar?.AccessChain
IntroduceUnwrap(testedVar, varLoad, mode); IntroduceUnwrap(testedVar, varLoad, mode);
return new NullableRewrap(nonNullInst) { ILRange = ilRange }; return new NullableRewrap(nonNullInst);
} else if (nullInst.MatchDefaultValue(out var type) && type.IsKnownType(KnownTypeCode.NullableOfT)) { } else if (nullInst.MatchDefaultValue(out var type) && type.IsKnownType(KnownTypeCode.NullableOfT)) {
context.Step($"Null propagation (mode={mode}, output=value type)", nonNullInst); context.Step($"Null propagation (mode={mode}, output=value type)", nonNullInst);
// testedVar != null ? testedVar.AccessChain : default(T?) // testedVar != null ? testedVar.AccessChain : default(T?)
// => testedVar?.AccessChain // => testedVar?.AccessChain
IntroduceUnwrap(testedVar, varLoad, mode); IntroduceUnwrap(testedVar, varLoad, mode);
return new NullableRewrap(nonNullInst) { ILRange = ilRange }; return new NullableRewrap(nonNullInst);
} else if (!removedRewrapOrNullableCtor && NullableType.IsNonNullableValueType(returnType)) { } else if (!removedRewrapOrNullableCtor && NullableType.IsNonNullableValueType(returnType)) {
context.Step($"Null propagation (mode={mode}, output=null coalescing)", nonNullInst); context.Step($"Null propagation (mode={mode}, output=null coalescing)", nonNullInst);
// testedVar != null ? testedVar.AccessChain : nullInst // testedVar != null ? testedVar.AccessChain : nullInst
@ -136,8 +136,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
new NullableRewrap(nonNullInst), new NullableRewrap(nonNullInst),
nullInst nullInst
) { ) {
UnderlyingResultType = nullInst.ResultType, UnderlyingResultType = nullInst.ResultType
ILRange = ilRange
}; };
} }
return null; return null;
@ -180,7 +179,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IntroduceUnwrap(testedVar, varLoad, mode); IntroduceUnwrap(testedVar, varLoad, mode);
ifInst.ReplaceWith(new NullableRewrap( ifInst.ReplaceWith(new NullableRewrap(
bodyInst bodyInst
) { ILRange = ifInst.ILRange }); ).WithILRange(ifInst));
} }
bool IsValidAccessChain(ILVariable testedVar, Mode mode, ILInstruction inst, out ILInstruction finalLoad) bool IsValidAccessChain(ILVariable testedVar, Mode mode, ILInstruction inst, out ILInstruction finalLoad)
@ -286,15 +285,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
Debug.Assert(NullableLiftingTransform.MatchGetValueOrDefault(varLoad, testedVar)); Debug.Assert(NullableLiftingTransform.MatchGetValueOrDefault(varLoad, testedVar));
replacement = new NullableUnwrap( replacement = new NullableUnwrap(
varLoad.ResultType, varLoad.ResultType,
new LdLoc(testedVar) { ILRange = varLoad.Children[0].ILRange } new LdLoc(testedVar).WithILRange(varLoad.Children[0])
) { ILRange = varLoad.ILRange }; ).WithILRange(varLoad);
break; break;
case Mode.NullableByReference: case Mode.NullableByReference:
replacement = new NullableUnwrap( replacement = new NullableUnwrap(
varLoad.ResultType, varLoad.ResultType,
new LdLoc(testedVar) { ILRange = varLoad.Children[0].ILRange }, new LdLoc(testedVar).WithILRange(varLoad.Children[0]),
refInput: true refInput: true
) { ILRange = varLoad.ILRange }; ).WithILRange(varLoad);
break; break;
default: default:
throw new ArgumentOutOfRangeException("mode"); throw new ArgumentOutOfRangeException("mode");

81
ICSharpCode.Decompiler/IL/Transforms/NullableLiftingTransform.cs

@ -147,7 +147,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
if (context.Settings.NullPropagation && !NullPropagationTransform.IsProtectedIfInst(ifInst as IfInstruction)) { if (context.Settings.NullPropagation && !NullPropagationTransform.IsProtectedIfInst(ifInst as IfInstruction)) {
var nullPropagated = new NullPropagationTransform(context) var nullPropagated = new NullPropagationTransform(context)
.Run(condition, trueInst, falseInst, ifInst.ILRange); .Run(condition, trueInst, falseInst)?.WithILRange(ifInst);
if (nullPropagated != null) if (nullPropagated != null)
return nullPropagated; return nullPropagated;
} }
@ -156,7 +156,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (AnalyzeCondition(condition)) { if (AnalyzeCondition(condition)) {
// (v1 != null && ... && vn != null) ? trueInst : falseInst // (v1 != null && ... && vn != null) ? trueInst : falseInst
// => normal lifting // => normal lifting
return LiftNormal(trueInst, falseInst, ilrange: ifInst.ILRange); return LiftNormal(trueInst, falseInst)?.WithILRange(ifInst);
} }
if (MatchCompOrDecimal(condition, out var comp)) { if (MatchCompOrDecimal(condition, out var comp)) {
// This might be a C#-style lifted comparison // This might be a C#-style lifted comparison
@ -206,36 +206,36 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step("NullableLiftingTransform: v == true", ifInst); context.Step("NullableLiftingTransform: v == true", ifInst);
return new Comp(ComparisonKind.Equality, ComparisonLiftingKind.CSharp, return new Comp(ComparisonKind.Equality, ComparisonLiftingKind.CSharp,
StackType.I4, Sign.None, StackType.I4, Sign.None,
new LdLoc(v) { ILRange = trueInst.ILRange }, new LdLoc(v).WithILRange(trueInst),
new LdcI4(1) { ILRange = falseInst.ILRange } new LdcI4(1).WithILRange(falseInst)
) { ILRange = ifInst.ILRange }; ).WithILRange(ifInst);
} else if (trueInst.MatchLdcI4(0) && MatchHasValueCall(falseInst, v)) { } else if (trueInst.MatchLdcI4(0) && MatchHasValueCall(falseInst, v)) {
// v.GetValueOrDefault() ? false : v.HasValue // v.GetValueOrDefault() ? false : v.HasValue
// ==> v == false // ==> v == false
context.Step("NullableLiftingTransform: v == false", ifInst); context.Step("NullableLiftingTransform: v == false", ifInst);
return new Comp(ComparisonKind.Equality, ComparisonLiftingKind.CSharp, return new Comp(ComparisonKind.Equality, ComparisonLiftingKind.CSharp,
StackType.I4, Sign.None, StackType.I4, Sign.None,
new LdLoc(v) { ILRange = falseInst.ILRange }, new LdLoc(v).WithILRange(falseInst),
trueInst // LdcI4(0) trueInst // LdcI4(0)
) { ILRange = ifInst.ILRange }; ).WithILRange(ifInst);
} else if (MatchNegatedHasValueCall(trueInst, v) && falseInst.MatchLdcI4(1)) { } else if (MatchNegatedHasValueCall(trueInst, v) && falseInst.MatchLdcI4(1)) {
// v.GetValueOrDefault() ? !v.HasValue : true // v.GetValueOrDefault() ? !v.HasValue : true
// ==> v != true // ==> v != true
context.Step("NullableLiftingTransform: v != true", ifInst); context.Step("NullableLiftingTransform: v != true", ifInst);
return new Comp(ComparisonKind.Inequality, ComparisonLiftingKind.CSharp, return new Comp(ComparisonKind.Inequality, ComparisonLiftingKind.CSharp,
StackType.I4, Sign.None, StackType.I4, Sign.None,
new LdLoc(v) { ILRange = trueInst.ILRange }, new LdLoc(v).WithILRange(trueInst),
falseInst // LdcI4(1) falseInst // LdcI4(1)
) { ILRange = ifInst.ILRange }; ).WithILRange(ifInst);
} else if (trueInst.MatchLdcI4(1) && MatchNegatedHasValueCall(falseInst, v)) { } else if (trueInst.MatchLdcI4(1) && MatchNegatedHasValueCall(falseInst, v)) {
// v.GetValueOrDefault() ? true : !v.HasValue // v.GetValueOrDefault() ? true : !v.HasValue
// ==> v != false // ==> v != false
context.Step("NullableLiftingTransform: v != false", ifInst); context.Step("NullableLiftingTransform: v != false", ifInst);
return new Comp(ComparisonKind.Inequality, ComparisonLiftingKind.CSharp, return new Comp(ComparisonKind.Inequality, ComparisonLiftingKind.CSharp,
StackType.I4, Sign.None, StackType.I4, Sign.None,
new LdLoc(v) { ILRange = falseInst.ILRange }, new LdLoc(v).WithILRange(falseInst),
new LdcI4(0) { ILRange = trueInst.ILRange } new LdcI4(0).WithILRange(trueInst)
) { ILRange = ifInst.ILRange }; ).WithILRange(ifInst);
} }
} }
// Handle & and | on bool?: // Handle & and | on bool?:
@ -246,7 +246,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// condition ? v : (bool?)false // condition ? v : (bool?)false
// => condition & v // => condition & v
context.Step("NullableLiftingTransform: 3vl.bool.and(bool, bool?)", ifInst); context.Step("NullableLiftingTransform: 3vl.bool.and(bool, bool?)", ifInst);
return new ThreeValuedBoolAnd(condition, trueInst) { ILRange = ifInst.ILRange }; return new ThreeValuedBoolAnd(condition, trueInst).WithILRange(ifInst);
} }
if (falseInst.MatchLdLoc(out var v2)) { if (falseInst.MatchLdLoc(out var v2)) {
// condition ? v : v2 // condition ? v : v2
@ -254,10 +254,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// (nullable1.GetValueOrDefault() || (!nullable2.GetValueOrDefault() && !nullable1.HasValue)) ? v : v2 // (nullable1.GetValueOrDefault() || (!nullable2.GetValueOrDefault() && !nullable1.HasValue)) ? v : v2
if (v == nullable1 && v2 == nullable2) { if (v == nullable1 && v2 == nullable2) {
context.Step("NullableLiftingTransform: 3vl.bool.or(bool?, bool?)", ifInst); context.Step("NullableLiftingTransform: 3vl.bool.or(bool?, bool?)", ifInst);
return new ThreeValuedBoolOr(trueInst, falseInst) { ILRange = ifInst.ILRange }; return new ThreeValuedBoolOr(trueInst, falseInst).WithILRange(ifInst);
} else if (v == nullable2 && v2 == nullable1) { } else if (v == nullable2 && v2 == nullable1) {
context.Step("NullableLiftingTransform: 3vl.bool.and(bool?, bool?)", ifInst); context.Step("NullableLiftingTransform: 3vl.bool.and(bool?, bool?)", ifInst);
return new ThreeValuedBoolAnd(falseInst, trueInst) { ILRange = ifInst.ILRange }; return new ThreeValuedBoolAnd(falseInst, trueInst).WithILRange(ifInst);
} }
} }
} }
@ -267,7 +267,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// condition ? (bool?)true : v // condition ? (bool?)true : v
// => condition | v // => condition | v
context.Step("NullableLiftingTransform: 3vl.logic.or(bool, bool?)", ifInst); context.Step("NullableLiftingTransform: 3vl.logic.or(bool, bool?)", ifInst);
return new ThreeValuedBoolOr(condition, falseInst) { ILRange = ifInst.ILRange }; return new ThreeValuedBoolOr(condition, falseInst).WithILRange(ifInst);
} }
} }
return null; return null;
@ -382,9 +382,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
internal ILInstruction MakeLifted(ComparisonKind newComparisonKind, ILInstruction left, ILInstruction right) internal ILInstruction MakeLifted(ComparisonKind newComparisonKind, ILInstruction left, ILInstruction right)
{ {
if (Instruction is Comp comp) { if (Instruction is Comp comp) {
return new Comp(newComparisonKind, ComparisonLiftingKind.CSharp, comp.InputType, comp.Sign, left, right) { return new Comp(newComparisonKind, ComparisonLiftingKind.CSharp, comp.InputType, comp.Sign, left, right).WithILRange(Instruction);
ILRange = Instruction.ILRange
};
} else if (Instruction is Call call) { } else if (Instruction is Call call) {
IMethod method; IMethod method;
if (newComparisonKind == Kind) { if (newComparisonKind == Kind) {
@ -400,10 +398,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return new Call(CSharp.Resolver.CSharpOperators.LiftUserDefinedOperator(method)) { return new Call(CSharp.Resolver.CSharpOperators.LiftUserDefinedOperator(method)) {
Arguments = { left, right }, Arguments = { left, right },
ConstrainedTo = call.ConstrainedTo, ConstrainedTo = call.ConstrainedTo,
ILRange = call.ILRange,
ILStackWasEmpty = call.ILStackWasEmpty, ILStackWasEmpty = call.ILStackWasEmpty,
IsTail = call.IsTail IsTail = call.IsTail
}; }.WithILRange(call);
} else { } else {
return null; return null;
} }
@ -531,10 +528,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return new Call(liftedOperator) { return new Call(liftedOperator) {
Arguments = { left, right }, Arguments = { left, right },
ConstrainedTo = call.ConstrainedTo, ConstrainedTo = call.ConstrainedTo,
ILRange = call.ILRange,
ILStackWasEmpty = call.ILStackWasEmpty, ILStackWasEmpty = call.ILStackWasEmpty,
IsTail = call.IsTail, IsTail = call.IsTail,
}; }.WithILRange(call);
} }
return null; return null;
} }
@ -549,7 +545,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// where the v1,...,vn are the <c>this.nullableVars</c>. /// where the v1,...,vn are the <c>this.nullableVars</c>.
/// If lifting fails, returns <c>null</c>. /// If lifting fails, returns <c>null</c>.
/// </summary> /// </summary>
ILInstruction LiftNormal(ILInstruction trueInst, ILInstruction falseInst, Interval ilrange) ILInstruction LiftNormal(ILInstruction trueInst, ILInstruction falseInst)
{ {
if (trueInst.MatchIfInstructionPositiveCondition(out var nestedCondition, out var nestedTrue, out var nestedFalse)) { if (trueInst.MatchIfInstructionPositiveCondition(out var nestedCondition, out var nestedTrue, out var nestedFalse)) {
// Sometimes Roslyn generates pointless conditions like: // Sometimes Roslyn generates pointless conditions like:
@ -569,8 +565,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// => v ?? fallback // => v ?? fallback
context.Step("v.HasValue ? v : fallback => v ?? fallback", trueInst); context.Step("v.HasValue ? v : fallback => v ?? fallback", trueInst);
return new NullCoalescingInstruction(NullCoalescingKind.Nullable, trueInst, falseInst) { return new NullCoalescingInstruction(NullCoalescingKind.Nullable, trueInst, falseInst) {
UnderlyingResultType = NullableType.GetUnderlyingType(nullableVars[0].Type).GetStackType(), UnderlyingResultType = NullableType.GetUnderlyingType(nullableVars[0].Type).GetStackType()
ILRange = ilrange
}; };
} else if (trueInst is Call call && !call.IsLifted } else if (trueInst is Call call && !call.IsLifted
&& CSharp.Resolver.CSharpOperators.IsComparisonOperator(call.Method) && CSharp.Resolver.CSharpOperators.IsComparisonOperator(call.Method)
@ -592,10 +587,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return new Call(liftedOperator) { return new Call(liftedOperator) {
Arguments = { left, right }, Arguments = { left, right },
ConstrainedTo = call.ConstrainedTo, ConstrainedTo = call.ConstrainedTo,
ILRange = call.ILRange,
ILStackWasEmpty = call.ILStackWasEmpty, ILStackWasEmpty = call.ILStackWasEmpty,
IsTail = call.IsTail IsTail = call.IsTail
}; }.WithILRange(call);
} }
} }
} }
@ -619,9 +613,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
inputUType.GetStackType(), inputUType.GetSign(), utype.ToPrimitiveType(), inputUType.GetStackType(), inputUType.GetSign(), utype.ToPrimitiveType(),
checkForOverflow: false, checkForOverflow: false,
isLifted: true isLifted: true
) { );
ILRange = ilrange
};
} }
} else { } else {
context.Step("NullableLiftingTransform.DoLift", trueInst); context.Step("NullableLiftingTransform.DoLift", trueInst);
@ -639,15 +631,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
if (isNullCoalescingWithNonNullableFallback) { if (isNullCoalescingWithNonNullableFallback) {
lifted = new NullCoalescingInstruction(NullCoalescingKind.NullableWithValueFallback, lifted, falseInst) { lifted = new NullCoalescingInstruction(NullCoalescingKind.NullableWithValueFallback, lifted, falseInst) {
UnderlyingResultType = exprToLift.ResultType, UnderlyingResultType = exprToLift.ResultType
ILRange = ilrange
}; };
} else if (!MatchNull(falseInst, utype)) { } else if (!MatchNull(falseInst, utype)) {
// Normal lifting, but the falseInst isn't `default(utype?)` // Normal lifting, but the falseInst isn't `default(utype?)`
// => use the `??` operator to provide the fallback value. // => use the `??` operator to provide the fallback value.
lifted = new NullCoalescingInstruction(NullCoalescingKind.Nullable, lifted, falseInst) { lifted = new NullCoalescingInstruction(NullCoalescingKind.Nullable, lifted, falseInst) {
UnderlyingResultType = exprToLift.ResultType, UnderlyingResultType = exprToLift.ResultType
ILRange = ilrange
}; };
} }
return lifted; return lifted;
@ -681,7 +671,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} }
} }
if (foundIndices.Any()) if (foundIndices.Any())
return (new LdLoc(inputVar) { ILRange = inst.ILRange }, foundIndices); return (new LdLoc(inputVar).WithILRange(inst), foundIndices);
else else
return (null, null); return (null, null);
} else if (inst is Conv conv) { } else if (inst is Conv conv) {
@ -693,17 +683,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// (thus causing it not to throw when any of them is null). // (thus causing it not to throw when any of them is null).
return (null, null); return (null, null);
} }
var newInst = new Conv(arg, conv.InputType, conv.InputSign, conv.TargetType, conv.CheckForOverflow, isLifted: true) { var newInst = new Conv(arg, conv.InputType, conv.InputSign, conv.TargetType, conv.CheckForOverflow, isLifted: true).WithILRange(conv);
ILRange = conv.ILRange
};
return (newInst, bits); return (newInst, bits);
} }
} else if (inst is BitNot bitnot) { } else if (inst is BitNot bitnot) {
var (arg, bits) = DoLift(bitnot.Argument); var (arg, bits) = DoLift(bitnot.Argument);
if (arg != null) { if (arg != null) {
var newInst = new BitNot(arg, isLifted: true, stackType: bitnot.ResultType) { var newInst = new BitNot(arg, isLifted: true, stackType: bitnot.ResultType).WithILRange(bitnot);
ILRange = bitnot.ILRange
};
return (newInst, bits); return (newInst, bits);
} }
} else if (inst is BinaryNumericInstruction binary) { } else if (inst is BinaryNumericInstruction binary) {
@ -720,9 +706,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
binary.LeftInputType, binary.RightInputType, binary.LeftInputType, binary.RightInputType,
binary.CheckForOverflow, binary.Sign, binary.CheckForOverflow, binary.Sign,
isLifted: true isLifted: true
) { ).WithILRange(binary);
ILRange = binary.ILRange
};
return (newInst, bits); return (newInst, bits);
} }
} else if (inst is Comp comp && !comp.IsLifted && comp.Kind == ComparisonKind.Equality } else if (inst is Comp comp && !comp.IsLifted && comp.Kind == ComparisonKind.Equality
@ -734,9 +718,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// except for operator! on bool?. // except for operator! on bool?.
var (arg, bits) = DoLift(comp.Left); var (arg, bits) = DoLift(comp.Left);
Debug.Assert(arg != null); Debug.Assert(arg != null);
var newInst = new Comp(comp.Kind, ComparisonLiftingKind.ThreeValuedLogic, comp.InputType, comp.Sign, arg, comp.Right.Clone()) { var newInst = new Comp(comp.Kind, ComparisonLiftingKind.ThreeValuedLogic, comp.InputType, comp.Sign, arg, comp.Right.Clone()).WithILRange(comp);
ILRange = comp.ILRange
};
return (newInst, bits); return (newInst, bits);
} else if (inst is Call call && call.Method.IsOperator) { } else if (inst is Call call && call.Method.IsOperator) {
// Lifted user-defined operators, except for comparison operators (as those return bool, not bool?) // Lifted user-defined operators, except for comparison operators (as those return bool, not bool?)
@ -765,8 +747,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ConstrainedTo = call.ConstrainedTo, ConstrainedTo = call.ConstrainedTo,
IsTail = call.IsTail, IsTail = call.IsTail,
ILStackWasEmpty = call.ILStackWasEmpty, ILStackWasEmpty = call.ILStackWasEmpty,
ILRange = call.ILRange }.WithILRange(call);
};
newInst.Arguments.AddRange(newArgs); newInst.Arguments.AddRange(newArgs);
return (newInst, newBits); return (newInst, newBits);
} }

6
ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs

@ -136,9 +136,9 @@ namespace ICSharpCode.Decompiler.IL
Debug.Assert(ifInst != block.Instructions.Last()); Debug.Assert(ifInst != block.Instructions.Last());
var trueRange = ConditionDetection.GetILRange(ifInst.TrueInst); var trueRangeStart = ConditionDetection.GetStartILOffset(ifInst.TrueInst, out bool trueRangeIsEmpty);
var falseRange = ConditionDetection.GetILRange(block.Instructions[block.Instructions.IndexOf(ifInst)+1]); var falseRangeStart = ConditionDetection.GetStartILOffset(block.Instructions[block.Instructions.IndexOf(ifInst)+1], out bool falseRangeIsEmpty);
if (!trueRange.IsEmpty && !falseRange.IsEmpty && falseRange.Start < trueRange.Start) if (!trueRangeIsEmpty && !falseRangeIsEmpty && falseRangeStart < trueRangeStart)
ConditionDetection.InvertIf(block, ifInst, context); ConditionDetection.InvertIf(block, ifInst, context);
} }

4
ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs

@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
for (int i = block.Instructions.Count - 1; i >= 0; i--) { for (int i = block.Instructions.Count - 1; i >= 0; i--) {
SwitchInstruction newSwitch; SwitchInstruction newSwitch;
if (MatchSwitchOnNullable(block.Instructions, i, out newSwitch)) { if (MatchSwitchOnNullable(block.Instructions, i, out newSwitch)) {
newSwitch.ILRange = block.Instructions[i - 2].ILRange; newSwitch.AddILRange(block.Instructions[i - 2]);
block.Instructions[i + 1].ReplaceWith(newSwitch); block.Instructions[i + 1].ReplaceWith(newSwitch);
block.Instructions.RemoveRange(i - 2, 3); block.Instructions.RemoveRange(i - 2, 3);
i -= 2; i -= 2;
@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
continue; continue;
} }
if (MatchRoslynSwitchOnNullable(block.Instructions, i, out newSwitch)) { if (MatchRoslynSwitchOnNullable(block.Instructions, i, out newSwitch)) {
newSwitch.ILRange = block.Instructions[i - 1].ILRange; newSwitch.AddILRange(block.Instructions[i - 1]);
block.Instructions[i - 1].ReplaceWith(newSwitch); block.Instructions[i - 1].ReplaceWith(newSwitch);
block.Instructions.RemoveRange(i, 2); block.Instructions.RemoveRange(i, 2);
i--; i--;

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

@ -219,17 +219,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var inst = new SwitchInstruction(stringToInt); var inst = new SwitchInstruction(stringToInt);
inst.Sections.AddRange(sections); inst.Sections.AddRange(sections);
if (extraLoad) { if (extraLoad) {
inst.ILRange = instructions[i - 2].ILRange; inst.AddILRange(instructions[i - 2]);
instructions[i - 2].ReplaceWith(inst); instructions[i - 2].ReplaceWith(inst);
instructions.RemoveRange(i - 1, 3); instructions.RemoveRange(i - 1, 3);
i -= 2; i -= 2;
} else { } else {
if (keepAssignmentBefore) { if (keepAssignmentBefore) {
inst.ILRange = instructions[i].ILRange; inst.AddILRange(instructions[i]);
instructions[i].ReplaceWith(inst); instructions[i].ReplaceWith(inst);
instructions.RemoveAt(i + 1); instructions.RemoveAt(i + 1);
} else { } else {
inst.ILRange = instructions[i - 1].ILRange; inst.AddILRange(instructions[i - 1]);
instructions[i - 1].ReplaceWith(inst); instructions[i - 1].ReplaceWith(inst);
instructions.RemoveRange(i, 2); instructions.RemoveRange(i, 2);
i--; i--;
@ -308,7 +308,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var inst = new SwitchInstruction(stringToInt); var inst = new SwitchInstruction(stringToInt);
inst.Sections.AddRange(sections); inst.Sections.AddRange(sections);
inst.ILRange = instructions[i - 1].ILRange; inst.AddILRange(instructions[i - 1]);
instructions[i].ReplaceWith(inst); instructions[i].ReplaceWith(inst);
instructions.RemoveAt(i + 1); instructions.RemoveAt(i + 1);
instructions.RemoveAt(i - 1); instructions.RemoveAt(i - 1);
@ -477,8 +477,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; return false;
if (!right.MatchLdcI4(0)) if (!right.MatchLdcI4(0))
return false; return false;
sections.Add(new SwitchSection() { Body = ifInst.TrueInst, Labels = new LongSet(0), ILRange = ifInst.ILRange }); sections.Add(new SwitchSection() { Body = ifInst.TrueInst, Labels = new LongSet(0) }.WithILRange(ifInst));
sections.Add(new SwitchSection() { Body = switchBlock.Instructions[1], Labels = new LongSet(0).Invert(), ILRange = switchBlock.Instructions[1].ILRange }); sections.Add(new SwitchSection() { Body = switchBlock.Instructions[1], Labels = new LongSet(0).Invert() }.WithILRange(switchBlock.Instructions[1]));
break; break;
} }
// mcs: map sections without a value to the default section, if possible // mcs: map sections without a value to the default section, if possible
@ -501,12 +501,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
instructions[i + 1].ReplaceWith(inst); instructions[i + 1].ReplaceWith(inst);
if (keepAssignmentBefore) { if (keepAssignmentBefore) {
// delete if (comp(ldloc switchValueVar == ldnull)) // delete if (comp(ldloc switchValueVar == ldnull))
inst.ILRange = instructions[i].ILRange; inst.AddILRange(instructions[i]);
instructions.RemoveAt(i); instructions.RemoveAt(i);
i--; i--;
} else { } else {
// delete both the if and the assignment before // delete both the if and the assignment before
inst.ILRange = instructions[i - 1].ILRange; inst.AddILRange(instructions[i - 1]);
instructions.RemoveRange(i - 1, 2); instructions.RemoveRange(i - 1, 2);
i -= 2; i -= 2;
} }
@ -721,7 +721,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var stringToInt = new StringToInt(switchValue, stringValues); var stringToInt = new StringToInt(switchValue, stringValues);
var inst = new SwitchInstruction(stringToInt); var inst = new SwitchInstruction(stringToInt);
inst.Sections.AddRange(sections); inst.Sections.AddRange(sections);
inst.ILRange = block.Instructions[i].ILRange; inst.AddILRange(block.Instructions[i]);
block.Instructions[i].ReplaceWith(inst); block.Instructions[i].ReplaceWith(inst);
block.Instructions.RemoveRange(i + 1, 3); block.Instructions.RemoveRange(i + 1, 3);
info.Transformed = true; info.Transformed = true;
@ -819,11 +819,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
newSwitch.Sections.Add(new SwitchSection { Labels = defaultLabel, Body = defaultSection.Body }); newSwitch.Sections.Add(new SwitchSection { Labels = defaultLabel, Body = defaultSection.Body });
instructions[i].ReplaceWith(newSwitch); instructions[i].ReplaceWith(newSwitch);
if (keepAssignmentBefore) { if (keepAssignmentBefore) {
newSwitch.ILRange = instructions[i - 1].ILRange; newSwitch.AddILRange(instructions[i - 1]);
instructions.RemoveAt(i - 1); instructions.RemoveAt(i - 1);
i--; i--;
} else { } else {
newSwitch.ILRange = instructions[i - 2].ILRange; newSwitch.AddILRange(instructions[i - 2]);
instructions.RemoveRange(i - 2, 2); instructions.RemoveRange(i - 2, 2);
i -= 2; i -= 2;
} }

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

@ -321,7 +321,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else { } else {
return false; return false;
} }
newInst.AddILRange(setterValue.ILRange); newInst.AddILRange(setterValue);
if (storeInSetter != null) { if (storeInSetter != null) {
storeInSetter.Value = newInst; storeInSetter.Value = newInst;
newInst = storeInSetter; newInst = storeInSetter;

4
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -152,13 +152,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!ReadParameters(instruction.Arguments[1], parameterList, parameterVariablesList, new SimpleTypeResolveContext(context.Function.Method))) if (!ReadParameters(instruction.Arguments[1], parameterList, parameterVariablesList, new SimpleTypeResolveContext(context.Function.Method)))
return (null, SpecialType.UnknownType); return (null, SpecialType.UnknownType);
var container = new BlockContainer(); var container = new BlockContainer();
container.ILRange = instruction.ILRange; container.AddILRange(instruction);
var functionType = instruction.Method.ReturnType.TypeArguments[0]; var functionType = instruction.Method.ReturnType.TypeArguments[0];
var returnType = functionType.GetDelegateInvokeMethod()?.ReturnType; var returnType = functionType.GetDelegateInvokeMethod()?.ReturnType;
var function = new ILFunction(returnType, parameterList, context.Function.GenericContext, container); var function = new ILFunction(returnType, parameterList, context.Function.GenericContext, container);
function.DelegateType = functionType; function.DelegateType = functionType;
function.Variables.AddRange(parameterVariablesList); function.Variables.AddRange(parameterVariablesList);
function.ILRange = instruction.ILRange; function.AddILRange(instruction);
lambdaStack.Push(function); lambdaStack.Push(function);
var (bodyInstruction, type) = ConvertInstruction(instruction.Arguments[0]); var (bodyInstruction, type) = ConvertInstruction(instruction.Arguments[0]);
lambdaStack.Pop(); lambdaStack.Pop();

15
ICSharpCode.Decompiler/IL/Transforms/UserDefinedLogicTransform.cs

@ -97,9 +97,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (s.IsUsedWithin(call.Arguments[1])) if (s.IsUsedWithin(call.Arguments[1]))
return false; return false;
context.Step("User-defined short-circuiting logic operator (legacy pattern)", condition); context.Step("User-defined short-circuiting logic operator (legacy pattern)", condition);
((StLoc)block.Instructions[pos]).Value = new UserDefinedLogicOperator(call.Method, lhsInst, call.Arguments[1]) { ((StLoc)block.Instructions[pos]).Value = new UserDefinedLogicOperator(call.Method, lhsInst, call.Arguments[1])
ILRange = call.ILRange .WithILRange(call);
};
block.Instructions.RemoveAt(pos + 1); block.Instructions.RemoveAt(pos + 1);
context.RequestRerun(); // the 'stloc s' may now be eligible for inlining context.RequestRerun(); // the 'stloc s' may now be eligible for inlining
return true; return true;
@ -148,9 +147,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null; return null;
var result = new UserDefinedLogicOperator(call.Method, call.Arguments[0], call.Arguments[1]); var result = new UserDefinedLogicOperator(call.Method, call.Arguments[0], call.Arguments[1]);
result.AddILRange(condition.ILRange); result.AddILRange(condition);
result.AddILRange(trueInst.ILRange); result.AddILRange(trueInst);
result.AddILRange(call.ILRange); result.AddILRange(call);
return result; return result;
} }
@ -242,9 +241,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null; return null;
var logicInst = new DynamicLogicOperatorInstruction(binary.BinderFlags, logicOp, binary.CallingContext, var logicInst = new DynamicLogicOperatorInstruction(binary.BinderFlags, logicOp, binary.CallingContext,
binary.LeftArgumentInfo, binary.Left, binary.RightArgumentInfo, binary.Right) binary.LeftArgumentInfo, binary.Left, binary.RightArgumentInfo, binary.Right)
{ .WithILRange(binary);
ILRange = binary.ILRange
};
if (rhsUnary != null) { if (rhsUnary != null) {
rhsUnary.Operand = logicInst; rhsUnary.Operand = logicInst;
return rhsUnary; return rhsUnary;

2
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -87,7 +87,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.Step("UsingTransform", tryFinally); context.Step("UsingTransform", tryFinally);
storeInst.Variable.Kind = VariableKind.UsingLocal; storeInst.Variable.Kind = VariableKind.UsingLocal;
block.Instructions.RemoveAt(i); block.Instructions.RemoveAt(i);
block.Instructions[i - 1] = new UsingInstruction(storeInst.Variable, storeInst.Value, tryFinally.TryBlock) { ILRange = storeInst.ILRange }; block.Instructions[i - 1] = new UsingInstruction(storeInst.Variable, storeInst.Value, tryFinally.TryBlock).WithILRange(storeInst);
return true; return true;
} }

Loading…
Cancel
Save