mirror of
https://github.com/AssetRipper/ILSpy.git
synced 2026-11-13 20:05:48 -10:00
Fix #1391, #1393, #1458: Fix ReduceNestingTransform modifying the Blocks collection while iterating over it.
This commit is contained in:
1 parent
bb10f5a6a6
commit
7f27768ff9
1 file changed
+22
-10
@@ -65,8 +65,13 @@ namespace ICSharpCode.Decompiler.IL
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var block in container.Blocks)
|
||||
for (int i = 0; i < container.Blocks.Count; i++) {
|
||||
var block = container.Blocks[i];
|
||||
// Note: it's possible for additional blocks to be appended to the container
|
||||
// by the Visit() call; but there should be no other changes to the Blocks collection.
|
||||
Visit(block, continueTarget);
|
||||
Debug.Assert(container.Blocks[i] == block);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,10 +99,10 @@ namespace ICSharpCode.Decompiler.IL
|
||||
|
||||
// reduce nesting in switch blocks
|
||||
if (container.Kind == ContainerKind.Switch &&
|
||||
CanDuplicateExit(NextInsn(), continueTarget) &&
|
||||
ReduceNesting(block, container, NextInsn()))
|
||||
CanDuplicateExit(NextInsn(), continueTarget) &&
|
||||
ReduceSwitchNesting(block, container, NextInsn())) {
|
||||
RemoveRedundantExit(block, nextInstruction);
|
||||
|
||||
}
|
||||
break;
|
||||
case IfInstruction ifInst:
|
||||
ImproveILOrdering(block, ifInst);
|
||||
@@ -200,7 +205,7 @@ namespace ICSharpCode.Decompiler.IL
|
||||
/// Reduce Nesting in switch statements by replacing break; in cases with the block exit, and extracting the default case
|
||||
/// Does not affect IL order
|
||||
/// </summary>
|
||||
private bool ReduceNesting(Block parentBlock, BlockContainer switchContainer, ILInstruction exitInst)
|
||||
private bool ReduceSwitchNesting(Block parentBlock, BlockContainer switchContainer, ILInstruction exitInst)
|
||||
{
|
||||
// break; from outer container cannot be brought inside the switch as the meaning would change
|
||||
if (exitInst is Leave leave && !leave.IsLeavingFunction)
|
||||
@@ -229,7 +234,10 @@ namespace ICSharpCode.Decompiler.IL
|
||||
var defaultTree = TreeTraversal.PreOrder(defaultNode, n => n.DominatorTreeChildren).ToList();
|
||||
if (defaultTree.SelectMany(n => n.Successors).Any(n => !defaultNode.Dominates(n)))
|
||||
return false;
|
||||
|
||||
|
||||
if (defaultTree.Count > 1 && !(parentBlock.Parent is BlockContainer))
|
||||
return false;
|
||||
|
||||
EnsureEndPointUnreachable(parentBlock, exitInst);
|
||||
context.Step("Extract default case of switch", switchContainer);
|
||||
|
||||
@@ -247,14 +255,18 @@ namespace ICSharpCode.Decompiler.IL
|
||||
switchContainer.Blocks.Remove(block);
|
||||
|
||||
// replace the parent block exit with the default case instructions
|
||||
Debug.Assert(parentBlock.Instructions.Last() == exitInst);
|
||||
parentBlock.Instructions.RemoveLast();
|
||||
parentBlock.Instructions.AddRange(defaultBlock.Instructions);
|
||||
|
||||
// add any additional blocks from the default case to the parent container
|
||||
var parentContainer = (BlockContainer)parentBlock.Ancestors.First(p => p is BlockContainer);
|
||||
int insertAt = parentContainer.Blocks.IndexOf(parentBlock) + 1;
|
||||
foreach (var block in defaultBlocks.Skip(1))
|
||||
parentContainer.Blocks.Insert(insertAt++, block);
|
||||
Debug.Assert(defaultBlocks[0] == defaultBlock);
|
||||
if (defaultBlocks.Count > 1) {
|
||||
var parentContainer = (BlockContainer)parentBlock.Parent;
|
||||
int insertAt = parentContainer.Blocks.IndexOf(parentBlock) + 1;
|
||||
foreach (var block in defaultBlocks.Skip(1))
|
||||
parentContainer.Blocks.Insert(insertAt++, block);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user