From e9b766d7085bb0cdf763c5d221f1ed0b58203f94 Mon Sep 17 00:00:00 2001 From: Chicken-Bones Date: Sun, 2 Sep 2018 12:53:13 +1000 Subject: [PATCH 1/2] Improve persistence of IL offsets through various transforms. --- ICSharpCode.Decompiler/IL/BlockBuilder.cs | 10 +++++++++- .../IL/ControlFlow/AwaitInCatchTransform.cs | 4 +++- .../IL/ControlFlow/ConditionDetection.cs | 12 +++++++++++- .../IL/ControlFlow/ControlFlowSimplification.cs | 9 ++++++++- .../IL/ControlFlow/DetectPinnedRegions.cs | 7 +++++-- .../IL/ControlFlow/LoopDetection.cs | 4 +++- .../IL/ControlFlow/SwitchDetection.cs | 1 + .../IL/ControlFlow/YieldReturnDecompiler.cs | 4 +++- .../IL/Instructions/BlockContainer.cs | 1 + .../IL/Transforms/SwitchOnNullableTransform.cs | 2 ++ .../IL/Transforms/SwitchOnStringTransform.cs | 11 ++++++++++- .../IL/Transforms/TransformExpressionTrees.cs | 2 ++ 12 files changed, 58 insertions(+), 9 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/BlockBuilder.cs b/ICSharpCode.Decompiler/IL/BlockBuilder.cs index 412bd551e..1a2e69235 100644 --- a/ICSharpCode.Decompiler/IL/BlockBuilder.cs +++ b/ICSharpCode.Decompiler/IL/BlockBuilder.cs @@ -75,6 +75,7 @@ namespace ICSharpCode.Decompiler.IL var tryBlock = new BlockContainer(); tryBlock.ILRange = tryRange; tryCatch = new TryCatch(tryBlock); + tryCatch.ILRange = tryRange; tryCatchList.Add(tryCatch); tryInstructionList.Add(tryCatch); } @@ -90,7 +91,11 @@ namespace ICSharpCode.Decompiler.IL filter = new LdcI4(1); } - tryCatch.Handlers.Add(new TryCatchHandler(filter, handlerBlock, variableByExceptionHandler[eh])); + var handler = new TryCatchHandler(filter, handlerBlock, variableByExceptionHandler[eh]); + handler.AddILRange(filter.ILRange); + handler.AddILRange(handlerBlock.ILRange); + tryCatch.Handlers.Add(handler); + tryCatch.AddILRange(handler.ILRange); } if (tryInstructionList.Count > 0) { tryInstructionList = tryInstructionList.OrderBy(tc => tc.TryBlock.ILRange.Start).ThenByDescending(tc => tc.TryBlock.ILRange.End).ToList(); @@ -128,6 +133,7 @@ namespace ICSharpCode.Decompiler.IL // Leave nested containers if necessary while (start >= currentContainer.ILRange.End) { currentContainer = containerStack.Pop(); + currentBlock = currentContainer.Blocks.Last(); } // Enter a handler if necessary BlockContainer handlerContainer; @@ -136,6 +142,7 @@ namespace ICSharpCode.Decompiler.IL currentContainer = handlerContainer; currentBlock = handlerContainer.EntryPoint; } else { + FinalizeCurrentBlock(start, fallthrough: false); // Create the new block currentBlock = new Block(); currentContainer.Blocks.Add(currentBlock); @@ -172,6 +179,7 @@ namespace ICSharpCode.Decompiler.IL { if (currentBlock == null) return; + Debug.Assert(currentBlock.ILRange.IsEmpty); currentBlock.ILRange = new Interval(currentBlock.ILRange.Start, currentILOffset); if (fallthrough) { if (currentBlock.Instructions.LastOrDefault() is SwitchInstruction switchInst && switchInst.Sections.Last().Body.MatchNop()) { diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs index b9efda882..9800c264f 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs @@ -265,6 +265,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow var outer = BlockContainer.FindClosestContainer(container.Parent); if (outer != null) changedContainers.Add(outer); finallyContainer.Blocks.Add(entryPointOfFinally); + finallyContainer.ILRange = entryPointOfFinally.ILRange; exitOfFinally.Instructions.RemoveRange(tempStore.ChildIndex, 3); exitOfFinally.Instructions.Add(new Leave(finallyContainer)); foreach (var branchToFinally in container.Descendants.OfType()) { @@ -274,8 +275,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow foreach (var newBlock in additionalBlocksInFinally) { newBlock.Remove(); finallyContainer.Blocks.Add(newBlock); + finallyContainer.AddILRange(newBlock.ILRange); } - tryCatch.ReplaceWith(new TryFinally(tryCatch.TryBlock, finallyContainer)); + tryCatch.ReplaceWith(new TryFinally(tryCatch.TryBlock, finallyContainer) {ILRange = tryCatch.TryBlock.ILRange}); } // clean up all modified containers diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs b/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs index ee44eea01..430bc5598 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs @@ -425,7 +425,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow /// private void OrderIfBlocks(IfInstruction ifInst) { - if (IsEmpty(ifInst.FalseInst) || ifInst.TrueInst.ILRange.Start <= ifInst.FalseInst.ILRange.Start) + if (IsEmpty(ifInst.FalseInst) || GetILRange(ifInst.TrueInst).Start <= GetILRange(ifInst.FalseInst).Start) return; context.Step("Swap then-branch with else-branch to match IL order", ifInst); @@ -437,6 +437,16 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow ifInst.Condition = Comp.LogicNot(ifInst.Condition); } + public static Interval GetILRange(ILInstruction inst) + { + // 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 + if (inst is Leave leave && !leave.Value.MatchNop()) + return leave.Value.ILRange; + + return inst.ILRange; + } + /// /// Compares the current block exit, and the exit of ifInst.ThenInst /// and inverts if necessary to pick the better exit diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs b/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs index 1cc34d494..64bee1b75 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs @@ -132,7 +132,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } else if (targetBlock.Instructions.Count == 1 && targetBlock.Instructions[0] is Leave leave && leave.Value.MatchNop()) { context.Step("Replace branch to leave with leave", branch); // Replace branches to 'leave' instruction with the leave instruction - branch.ReplaceWith(leave.Clone()); + var leave2 = leave.Clone(); + if (!branch.ILRange.IsEmpty) // use the ILRange of the branch if possible + leave2.ILRange = branch.ILRange; + branch.ReplaceWith(leave2); } if (targetBlock.IncomingEdgeCount == 0) targetBlock.Instructions.Clear(); // mark the block for deletion @@ -187,6 +190,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow // The C# compiler generates a dead store for the condition of while (true) loops. block.Instructions.RemoveRange(block.Instructions.Count - 3, 2); } + + if (block.ILRange.IsEmpty) + block.ILRange = targetBlock.ILRange; + block.Instructions.Remove(br); block.Instructions.AddRange(targetBlock.Instructions); targetBlock.Instructions.Clear(); // mark targetBlock for deletion diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs b/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs index 45be3e101..f07e4e59b 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs @@ -147,7 +147,9 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow if (p.StackType != StackType.Ref) { 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 + }; ((Branch)block.Instructions.Last()).TargetBlock = targetBlock; modified = true; } @@ -343,7 +345,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } } - stLoc.ReplaceWith(new PinnedRegion(stLoc.Variable, stLoc.Value, body)); + stLoc.ReplaceWith(new PinnedRegion(stLoc.Variable, stLoc.Value, body) { ILRange = stLoc.ILRange }); block.Instructions.RemoveAt(block.Instructions.Count - 1); // remove branch into body ProcessPinnedRegion((PinnedRegion)block.Instructions.Last()); return true; @@ -400,6 +402,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow foreach (var block in body.Blocks) CreatePinnedRegion(block); body.Blocks.RemoveAll(b => b.Instructions.Count == 0); // remove dummy blocks + body.ILRange = body.EntryPoint.ILRange; } private void MoveArrayToPointerToPinnedRegionInit(PinnedRegion pinnedRegion) diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs b/ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs index 9e0f4e0bc..43dd6f9b0 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/LoopDetection.cs @@ -646,6 +646,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow if (exitTargetBlock != null) oldEntryPoint.Instructions.Add(new Branch(exitTargetBlock)); + loopContainer.ILRange = newEntryPoint.ILRange; MoveBlocksIntoContainer(loop, loopContainer); // Rewrite branches within the loop from oldEntryPoint to newEntryPoint: @@ -731,7 +732,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow if (exitTargetBlock != null) { block.Instructions.Add(new Branch(exitTargetBlock)); } - + + switchContainer.ILRange = newEntryPoint.ILRange; MoveBlocksIntoContainer(nodesInSwitch, switchContainer); // Rewrite branches within the loop from oldEntryPoint to newEntryPoint: diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/SwitchDetection.cs b/ICSharpCode.Decompiler/IL/ControlFlow/SwitchDetection.cs index d95fedb5b..4d2bb945c 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/SwitchDetection.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/SwitchDetection.cs @@ -180,6 +180,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow // Remove branch/leave after if; it's getting moved into a section. block.Instructions.RemoveAt(block.Instructions.Count - 1); } + sw.ILRange = block.Instructions[block.Instructions.Count - 1].ILRange; block.Instructions[block.Instructions.Count - 1] = sw; // mark all inner blocks that were converted to the switch statement for deletion diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs b/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs index a2b386105..c7389e123 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/YieldReturnDecompiler.cs @@ -674,6 +674,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } // copy over the instruction to the new block newBlock.Instructions.Add(oldInst); + newBlock.AddILRange(oldInst.ILRange); UpdateBranchTargets(oldInst); } } @@ -931,6 +932,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow tryBlock.Instructions.AddRange(block.Instructions); var tryBlockContainer = new BlockContainer(); tryBlockContainer.Blocks.Add(tryBlock); + tryBlockContainer.ILRange = tryBlock.ILRange; stateToContainer.Add(state, tryBlockContainer); ILInstruction finallyBlock; @@ -944,7 +946,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } block.Instructions.Clear(); - block.Instructions.Add(new TryFinally(tryBlockContainer, finallyBlock)); + block.Instructions.Add(new TryFinally(tryBlockContainer, finallyBlock) { ILRange = tryBlockContainer.ILRange}); } IMethod FindFinallyMethod(int state) diff --git a/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs b/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs index a716a6776..2f775bbb2 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs @@ -181,6 +181,7 @@ namespace ICSharpCode.Decompiler.IL base.CheckInvariant(phase); Debug.Assert(Blocks.Count > 0 && EntryPoint == Blocks[0]); Debug.Assert(!IsConnected || EntryPoint?.IncomingEdgeCount >= 1); + Debug.Assert(EntryPoint == null || Parent is ILFunction || !ILRange.IsEmpty); 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 Block bodyStartBlock; diff --git a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs index af7cc6ae7..066dc02b3 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnNullableTransform.cs @@ -42,6 +42,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms for (int i = block.Instructions.Count - 1; i >= 0; i--) { SwitchInstruction newSwitch; if (MatchSwitchOnNullable(block.Instructions, i, out newSwitch)) { + newSwitch.ILRange = block.Instructions[i - 2].ILRange; block.Instructions[i + 1].ReplaceWith(newSwitch); block.Instructions.RemoveRange(i - 2, 3); i -= 2; @@ -49,6 +50,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms continue; } if (MatchRoslynSwitchOnNullable(block.Instructions, i, out newSwitch)) { + newSwitch.ILRange = block.Instructions[i - 1].ILRange; block.Instructions[i - 1].ReplaceWith(newSwitch); block.Instructions.RemoveRange(i, 2); i--; diff --git a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs index fcd311b63..d35d2533c 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs @@ -219,14 +219,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms var inst = new SwitchInstruction(stringToInt); inst.Sections.AddRange(sections); if (extraLoad) { + inst.ILRange = instructions[i - 2].ILRange; instructions[i - 2].ReplaceWith(inst); instructions.RemoveRange(i - 1, 3); i -= 2; } else { if (keepAssignmentBefore) { + inst.ILRange = instructions[i].ILRange; instructions[i].ReplaceWith(inst); instructions.RemoveAt(i + 1); } else { + inst.ILRange = instructions[i - 1].ILRange; instructions[i - 1].ReplaceWith(inst); instructions.RemoveRange(i, 2); i--; @@ -304,7 +307,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms var stringToInt = new StringToInt(switchValue, values.SelectArray(item => item.Item1)); var inst = new SwitchInstruction(stringToInt); inst.Sections.AddRange(sections); - + + inst.ILRange = instructions[i - 1].ILRange; instructions[i].ReplaceWith(inst); instructions.RemoveAt(i + 1); instructions.RemoveAt(i - 1); @@ -493,10 +497,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms instructions[i + 1].ReplaceWith(inst); if (keepAssignmentBefore) { // delete if (comp(ldloc switchValueVar == ldnull)) + inst.ILRange = instructions[i].ILRange; instructions.RemoveAt(i); i--; } else { // delete both the if and the assignment before + inst.ILRange = instructions[i - 1].ILRange; instructions.RemoveRange(i - 1, 2); i -= 2; } @@ -711,6 +717,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms var stringToInt = new StringToInt(switchValue, stringValues); var inst = new SwitchInstruction(stringToInt); inst.Sections.AddRange(sections); + inst.ILRange = block.Instructions[i].ILRange; block.Instructions[i].ReplaceWith(inst); block.Instructions.RemoveRange(i + 1, 3); info.Transformed = true; @@ -808,9 +815,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms newSwitch.Sections.Add(new SwitchSection { Labels = defaultLabel, Body = defaultSection.Body }); instructions[i].ReplaceWith(newSwitch); if (keepAssignmentBefore) { + newSwitch.ILRange = instructions[i - 1].ILRange; instructions.RemoveAt(i - 1); i--; } else { + newSwitch.ILRange = instructions[i - 2].ILRange; instructions.RemoveRange(i - 2, 2); i -= 2; } diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs index 23535e578..3b75093b2 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs @@ -152,11 +152,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (!ReadParameters(instruction.Arguments[1], parameterList, parameterVariablesList, new SimpleTypeResolveContext(context.Function.Method))) return (null, SpecialType.UnknownType); var container = new BlockContainer(); + container.ILRange = instruction.ILRange; var functionType = instruction.Method.ReturnType.TypeArguments[0]; var returnType = functionType.GetDelegateInvokeMethod()?.ReturnType; var function = new ILFunction(returnType, parameterList, context.Function.GenericContext, container); function.DelegateType = functionType; function.Variables.AddRange(parameterVariablesList); + function.ILRange = instruction.ILRange; lambdaStack.Push(function); var (bodyInstruction, type) = ConvertInstruction(instruction.Arguments[0]); lambdaStack.Pop(); From ab9397d0990b14b6e3a99f4d4abfa84c4a8234c1 Mon Sep 17 00:00:00 2001 From: Chicken-Bones Date: Sun, 2 Sep 2018 13:16:46 +1000 Subject: [PATCH 2/2] Add ReduceNestingTransform --- .../ICSharpCode.Decompiler.Tests.csproj | 1 + .../PrettyTestRunner.cs | 6 + .../TestCases/Pretty/ExpressionTrees.cs | 82 +- .../TestCases/Pretty/ReduceNesting.cs | 270 +++++ .../TestCases/Pretty/ReduceNesting.il | 949 +++++++++++++++++ .../TestCases/Pretty/ReduceNesting.opt.il | 650 ++++++++++++ .../Pretty/ReduceNesting.opt.roslyn.il | 668 ++++++++++++ .../TestCases/Pretty/ReduceNesting.roslyn.il | 954 ++++++++++++++++++ .../CSharp/CSharpDecompiler.cs | 1 + .../ICSharpCode.Decompiler.csproj | 1 + .../IL/Transforms/ReduceNestingTransform.cs | 418 ++++++++ 11 files changed, 3959 insertions(+), 41 deletions(-) create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.cs create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.il create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.opt.il create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.opt.roslyn.il create mode 100644 ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.roslyn.il create mode 100644 ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index 229eea694..390649a39 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -73,6 +73,7 @@ + diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs index 285f3a86c..ec3a5eb64 100644 --- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs @@ -127,6 +127,12 @@ namespace ICSharpCode.Decompiler.Tests }); } + [Test] + public void ReduceNesting([ValueSource("defaultOptions")] CSharpCompilerOptions cscOptions) + { + RunForLibrary(cscOptions: cscOptions); + } + [Test] public void DelegateConstruction([ValueSource("defaultOptions")] CSharpCompilerOptions cscOptions) { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs index 727680634..bde2e1d55 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs @@ -322,47 +322,47 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { if (ID == 0) { ViewBag.data = "''"; - } else { - var model = (from a in db.Contracts - where a.ID == ID - select new { - ID = a.ID, - ContractNo = a.ContractNo, - HouseAddress = a.HouseAddress, - AdminID = (from b in db.Administrator - where b.ID == a.AdminID - select b.TrueName).FirstOrDefault(), - StoreID = (from b in db.Store - where b.ID == a.StoreID - select b.Name).FirstOrDefault(), - SigningTime = a.SigningTime, - YeWuPhone = (from b in db.Administrator - where b.ID == a.AdminID - select b.Phone).FirstOrDefault(), - BuyerName = a.BuyerName, - BuyerTelephone = a.BuyerTelephone, - Customer = a.Customer, - CustTelephone = a.CustTelephone, - Credit = (from b in db.Loan - where b.ContractNo == a.ContractNo - select b.Credit).FirstOrDefault(), - LoanBank = (from b in db.Loan - where b.ContractNo == a.ContractNo - select b.LoanBank).FirstOrDefault(), - Remarks = (from b in db.Loan - where b.ContractNo == a.ContractNo - select b.Remarks).FirstOrDefault() - }).FirstOrDefault(); - ViewBag.data = model.ToJson(); - DateTime? dateTime = (from b in db.Loan - where b.ContractNo == model.ContractNo - select b.ShenDate).FirstOrDefault(); - DateTime? dateTime2 = (from b in db.Loan - where b.ContractNo == model.ContractNo - select b.LoanDate).FirstOrDefault(); - ViewBag.ShenDate = ((!dateTime.HasValue) ? "" : dateTime.ParseDateTime().ToString("yyyy-MM-dd")); - ViewBag.LoanDate = ((!dateTime2.HasValue) ? "" : dateTime2.ParseDateTime().ToString("yyyy-MM-dd")); - } + return; + } + var model = (from a in db.Contracts + where a.ID == ID + select new { + ID = a.ID, + ContractNo = a.ContractNo, + HouseAddress = a.HouseAddress, + AdminID = (from b in db.Administrator + where b.ID == a.AdminID + select b.TrueName).FirstOrDefault(), + StoreID = (from b in db.Store + where b.ID == a.StoreID + select b.Name).FirstOrDefault(), + SigningTime = a.SigningTime, + YeWuPhone = (from b in db.Administrator + where b.ID == a.AdminID + select b.Phone).FirstOrDefault(), + BuyerName = a.BuyerName, + BuyerTelephone = a.BuyerTelephone, + Customer = a.Customer, + CustTelephone = a.CustTelephone, + Credit = (from b in db.Loan + where b.ContractNo == a.ContractNo + select b.Credit).FirstOrDefault(), + LoanBank = (from b in db.Loan + where b.ContractNo == a.ContractNo + select b.LoanBank).FirstOrDefault(), + Remarks = (from b in db.Loan + where b.ContractNo == a.ContractNo + select b.Remarks).FirstOrDefault() + }).FirstOrDefault(); + ViewBag.data = model.ToJson(); + DateTime? dateTime = (from b in db.Loan + where b.ContractNo == model.ContractNo + select b.ShenDate).FirstOrDefault(); + DateTime? dateTime2 = (from b in db.Loan + where b.ContractNo == model.ContractNo + select b.LoanDate).FirstOrDefault(); + ViewBag.ShenDate = ((!dateTime.HasValue) ? "" : dateTime.ParseDateTime().ToString("yyyy-MM-dd")); + ViewBag.LoanDate = ((!dateTime2.HasValue) ? "" : dateTime2.ParseDateTime().ToString("yyyy-MM-dd")); } private static object ToCode(object x, Expression> expr) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.cs new file mode 100644 index 000000000..a08cd43e9 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.cs @@ -0,0 +1,270 @@ +using System; + +namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty +{ + public abstract class ReduceNesting + { + public abstract bool B(int i); + public abstract int I(int i); + + public void IfIf() + { + if (B(0)) { + Console.WriteLine(0); + return; + } + + if (B(1)) { + Console.WriteLine(1); + } + + Console.WriteLine("end"); + } + + public void IfSwitch() + { + if (B(0)) { + Console.WriteLine(0); + return; + } + + Console.WriteLine("switch"); + switch (I(0)) { + case 0: + Console.WriteLine("case 0"); + break; + case 1: + Console.WriteLine("case 1"); + break; + default: + Console.WriteLine("end"); + break; + } + } + + public void IfSwitchSwitch() + { + if (B(0)) { + Console.WriteLine(0); + return; + } + + Console.WriteLine("switch 0"); + switch (I(1)) { + case 0: + Console.WriteLine("case 0"); + return; + case 1: + Console.WriteLine("case 1"); + return; + } + + Console.WriteLine("switch 1"); + switch (I(1)) { + case 0: + Console.WriteLine("case 0"); + break; + case 1: + Console.WriteLine("case 1"); + break; + default: + Console.WriteLine("end"); + break; + } + } + + public void IfLoop() + { + if (B(0)) { + Console.WriteLine(0); + return; + } + + for (int i = 0; i < 10; i++) { + Console.WriteLine(i); + } + + Console.WriteLine("end"); + } + + public void LoopContinue() + { + for (int i = 0; i < 10; i++) { + Console.WriteLine(i); + if (B(0)) { + Console.WriteLine(0); + continue; + } + + if (B(1)) { + Console.WriteLine(1); + } + Console.WriteLine("loop-tail"); + } + } + + public void LoopBreak() + { + for (int i = 0; i < 10; i++) { + Console.WriteLine(i); + if (B(0)) { + Console.WriteLine(0); + continue; + } + + if (B(1)) { + Console.WriteLine(1); + break; + } + + if (B(2)) { + Console.WriteLine(2); + } + + Console.WriteLine("break"); + break; + } + Console.WriteLine("end"); + } + + public void LoopBreakElseIf() + { + for (int i = 0; i < 10; i++) { + Console.WriteLine(i); + if (B(0)) { + Console.WriteLine(0); + continue; + } + + if (B(1)) { + Console.WriteLine(1); + } else if (B(2)) { + Console.WriteLine(2); + } + break; + } + Console.WriteLine("end"); + } + + public void SwitchIf() + { + switch (I(0)) { + case 0: + Console.WriteLine("case 0"); + return; + case 1: + Console.WriteLine("case 1"); + return; + } + + if (B(0)) { + Console.WriteLine(0); + } + Console.WriteLine("end"); + } + + public void NestedSwitchIf() + { + if (B(0)) { + switch (I(0)) { + case 0: + Console.WriteLine("case 0"); + return; + case 1: + Console.WriteLine("case 1"); + return; + } + + if (B(1)) { + Console.WriteLine(1); + } + } else { + Console.WriteLine("else"); + } + } + + // nesting should not be reduced as maximum nesting level is 1 + public void EarlyExit1() + { + if (!B(0)) { + for (int i = 0; i < 10; i++) { + Console.WriteLine(i); + } + Console.WriteLine("end"); + } + } + + // nesting should not be reduced as maximum nesting level is 2 + public void EarlyExit2() + { + if (B(0)) { + return; + } + + for (int i = 0; i < 10; i++) { + Console.WriteLine(i); + if (i % 2 == 0) { + Console.WriteLine("even"); + } + } + + Console.WriteLine("end"); + } + + // nesting should not be reduced as maximum nesting level is 1 and the else block has no more instructions than any other block + public void BalancedIf() + { + if (B(0)) { + Console.WriteLine("true"); + if (B(1)) { + Console.WriteLine(1); + } + } else { + if (B(2)) { + Console.WriteLine(2); + } + Console.WriteLine("false"); + } + } + + public string ComplexCase1(string s) + { + if (B(0)) { + return s; + } + + for (int i = 0; i < s.Length; i++) { + if (B(1)) { + Console.WriteLine(1); + } else if (B(2)) { + switch (i) { + case 1: + if (B(3)) { + Console.WriteLine(3); + break; + } + + Console.WriteLine("case1"); + if (B(4)) { + Console.WriteLine(4); + } + break; + case 2: + case 3: + Console.WriteLine("case23"); + break; + } + Console.WriteLine(2); + } else if (B(5)) { + Console.WriteLine(5); + } else { + if (B(6)) { + Console.WriteLine(6); + } + Console.WriteLine("else"); + } + } + return s; + } + } +} diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.il new file mode 100644 index 000000000..b4493229c --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.il @@ -0,0 +1,949 @@ + + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 4:0:0:0 +} +.assembly ReduceNesting +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + .permissionset reqmin + = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module ReduceNesting.dll +.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) +.imagebase 0x10000000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public abstract auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting + extends [mscorlib]System.Object +{ + .method public hidebysig newslot abstract virtual + instance bool B(int32 i) cil managed + { + } // end of method ReduceNesting::B + + .method public hidebysig newslot abstract virtual + instance int32 I(int32 i) cil managed + { + } // end of method ReduceNesting::I + + .method public hidebysig instance void + IfIf() cil managed + { + // Code size 60 (0x3c) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.0 + IL_000c: ldloc.0 + IL_000d: brtrue.s IL_0019 + + IL_000f: nop + IL_0010: ldc.i4.0 + IL_0011: call void [mscorlib]System.Console::WriteLine(int32) + IL_0016: nop + IL_0017: br.s IL_003b + + IL_0019: ldarg.0 + IL_001a: ldc.i4.1 + IL_001b: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0020: ldc.i4.0 + IL_0021: ceq + IL_0023: stloc.0 + IL_0024: ldloc.0 + IL_0025: brtrue.s IL_0030 + + IL_0027: nop + IL_0028: ldc.i4.1 + IL_0029: call void [mscorlib]System.Console::WriteLine(int32) + IL_002e: nop + IL_002f: nop + IL_0030: ldstr "end" + IL_0035: call void [mscorlib]System.Console::WriteLine(string) + IL_003a: nop + IL_003b: ret + } // end of method ReduceNesting::IfIf + + .method public hidebysig instance void + IfSwitch() cil managed + { + // Code size 100 (0x64) + .maxstack 2 + .locals init (bool V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.0 + IL_000c: ldloc.0 + IL_000d: brtrue.s IL_0019 + + IL_000f: nop + IL_0010: ldc.i4.0 + IL_0011: call void [mscorlib]System.Console::WriteLine(int32) + IL_0016: nop + IL_0017: br.s IL_0063 + + IL_0019: ldstr "switch" + IL_001e: call void [mscorlib]System.Console::WriteLine(string) + IL_0023: nop + IL_0024: ldarg.0 + IL_0025: ldc.i4.0 + IL_0026: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_002b: stloc.1 + IL_002c: ldloc.1 + IL_002d: switch ( + IL_003c, + IL_0049) + IL_003a: br.s IL_0056 + + IL_003c: ldstr "case 0" + IL_0041: call void [mscorlib]System.Console::WriteLine(string) + IL_0046: nop + IL_0047: br.s IL_0063 + + IL_0049: ldstr "case 1" + IL_004e: call void [mscorlib]System.Console::WriteLine(string) + IL_0053: nop + IL_0054: br.s IL_0063 + + IL_0056: ldstr "end" + IL_005b: call void [mscorlib]System.Console::WriteLine(string) + IL_0060: nop + IL_0061: br.s IL_0063 + + IL_0063: ret + } // end of method ReduceNesting::IfSwitch + + .method public hidebysig instance void + IfSwitchSwitch() cil managed + { + // Code size 164 (0xa4) + .maxstack 2 + .locals init (bool V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.0 + IL_000c: ldloc.0 + IL_000d: brtrue.s IL_001c + + IL_000f: nop + IL_0010: ldc.i4.0 + IL_0011: call void [mscorlib]System.Console::WriteLine(int32) + IL_0016: nop + IL_0017: br IL_00a3 + + IL_001c: ldstr "switch 0" + IL_0021: call void [mscorlib]System.Console::WriteLine(string) + IL_0026: nop + IL_0027: ldarg.0 + IL_0028: ldc.i4.1 + IL_0029: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_002e: stloc.1 + IL_002f: ldloc.1 + IL_0030: switch ( + IL_003f, + IL_004c) + IL_003d: br.s IL_0059 + + IL_003f: ldstr "case 0" + IL_0044: call void [mscorlib]System.Console::WriteLine(string) + IL_0049: nop + IL_004a: br.s IL_00a3 + + IL_004c: ldstr "case 1" + IL_0051: call void [mscorlib]System.Console::WriteLine(string) + IL_0056: nop + IL_0057: br.s IL_00a3 + + IL_0059: ldstr "switch 1" + IL_005e: call void [mscorlib]System.Console::WriteLine(string) + IL_0063: nop + IL_0064: ldarg.0 + IL_0065: ldc.i4.1 + IL_0066: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_006b: stloc.1 + IL_006c: ldloc.1 + IL_006d: switch ( + IL_007c, + IL_0089) + IL_007a: br.s IL_0096 + + IL_007c: ldstr "case 0" + IL_0081: call void [mscorlib]System.Console::WriteLine(string) + IL_0086: nop + IL_0087: br.s IL_00a3 + + IL_0089: ldstr "case 1" + IL_008e: call void [mscorlib]System.Console::WriteLine(string) + IL_0093: nop + IL_0094: br.s IL_00a3 + + IL_0096: ldstr "end" + IL_009b: call void [mscorlib]System.Console::WriteLine(string) + IL_00a0: nop + IL_00a1: br.s IL_00a3 + + IL_00a3: ret + } // end of method ReduceNesting::IfSwitchSwitch + + .method public hidebysig instance void + IfLoop() cil managed + { + // Code size 63 (0x3f) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.1 + IL_000c: ldloc.1 + IL_000d: brtrue.s IL_0019 + + IL_000f: nop + IL_0010: ldc.i4.0 + IL_0011: call void [mscorlib]System.Console::WriteLine(int32) + IL_0016: nop + IL_0017: br.s IL_003e + + IL_0019: ldc.i4.0 + IL_001a: stloc.0 + IL_001b: br.s IL_002a + + IL_001d: nop + IL_001e: ldloc.0 + IL_001f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0024: nop + IL_0025: nop + IL_0026: ldloc.0 + IL_0027: ldc.i4.1 + IL_0028: add + IL_0029: stloc.0 + IL_002a: ldloc.0 + IL_002b: ldc.i4.s 10 + IL_002d: clt + IL_002f: stloc.1 + IL_0030: ldloc.1 + IL_0031: brtrue.s IL_001d + + IL_0033: ldstr "end" + IL_0038: call void [mscorlib]System.Console::WriteLine(string) + IL_003d: nop + IL_003e: ret + } // end of method ReduceNesting::IfLoop + + .method public hidebysig instance void + LoopContinue() cil managed + { + // Code size 86 (0x56) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_004c + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: call void [mscorlib]System.Console::WriteLine(int32) + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: ldc.i4.0 + IL_000f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0014: ldc.i4.0 + IL_0015: ceq + IL_0017: stloc.1 + IL_0018: ldloc.1 + IL_0019: brtrue.s IL_0025 + + IL_001b: nop + IL_001c: ldc.i4.0 + IL_001d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0022: nop + IL_0023: br.s IL_0048 + + IL_0025: ldarg.0 + IL_0026: ldc.i4.1 + IL_0027: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_002c: ldc.i4.0 + IL_002d: ceq + IL_002f: stloc.1 + IL_0030: ldloc.1 + IL_0031: brtrue.s IL_003c + + IL_0033: nop + IL_0034: ldc.i4.1 + IL_0035: call void [mscorlib]System.Console::WriteLine(int32) + IL_003a: nop + IL_003b: nop + IL_003c: ldstr "loop-tail" + IL_0041: call void [mscorlib]System.Console::WriteLine(string) + IL_0046: nop + IL_0047: nop + IL_0048: ldloc.0 + IL_0049: ldc.i4.1 + IL_004a: add + IL_004b: stloc.0 + IL_004c: ldloc.0 + IL_004d: ldc.i4.s 10 + IL_004f: clt + IL_0051: stloc.1 + IL_0052: ldloc.1 + IL_0053: brtrue.s IL_0005 + + IL_0055: ret + } // end of method ReduceNesting::LoopContinue + + .method public hidebysig instance void + LoopBreak() cil managed + { + // Code size 122 (0x7a) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0065 + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: call void [mscorlib]System.Console::WriteLine(int32) + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: ldc.i4.0 + IL_000f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0014: ldc.i4.0 + IL_0015: ceq + IL_0017: stloc.1 + IL_0018: ldloc.1 + IL_0019: brtrue.s IL_0025 + + IL_001b: nop + IL_001c: ldc.i4.0 + IL_001d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0022: nop + IL_0023: br.s IL_0061 + + IL_0025: ldarg.0 + IL_0026: ldc.i4.1 + IL_0027: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_002c: ldc.i4.0 + IL_002d: ceq + IL_002f: stloc.1 + IL_0030: ldloc.1 + IL_0031: brtrue.s IL_003d + + IL_0033: nop + IL_0034: ldc.i4.1 + IL_0035: call void [mscorlib]System.Console::WriteLine(int32) + IL_003a: nop + IL_003b: br.s IL_006e + + IL_003d: ldarg.0 + IL_003e: ldc.i4.2 + IL_003f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0044: ldc.i4.0 + IL_0045: ceq + IL_0047: stloc.1 + IL_0048: ldloc.1 + IL_0049: brtrue.s IL_0054 + + IL_004b: nop + IL_004c: ldc.i4.2 + IL_004d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0052: nop + IL_0053: nop + IL_0054: ldstr "break" + IL_0059: call void [mscorlib]System.Console::WriteLine(string) + IL_005e: nop + IL_005f: br.s IL_006e + + IL_0061: ldloc.0 + IL_0062: ldc.i4.1 + IL_0063: add + IL_0064: stloc.0 + IL_0065: ldloc.0 + IL_0066: ldc.i4.s 10 + IL_0068: clt + IL_006a: stloc.1 + IL_006b: ldloc.1 + IL_006c: brtrue.s IL_0005 + + IL_006e: ldstr "end" + IL_0073: call void [mscorlib]System.Console::WriteLine(string) + IL_0078: nop + IL_0079: ret + } // end of method ReduceNesting::LoopBreak + + .method public hidebysig instance void + LoopBreakElseIf() cil managed + { + // Code size 112 (0x70) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_005b + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: call void [mscorlib]System.Console::WriteLine(int32) + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: ldc.i4.0 + IL_000f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0014: ldc.i4.0 + IL_0015: ceq + IL_0017: stloc.1 + IL_0018: ldloc.1 + IL_0019: brtrue.s IL_0025 + + IL_001b: nop + IL_001c: ldc.i4.0 + IL_001d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0022: nop + IL_0023: br.s IL_0057 + + IL_0025: ldarg.0 + IL_0026: ldc.i4.1 + IL_0027: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_002c: ldc.i4.0 + IL_002d: ceq + IL_002f: stloc.1 + IL_0030: ldloc.1 + IL_0031: brtrue.s IL_003e + + IL_0033: nop + IL_0034: ldc.i4.1 + IL_0035: call void [mscorlib]System.Console::WriteLine(int32) + IL_003a: nop + IL_003b: nop + IL_003c: br.s IL_0055 + + IL_003e: ldarg.0 + IL_003f: ldc.i4.2 + IL_0040: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0045: ldc.i4.0 + IL_0046: ceq + IL_0048: stloc.1 + IL_0049: ldloc.1 + IL_004a: brtrue.s IL_0055 + + IL_004c: nop + IL_004d: ldc.i4.2 + IL_004e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0053: nop + IL_0054: nop + IL_0055: br.s IL_0064 + + IL_0057: ldloc.0 + IL_0058: ldc.i4.1 + IL_0059: add + IL_005a: stloc.0 + IL_005b: ldloc.0 + IL_005c: ldc.i4.s 10 + IL_005e: clt + IL_0060: stloc.1 + IL_0061: ldloc.1 + IL_0062: brtrue.s IL_0005 + + IL_0064: ldstr "end" + IL_0069: call void [mscorlib]System.Console::WriteLine(string) + IL_006e: nop + IL_006f: ret + } // end of method ReduceNesting::LoopBreakElseIf + + .method public hidebysig instance void + SwitchIf() cil managed + { + // Code size 86 (0x56) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: switch ( + IL_0019, + IL_0026) + IL_0017: br.s IL_0033 + + IL_0019: ldstr "case 0" + IL_001e: call void [mscorlib]System.Console::WriteLine(string) + IL_0023: nop + IL_0024: br.s IL_0055 + + IL_0026: ldstr "case 1" + IL_002b: call void [mscorlib]System.Console::WriteLine(string) + IL_0030: nop + IL_0031: br.s IL_0055 + + IL_0033: ldarg.0 + IL_0034: ldc.i4.0 + IL_0035: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_003a: ldc.i4.0 + IL_003b: ceq + IL_003d: stloc.1 + IL_003e: ldloc.1 + IL_003f: brtrue.s IL_004a + + IL_0041: nop + IL_0042: ldc.i4.0 + IL_0043: call void [mscorlib]System.Console::WriteLine(int32) + IL_0048: nop + IL_0049: nop + IL_004a: ldstr "end" + IL_004f: call void [mscorlib]System.Console::WriteLine(string) + IL_0054: nop + IL_0055: ret + } // end of method ReduceNesting::SwitchIf + + .method public hidebysig instance void + NestedSwitchIf() cil managed + { + // Code size 106 (0x6a) + .maxstack 2 + .locals init (bool V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.0 + IL_000c: ldloc.0 + IL_000d: brtrue.s IL_005c + + IL_000f: nop + IL_0010: ldarg.0 + IL_0011: ldc.i4.0 + IL_0012: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0017: stloc.1 + IL_0018: ldloc.1 + IL_0019: switch ( + IL_0028, + IL_0035) + IL_0026: br.s IL_0042 + + IL_0028: ldstr "case 0" + IL_002d: call void [mscorlib]System.Console::WriteLine(string) + IL_0032: nop + IL_0033: br.s IL_0069 + + IL_0035: ldstr "case 1" + IL_003a: call void [mscorlib]System.Console::WriteLine(string) + IL_003f: nop + IL_0040: br.s IL_0069 + + IL_0042: ldarg.0 + IL_0043: ldc.i4.1 + IL_0044: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0049: ldc.i4.0 + IL_004a: ceq + IL_004c: stloc.0 + IL_004d: ldloc.0 + IL_004e: brtrue.s IL_0059 + + IL_0050: nop + IL_0051: ldc.i4.1 + IL_0052: call void [mscorlib]System.Console::WriteLine(int32) + IL_0057: nop + IL_0058: nop + IL_0059: nop + IL_005a: br.s IL_0069 + + IL_005c: nop + IL_005d: ldstr "else" + IL_0062: call void [mscorlib]System.Console::WriteLine(string) + IL_0067: nop + IL_0068: nop + IL_0069: ret + } // end of method ReduceNesting::NestedSwitchIf + + .method public hidebysig instance void + EarlyExit1() cil managed + { + // Code size 52 (0x34) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.1 + IL_0009: ldloc.1 + IL_000a: brtrue.s IL_0033 + + IL_000c: nop + IL_000d: ldc.i4.0 + IL_000e: stloc.0 + IL_000f: br.s IL_001e + + IL_0011: nop + IL_0012: ldloc.0 + IL_0013: call void [mscorlib]System.Console::WriteLine(int32) + IL_0018: nop + IL_0019: nop + IL_001a: ldloc.0 + IL_001b: ldc.i4.1 + IL_001c: add + IL_001d: stloc.0 + IL_001e: ldloc.0 + IL_001f: ldc.i4.s 10 + IL_0021: clt + IL_0023: stloc.1 + IL_0024: ldloc.1 + IL_0025: brtrue.s IL_0011 + + IL_0027: ldstr "end" + IL_002c: call void [mscorlib]System.Console::WriteLine(string) + IL_0031: nop + IL_0032: nop + IL_0033: ret + } // end of method ReduceNesting::EarlyExit1 + + .method public hidebysig instance void + EarlyExit2() cil managed + { + // Code size 82 (0x52) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.1 + IL_000c: ldloc.1 + IL_000d: brtrue.s IL_0012 + + IL_000f: nop + IL_0010: br.s IL_0051 + + IL_0012: ldc.i4.0 + IL_0013: stloc.0 + IL_0014: br.s IL_003d + + IL_0016: nop + IL_0017: ldloc.0 + IL_0018: call void [mscorlib]System.Console::WriteLine(int32) + IL_001d: nop + IL_001e: ldloc.0 + IL_001f: ldc.i4.2 + IL_0020: rem + IL_0021: ldc.i4.0 + IL_0022: ceq + IL_0024: ldc.i4.0 + IL_0025: ceq + IL_0027: stloc.1 + IL_0028: ldloc.1 + IL_0029: brtrue.s IL_0038 + + IL_002b: nop + IL_002c: ldstr "even" + IL_0031: call void [mscorlib]System.Console::WriteLine(string) + IL_0036: nop + IL_0037: nop + IL_0038: nop + IL_0039: ldloc.0 + IL_003a: ldc.i4.1 + IL_003b: add + IL_003c: stloc.0 + IL_003d: ldloc.0 + IL_003e: ldc.i4.s 10 + IL_0040: clt + IL_0042: stloc.1 + IL_0043: ldloc.1 + IL_0044: brtrue.s IL_0016 + + IL_0046: ldstr "end" + IL_004b: call void [mscorlib]System.Console::WriteLine(string) + IL_0050: nop + IL_0051: ret + } // end of method ReduceNesting::EarlyExit2 + + .method public hidebysig instance void + BalancedIf() cil managed + { + // Code size 90 (0x5a) + .maxstack 2 + .locals init (bool V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.0 + IL_000c: ldloc.0 + IL_000d: brtrue.s IL_0035 + + IL_000f: nop + IL_0010: ldstr "true" + IL_0015: call void [mscorlib]System.Console::WriteLine(string) + IL_001a: nop + IL_001b: ldarg.0 + IL_001c: ldc.i4.1 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0022: ldc.i4.0 + IL_0023: ceq + IL_0025: stloc.0 + IL_0026: ldloc.0 + IL_0027: brtrue.s IL_0032 + + IL_0029: nop + IL_002a: ldc.i4.1 + IL_002b: call void [mscorlib]System.Console::WriteLine(int32) + IL_0030: nop + IL_0031: nop + IL_0032: nop + IL_0033: br.s IL_0059 + + IL_0035: nop + IL_0036: ldarg.0 + IL_0037: ldc.i4.2 + IL_0038: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_003d: ldc.i4.0 + IL_003e: ceq + IL_0040: stloc.0 + IL_0041: ldloc.0 + IL_0042: brtrue.s IL_004d + + IL_0044: nop + IL_0045: ldc.i4.2 + IL_0046: call void [mscorlib]System.Console::WriteLine(int32) + IL_004b: nop + IL_004c: nop + IL_004d: ldstr "false" + IL_0052: call void [mscorlib]System.Console::WriteLine(string) + IL_0057: nop + IL_0058: nop + IL_0059: ret + } // end of method ReduceNesting::BalancedIf + + .method public hidebysig instance string + ComplexCase1(string s) cil managed + { + // Code size 269 (0x10d) + .maxstack 2 + .locals init (int32 V_0, + string V_1, + bool V_2, + int32 V_3) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.2 + IL_000c: ldloc.2 + IL_000d: brtrue.s IL_0017 + + IL_000f: nop + IL_0010: ldarg.1 + IL_0011: stloc.1 + IL_0012: br IL_010b + + IL_0017: ldc.i4.0 + IL_0018: stloc.0 + IL_0019: br IL_00f7 + + IL_001e: nop + IL_001f: ldarg.0 + IL_0020: ldc.i4.1 + IL_0021: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0026: ldc.i4.0 + IL_0027: ceq + IL_0029: stloc.2 + IL_002a: ldloc.2 + IL_002b: brtrue.s IL_003b + + IL_002d: nop + IL_002e: ldc.i4.1 + IL_002f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0034: nop + IL_0035: nop + IL_0036: br IL_00f2 + + IL_003b: ldarg.0 + IL_003c: ldc.i4.2 + IL_003d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0042: ldc.i4.0 + IL_0043: ceq + IL_0045: stloc.2 + IL_0046: ldloc.2 + IL_0047: brtrue.s IL_00b5 + + IL_0049: nop + IL_004a: ldloc.0 + IL_004b: stloc.3 + IL_004c: ldloc.3 + IL_004d: ldc.i4.1 + IL_004e: sub + IL_004f: switch ( + IL_0062, + IL_009e, + IL_009e) + IL_0060: br.s IL_00ab + + IL_0062: ldarg.0 + IL_0063: ldc.i4.3 + IL_0064: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0069: ldc.i4.0 + IL_006a: ceq + IL_006c: stloc.2 + IL_006d: ldloc.2 + IL_006e: brtrue.s IL_007a + + IL_0070: nop + IL_0071: ldc.i4.3 + IL_0072: call void [mscorlib]System.Console::WriteLine(int32) + IL_0077: nop + IL_0078: br.s IL_00ab + + IL_007a: ldstr "case1" + IL_007f: call void [mscorlib]System.Console::WriteLine(string) + IL_0084: nop + IL_0085: ldarg.0 + IL_0086: ldc.i4.4 + IL_0087: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_008c: ldc.i4.0 + IL_008d: ceq + IL_008f: stloc.2 + IL_0090: ldloc.2 + IL_0091: brtrue.s IL_009c + + IL_0093: nop + IL_0094: ldc.i4.4 + IL_0095: call void [mscorlib]System.Console::WriteLine(int32) + IL_009a: nop + IL_009b: nop + IL_009c: br.s IL_00ab + + IL_009e: ldstr "case23" + IL_00a3: call void [mscorlib]System.Console::WriteLine(string) + IL_00a8: nop + IL_00a9: br.s IL_00ab + + IL_00ab: ldc.i4.2 + IL_00ac: call void [mscorlib]System.Console::WriteLine(int32) + IL_00b1: nop + IL_00b2: nop + IL_00b3: br.s IL_00f2 + + IL_00b5: ldarg.0 + IL_00b6: ldc.i4.5 + IL_00b7: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_00bc: ldc.i4.0 + IL_00bd: ceq + IL_00bf: stloc.2 + IL_00c0: ldloc.2 + IL_00c1: brtrue.s IL_00ce + + IL_00c3: nop + IL_00c4: ldc.i4.5 + IL_00c5: call void [mscorlib]System.Console::WriteLine(int32) + IL_00ca: nop + IL_00cb: nop + IL_00cc: br.s IL_00f2 + + IL_00ce: nop + IL_00cf: ldarg.0 + IL_00d0: ldc.i4.6 + IL_00d1: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_00d6: ldc.i4.0 + IL_00d7: ceq + IL_00d9: stloc.2 + IL_00da: ldloc.2 + IL_00db: brtrue.s IL_00e6 + + IL_00dd: nop + IL_00de: ldc.i4.6 + IL_00df: call void [mscorlib]System.Console::WriteLine(int32) + IL_00e4: nop + IL_00e5: nop + IL_00e6: ldstr "else" + IL_00eb: call void [mscorlib]System.Console::WriteLine(string) + IL_00f0: nop + IL_00f1: nop + IL_00f2: nop + IL_00f3: ldloc.0 + IL_00f4: ldc.i4.1 + IL_00f5: add + IL_00f6: stloc.0 + IL_00f7: ldloc.0 + IL_00f8: ldarg.1 + IL_00f9: callvirt instance int32 [mscorlib]System.String::get_Length() + IL_00fe: clt + IL_0100: stloc.2 + IL_0101: ldloc.2 + IL_0102: brtrue IL_001e + + IL_0107: ldarg.1 + IL_0108: stloc.1 + IL_0109: br.s IL_010b + + IL_010b: ldloc.1 + IL_010c: ret + } // end of method ReduceNesting::ComplexCase1 + + .method family hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method ReduceNesting::.ctor + +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.opt.il new file mode 100644 index 000000000..4a5b3e019 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.opt.il @@ -0,0 +1,650 @@ + + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 4:0:0:0 +} +.assembly ReduceNesting.opt +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + .permissionset reqmin + = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module ReduceNesting.opt.dll +.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) +.imagebase 0x10000000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public abstract auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting + extends [mscorlib]System.Object +{ + .method public hidebysig newslot abstract virtual + instance bool B(int32 i) cil managed + { + } // end of method ReduceNesting::B + + .method public hidebysig newslot abstract virtual + instance int32 I(int32 i) cil managed + { + } // end of method ReduceNesting::I + + .method public hidebysig instance void + IfIf() cil managed + { + // Code size 42 (0x2a) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0010 + + IL_0009: ldc.i4.0 + IL_000a: call void [mscorlib]System.Console::WriteLine(int32) + IL_000f: ret + + IL_0010: ldarg.0 + IL_0011: ldc.i4.1 + IL_0012: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0017: brfalse.s IL_001f + + IL_0019: ldc.i4.1 + IL_001a: call void [mscorlib]System.Console::WriteLine(int32) + IL_001f: ldstr "end" + IL_0024: call void [mscorlib]System.Console::WriteLine(string) + IL_0029: ret + } // end of method ReduceNesting::IfIf + + .method public hidebysig instance void + IfSwitch() cil managed + { + // Code size 83 (0x53) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0010 + + IL_0009: ldc.i4.0 + IL_000a: call void [mscorlib]System.Console::WriteLine(int32) + IL_000f: ret + + IL_0010: ldstr "switch" + IL_0015: call void [mscorlib]System.Console::WriteLine(string) + IL_001a: ldarg.0 + IL_001b: ldc.i4.0 + IL_001c: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0021: stloc.0 + IL_0022: ldloc.0 + IL_0023: switch ( + IL_0032, + IL_003d) + IL_0030: br.s IL_0048 + + IL_0032: ldstr "case 0" + IL_0037: call void [mscorlib]System.Console::WriteLine(string) + IL_003c: ret + + IL_003d: ldstr "case 1" + IL_0042: call void [mscorlib]System.Console::WriteLine(string) + IL_0047: ret + + IL_0048: ldstr "end" + IL_004d: call void [mscorlib]System.Console::WriteLine(string) + IL_0052: ret + } // end of method ReduceNesting::IfSwitch + + .method public hidebysig instance void + IfSwitchSwitch() cil managed + { + // Code size 139 (0x8b) + .maxstack 2 + .locals init (int32 V_0, + int32 V_1) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0010 + + IL_0009: ldc.i4.0 + IL_000a: call void [mscorlib]System.Console::WriteLine(int32) + IL_000f: ret + + IL_0010: ldstr "switch 0" + IL_0015: call void [mscorlib]System.Console::WriteLine(string) + IL_001a: ldarg.0 + IL_001b: ldc.i4.1 + IL_001c: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0021: stloc.0 + IL_0022: ldloc.0 + IL_0023: switch ( + IL_0032, + IL_003d) + IL_0030: br.s IL_0048 + + IL_0032: ldstr "case 0" + IL_0037: call void [mscorlib]System.Console::WriteLine(string) + IL_003c: ret + + IL_003d: ldstr "case 1" + IL_0042: call void [mscorlib]System.Console::WriteLine(string) + IL_0047: ret + + IL_0048: ldstr "switch 1" + IL_004d: call void [mscorlib]System.Console::WriteLine(string) + IL_0052: ldarg.0 + IL_0053: ldc.i4.1 + IL_0054: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0059: stloc.1 + IL_005a: ldloc.1 + IL_005b: switch ( + IL_006a, + IL_0075) + IL_0068: br.s IL_0080 + + IL_006a: ldstr "case 0" + IL_006f: call void [mscorlib]System.Console::WriteLine(string) + IL_0074: ret + + IL_0075: ldstr "case 1" + IL_007a: call void [mscorlib]System.Console::WriteLine(string) + IL_007f: ret + + IL_0080: ldstr "end" + IL_0085: call void [mscorlib]System.Console::WriteLine(string) + IL_008a: ret + } // end of method ReduceNesting::IfSwitchSwitch + + .method public hidebysig instance void + IfLoop() cil managed + { + // Code size 46 (0x2e) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0010 + + IL_0009: ldc.i4.0 + IL_000a: call void [mscorlib]System.Console::WriteLine(int32) + IL_000f: ret + + IL_0010: ldc.i4.0 + IL_0011: stloc.0 + IL_0012: br.s IL_001e + + IL_0014: ldloc.0 + IL_0015: call void [mscorlib]System.Console::WriteLine(int32) + IL_001a: ldloc.0 + IL_001b: ldc.i4.1 + IL_001c: add + IL_001d: stloc.0 + IL_001e: ldloc.0 + IL_001f: ldc.i4.s 10 + IL_0021: blt.s IL_0014 + + IL_0023: ldstr "end" + IL_0028: call void [mscorlib]System.Console::WriteLine(string) + IL_002d: ret + } // end of method ReduceNesting::IfLoop + + .method public hidebysig instance void + LoopContinue() cil managed + { + // Code size 62 (0x3e) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br.s IL_0038 + + IL_0004: ldloc.0 + IL_0005: call void [mscorlib]System.Console::WriteLine(int32) + IL_000a: ldarg.0 + IL_000b: ldc.i4.0 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0011: brfalse.s IL_001b + + IL_0013: ldc.i4.0 + IL_0014: call void [mscorlib]System.Console::WriteLine(int32) + IL_0019: br.s IL_0034 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.1 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0022: brfalse.s IL_002a + + IL_0024: ldc.i4.1 + IL_0025: call void [mscorlib]System.Console::WriteLine(int32) + IL_002a: ldstr "loop-tail" + IL_002f: call void [mscorlib]System.Console::WriteLine(string) + IL_0034: ldloc.0 + IL_0035: ldc.i4.1 + IL_0036: add + IL_0037: stloc.0 + IL_0038: ldloc.0 + IL_0039: ldc.i4.s 10 + IL_003b: blt.s IL_0004 + + IL_003d: ret + } // end of method ReduceNesting::LoopContinue + + .method public hidebysig instance void + LoopBreak() cil managed + { + // Code size 91 (0x5b) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br.s IL_004b + + IL_0004: ldloc.0 + IL_0005: call void [mscorlib]System.Console::WriteLine(int32) + IL_000a: ldarg.0 + IL_000b: ldc.i4.0 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0011: brfalse.s IL_001b + + IL_0013: ldc.i4.0 + IL_0014: call void [mscorlib]System.Console::WriteLine(int32) + IL_0019: br.s IL_0047 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.1 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0022: brfalse.s IL_002c + + IL_0024: ldc.i4.1 + IL_0025: call void [mscorlib]System.Console::WriteLine(int32) + IL_002a: br.s IL_0050 + + IL_002c: ldarg.0 + IL_002d: ldc.i4.2 + IL_002e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0033: brfalse.s IL_003b + + IL_0035: ldc.i4.2 + IL_0036: call void [mscorlib]System.Console::WriteLine(int32) + IL_003b: ldstr "break" + IL_0040: call void [mscorlib]System.Console::WriteLine(string) + IL_0045: br.s IL_0050 + + IL_0047: ldloc.0 + IL_0048: ldc.i4.1 + IL_0049: add + IL_004a: stloc.0 + IL_004b: ldloc.0 + IL_004c: ldc.i4.s 10 + IL_004e: blt.s IL_0004 + + IL_0050: ldstr "end" + IL_0055: call void [mscorlib]System.Console::WriteLine(string) + IL_005a: ret + } // end of method ReduceNesting::LoopBreak + + .method public hidebysig instance void + LoopBreakElseIf() cil managed + { + // Code size 81 (0x51) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br.s IL_0041 + + IL_0004: ldloc.0 + IL_0005: call void [mscorlib]System.Console::WriteLine(int32) + IL_000a: ldarg.0 + IL_000b: ldc.i4.0 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0011: brfalse.s IL_001b + + IL_0013: ldc.i4.0 + IL_0014: call void [mscorlib]System.Console::WriteLine(int32) + IL_0019: br.s IL_003d + + IL_001b: ldarg.0 + IL_001c: ldc.i4.1 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0022: brfalse.s IL_002c + + IL_0024: ldc.i4.1 + IL_0025: call void [mscorlib]System.Console::WriteLine(int32) + IL_002a: br.s IL_0046 + + IL_002c: ldarg.0 + IL_002d: ldc.i4.2 + IL_002e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0033: brfalse.s IL_0046 + + IL_0035: ldc.i4.2 + IL_0036: call void [mscorlib]System.Console::WriteLine(int32) + IL_003b: br.s IL_0046 + + IL_003d: ldloc.0 + IL_003e: ldc.i4.1 + IL_003f: add + IL_0040: stloc.0 + IL_0041: ldloc.0 + IL_0042: ldc.i4.s 10 + IL_0044: blt.s IL_0004 + + IL_0046: ldstr "end" + IL_004b: call void [mscorlib]System.Console::WriteLine(string) + IL_0050: ret + } // end of method ReduceNesting::LoopBreakElseIf + + .method public hidebysig instance void + SwitchIf() cil managed + { + // Code size 72 (0x48) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: switch ( + IL_0018, + IL_0023) + IL_0016: br.s IL_002e + + IL_0018: ldstr "case 0" + IL_001d: call void [mscorlib]System.Console::WriteLine(string) + IL_0022: ret + + IL_0023: ldstr "case 1" + IL_0028: call void [mscorlib]System.Console::WriteLine(string) + IL_002d: ret + + IL_002e: ldarg.0 + IL_002f: ldc.i4.0 + IL_0030: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0035: brfalse.s IL_003d + + IL_0037: ldc.i4.0 + IL_0038: call void [mscorlib]System.Console::WriteLine(int32) + IL_003d: ldstr "end" + IL_0042: call void [mscorlib]System.Console::WriteLine(string) + IL_0047: ret + } // end of method ReduceNesting::SwitchIf + + .method public hidebysig instance void + NestedSwitchIf() cil managed + { + // Code size 82 (0x52) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0047 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.0 + IL_000b: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0010: stloc.0 + IL_0011: ldloc.0 + IL_0012: switch ( + IL_0021, + IL_002c) + IL_001f: br.s IL_0037 + + IL_0021: ldstr "case 0" + IL_0026: call void [mscorlib]System.Console::WriteLine(string) + IL_002b: ret + + IL_002c: ldstr "case 1" + IL_0031: call void [mscorlib]System.Console::WriteLine(string) + IL_0036: ret + + IL_0037: ldarg.0 + IL_0038: ldc.i4.1 + IL_0039: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_003e: brfalse.s IL_0051 + + IL_0040: ldc.i4.1 + IL_0041: call void [mscorlib]System.Console::WriteLine(int32) + IL_0046: ret + + IL_0047: ldstr "else" + IL_004c: call void [mscorlib]System.Console::WriteLine(string) + IL_0051: ret + } // end of method ReduceNesting::NestedSwitchIf + + .method public hidebysig instance void + EarlyExit1() cil managed + { + // Code size 39 (0x27) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brtrue.s IL_0026 + + IL_0009: ldc.i4.0 + IL_000a: stloc.0 + IL_000b: br.s IL_0017 + + IL_000d: ldloc.0 + IL_000e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0013: ldloc.0 + IL_0014: ldc.i4.1 + IL_0015: add + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: ldc.i4.s 10 + IL_001a: blt.s IL_000d + + IL_001c: ldstr "end" + IL_0021: call void [mscorlib]System.Console::WriteLine(string) + IL_0026: ret + } // end of method ReduceNesting::EarlyExit1 + + .method public hidebysig instance void + EarlyExit2() cil managed + { + // Code size 55 (0x37) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_000a + + IL_0009: ret + + IL_000a: ldc.i4.0 + IL_000b: stloc.0 + IL_000c: br.s IL_0027 + + IL_000e: ldloc.0 + IL_000f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0014: ldloc.0 + IL_0015: ldc.i4.2 + IL_0016: rem + IL_0017: brtrue.s IL_0023 + + IL_0019: ldstr "even" + IL_001e: call void [mscorlib]System.Console::WriteLine(string) + IL_0023: ldloc.0 + IL_0024: ldc.i4.1 + IL_0025: add + IL_0026: stloc.0 + IL_0027: ldloc.0 + IL_0028: ldc.i4.s 10 + IL_002a: blt.s IL_000e + + IL_002c: ldstr "end" + IL_0031: call void [mscorlib]System.Console::WriteLine(string) + IL_0036: ret + } // end of method ReduceNesting::EarlyExit2 + + .method public hidebysig instance void + BalancedIf() cil managed + { + // Code size 61 (0x3d) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0023 + + IL_0009: ldstr "true" + IL_000e: call void [mscorlib]System.Console::WriteLine(string) + IL_0013: ldarg.0 + IL_0014: ldc.i4.1 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_001a: brfalse.s IL_003c + + IL_001c: ldc.i4.1 + IL_001d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0022: ret + + IL_0023: ldarg.0 + IL_0024: ldc.i4.2 + IL_0025: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_002a: brfalse.s IL_0032 + + IL_002c: ldc.i4.2 + IL_002d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0032: ldstr "false" + IL_0037: call void [mscorlib]System.Console::WriteLine(string) + IL_003c: ret + } // end of method ReduceNesting::BalancedIf + + .method public hidebysig instance string + ComplexCase1(string s) cil managed + { + // Code size 193 (0xc1) + .maxstack 2 + .locals init (int32 V_0, + int32 V_1) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_000b + + IL_0009: ldarg.1 + IL_000a: ret + + IL_000b: ldc.i4.0 + IL_000c: stloc.0 + IL_000d: br IL_00b3 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.1 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0019: brfalse.s IL_0026 + + IL_001b: ldc.i4.1 + IL_001c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0021: br IL_00af + + IL_0026: ldarg.0 + IL_0027: ldc.i4.2 + IL_0028: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_002d: brfalse.s IL_0085 + + IL_002f: ldloc.0 + IL_0030: stloc.1 + IL_0031: ldloc.1 + IL_0032: ldc.i4.1 + IL_0033: sub + IL_0034: switch ( + IL_0047, + IL_0073, + IL_0073) + IL_0045: br.s IL_007d + + IL_0047: ldarg.0 + IL_0048: ldc.i4.3 + IL_0049: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_004e: brfalse.s IL_0058 + + IL_0050: ldc.i4.3 + IL_0051: call void [mscorlib]System.Console::WriteLine(int32) + IL_0056: br.s IL_007d + + IL_0058: ldstr "case1" + IL_005d: call void [mscorlib]System.Console::WriteLine(string) + IL_0062: ldarg.0 + IL_0063: ldc.i4.4 + IL_0064: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0069: brfalse.s IL_007d + + IL_006b: ldc.i4.4 + IL_006c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0071: br.s IL_007d + + IL_0073: ldstr "case23" + IL_0078: call void [mscorlib]System.Console::WriteLine(string) + IL_007d: ldc.i4.2 + IL_007e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0083: br.s IL_00af + + IL_0085: ldarg.0 + IL_0086: ldc.i4.5 + IL_0087: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_008c: brfalse.s IL_0096 + + IL_008e: ldc.i4.5 + IL_008f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0094: br.s IL_00af + + IL_0096: ldarg.0 + IL_0097: ldc.i4.6 + IL_0098: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_009d: brfalse.s IL_00a5 + + IL_009f: ldc.i4.6 + IL_00a0: call void [mscorlib]System.Console::WriteLine(int32) + IL_00a5: ldstr "else" + IL_00aa: call void [mscorlib]System.Console::WriteLine(string) + IL_00af: ldloc.0 + IL_00b0: ldc.i4.1 + IL_00b1: add + IL_00b2: stloc.0 + IL_00b3: ldloc.0 + IL_00b4: ldarg.1 + IL_00b5: callvirt instance int32 [mscorlib]System.String::get_Length() + IL_00ba: blt IL_0012 + + IL_00bf: ldarg.1 + IL_00c0: ret + } // end of method ReduceNesting::ComplexCase1 + + .method family hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method ReduceNesting::.ctor + +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.opt.roslyn.il new file mode 100644 index 000000000..e257c826a --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.opt.roslyn.il @@ -0,0 +1,668 @@ + + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 4:0:0:0 +} +.assembly ReduceNesting +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + + // --- The following custom attribute is added automatically, do not uncomment ------- + // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 ) + + .permissionset reqmin + = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module ReduceNesting.dll +.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) +.imagebase 0x10000000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public abstract auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting + extends [mscorlib]System.Object +{ + .method public hidebysig newslot abstract virtual + instance bool B(int32 i) cil managed + { + } // end of method ReduceNesting::B + + .method public hidebysig newslot abstract virtual + instance int32 I(int32 i) cil managed + { + } // end of method ReduceNesting::I + + .method public hidebysig instance void + IfIf() cil managed + { + // Code size 42 (0x2a) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0010 + + IL_0009: ldc.i4.0 + IL_000a: call void [mscorlib]System.Console::WriteLine(int32) + IL_000f: ret + + IL_0010: ldarg.0 + IL_0011: ldc.i4.1 + IL_0012: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0017: brfalse.s IL_001f + + IL_0019: ldc.i4.1 + IL_001a: call void [mscorlib]System.Console::WriteLine(int32) + IL_001f: ldstr "end" + IL_0024: call void [mscorlib]System.Console::WriteLine(string) + IL_0029: ret + } // end of method ReduceNesting::IfIf + + .method public hidebysig instance void + IfSwitch() cil managed + { + // Code size 76 (0x4c) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0010 + + IL_0009: ldc.i4.0 + IL_000a: call void [mscorlib]System.Console::WriteLine(int32) + IL_000f: ret + + IL_0010: ldstr "switch" + IL_0015: call void [mscorlib]System.Console::WriteLine(string) + IL_001a: ldarg.0 + IL_001b: ldc.i4.0 + IL_001c: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0021: stloc.0 + IL_0022: ldloc.0 + IL_0023: brfalse.s IL_002b + + IL_0025: ldloc.0 + IL_0026: ldc.i4.1 + IL_0027: beq.s IL_0036 + + IL_0029: br.s IL_0041 + + IL_002b: ldstr "case 0" + IL_0030: call void [mscorlib]System.Console::WriteLine(string) + IL_0035: ret + + IL_0036: ldstr "case 1" + IL_003b: call void [mscorlib]System.Console::WriteLine(string) + IL_0040: ret + + IL_0041: ldstr "end" + IL_0046: call void [mscorlib]System.Console::WriteLine(string) + IL_004b: ret + } // end of method ReduceNesting::IfSwitch + + .method public hidebysig instance void + IfSwitchSwitch() cil managed + { + // Code size 125 (0x7d) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0010 + + IL_0009: ldc.i4.0 + IL_000a: call void [mscorlib]System.Console::WriteLine(int32) + IL_000f: ret + + IL_0010: ldstr "switch 0" + IL_0015: call void [mscorlib]System.Console::WriteLine(string) + IL_001a: ldarg.0 + IL_001b: ldc.i4.1 + IL_001c: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0021: stloc.0 + IL_0022: ldloc.0 + IL_0023: brfalse.s IL_002b + + IL_0025: ldloc.0 + IL_0026: ldc.i4.1 + IL_0027: beq.s IL_0036 + + IL_0029: br.s IL_0041 + + IL_002b: ldstr "case 0" + IL_0030: call void [mscorlib]System.Console::WriteLine(string) + IL_0035: ret + + IL_0036: ldstr "case 1" + IL_003b: call void [mscorlib]System.Console::WriteLine(string) + IL_0040: ret + + IL_0041: ldstr "switch 1" + IL_0046: call void [mscorlib]System.Console::WriteLine(string) + IL_004b: ldarg.0 + IL_004c: ldc.i4.1 + IL_004d: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0052: stloc.0 + IL_0053: ldloc.0 + IL_0054: brfalse.s IL_005c + + IL_0056: ldloc.0 + IL_0057: ldc.i4.1 + IL_0058: beq.s IL_0067 + + IL_005a: br.s IL_0072 + + IL_005c: ldstr "case 0" + IL_0061: call void [mscorlib]System.Console::WriteLine(string) + IL_0066: ret + + IL_0067: ldstr "case 1" + IL_006c: call void [mscorlib]System.Console::WriteLine(string) + IL_0071: ret + + IL_0072: ldstr "end" + IL_0077: call void [mscorlib]System.Console::WriteLine(string) + IL_007c: ret + } // end of method ReduceNesting::IfSwitchSwitch + + .method public hidebysig instance void + IfLoop() cil managed + { + // Code size 46 (0x2e) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0010 + + IL_0009: ldc.i4.0 + IL_000a: call void [mscorlib]System.Console::WriteLine(int32) + IL_000f: ret + + IL_0010: ldc.i4.0 + IL_0011: stloc.0 + IL_0012: br.s IL_001e + + IL_0014: ldloc.0 + IL_0015: call void [mscorlib]System.Console::WriteLine(int32) + IL_001a: ldloc.0 + IL_001b: ldc.i4.1 + IL_001c: add + IL_001d: stloc.0 + IL_001e: ldloc.0 + IL_001f: ldc.i4.s 10 + IL_0021: blt.s IL_0014 + + IL_0023: ldstr "end" + IL_0028: call void [mscorlib]System.Console::WriteLine(string) + IL_002d: ret + } // end of method ReduceNesting::IfLoop + + .method public hidebysig instance void + LoopContinue() cil managed + { + // Code size 62 (0x3e) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br.s IL_0038 + + IL_0004: ldloc.0 + IL_0005: call void [mscorlib]System.Console::WriteLine(int32) + IL_000a: ldarg.0 + IL_000b: ldc.i4.0 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0011: brfalse.s IL_001b + + IL_0013: ldc.i4.0 + IL_0014: call void [mscorlib]System.Console::WriteLine(int32) + IL_0019: br.s IL_0034 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.1 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0022: brfalse.s IL_002a + + IL_0024: ldc.i4.1 + IL_0025: call void [mscorlib]System.Console::WriteLine(int32) + IL_002a: ldstr "loop-tail" + IL_002f: call void [mscorlib]System.Console::WriteLine(string) + IL_0034: ldloc.0 + IL_0035: ldc.i4.1 + IL_0036: add + IL_0037: stloc.0 + IL_0038: ldloc.0 + IL_0039: ldc.i4.s 10 + IL_003b: blt.s IL_0004 + + IL_003d: ret + } // end of method ReduceNesting::LoopContinue + + .method public hidebysig instance void + LoopBreak() cil managed + { + // Code size 91 (0x5b) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br.s IL_004b + + IL_0004: ldloc.0 + IL_0005: call void [mscorlib]System.Console::WriteLine(int32) + IL_000a: ldarg.0 + IL_000b: ldc.i4.0 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0011: brfalse.s IL_001b + + IL_0013: ldc.i4.0 + IL_0014: call void [mscorlib]System.Console::WriteLine(int32) + IL_0019: br.s IL_0047 + + IL_001b: ldarg.0 + IL_001c: ldc.i4.1 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0022: brfalse.s IL_002c + + IL_0024: ldc.i4.1 + IL_0025: call void [mscorlib]System.Console::WriteLine(int32) + IL_002a: br.s IL_0050 + + IL_002c: ldarg.0 + IL_002d: ldc.i4.2 + IL_002e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0033: brfalse.s IL_003b + + IL_0035: ldc.i4.2 + IL_0036: call void [mscorlib]System.Console::WriteLine(int32) + IL_003b: ldstr "break" + IL_0040: call void [mscorlib]System.Console::WriteLine(string) + IL_0045: br.s IL_0050 + + IL_0047: ldloc.0 + IL_0048: ldc.i4.1 + IL_0049: add + IL_004a: stloc.0 + IL_004b: ldloc.0 + IL_004c: ldc.i4.s 10 + IL_004e: blt.s IL_0004 + + IL_0050: ldstr "end" + IL_0055: call void [mscorlib]System.Console::WriteLine(string) + IL_005a: ret + } // end of method ReduceNesting::LoopBreak + + .method public hidebysig instance void + LoopBreakElseIf() cil managed + { + // Code size 81 (0x51) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldc.i4.0 + IL_0001: stloc.0 + IL_0002: br.s IL_0041 + + IL_0004: ldloc.0 + IL_0005: call void [mscorlib]System.Console::WriteLine(int32) + IL_000a: ldarg.0 + IL_000b: ldc.i4.0 + IL_000c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0011: brfalse.s IL_001b + + IL_0013: ldc.i4.0 + IL_0014: call void [mscorlib]System.Console::WriteLine(int32) + IL_0019: br.s IL_003d + + IL_001b: ldarg.0 + IL_001c: ldc.i4.1 + IL_001d: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0022: brfalse.s IL_002c + + IL_0024: ldc.i4.1 + IL_0025: call void [mscorlib]System.Console::WriteLine(int32) + IL_002a: br.s IL_0046 + + IL_002c: ldarg.0 + IL_002d: ldc.i4.2 + IL_002e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0033: brfalse.s IL_0046 + + IL_0035: ldc.i4.2 + IL_0036: call void [mscorlib]System.Console::WriteLine(int32) + IL_003b: br.s IL_0046 + + IL_003d: ldloc.0 + IL_003e: ldc.i4.1 + IL_003f: add + IL_0040: stloc.0 + IL_0041: ldloc.0 + IL_0042: ldc.i4.s 10 + IL_0044: blt.s IL_0004 + + IL_0046: ldstr "end" + IL_004b: call void [mscorlib]System.Console::WriteLine(string) + IL_0050: ret + } // end of method ReduceNesting::LoopBreakElseIf + + .method public hidebysig instance void + SwitchIf() cil managed + { + // Code size 65 (0x41) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: brfalse.s IL_0011 + + IL_000b: ldloc.0 + IL_000c: ldc.i4.1 + IL_000d: beq.s IL_001c + + IL_000f: br.s IL_0027 + + IL_0011: ldstr "case 0" + IL_0016: call void [mscorlib]System.Console::WriteLine(string) + IL_001b: ret + + IL_001c: ldstr "case 1" + IL_0021: call void [mscorlib]System.Console::WriteLine(string) + IL_0026: ret + + IL_0027: ldarg.0 + IL_0028: ldc.i4.0 + IL_0029: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_002e: brfalse.s IL_0036 + + IL_0030: ldc.i4.0 + IL_0031: call void [mscorlib]System.Console::WriteLine(int32) + IL_0036: ldstr "end" + IL_003b: call void [mscorlib]System.Console::WriteLine(string) + IL_0040: ret + } // end of method ReduceNesting::SwitchIf + + .method public hidebysig instance void + NestedSwitchIf() cil managed + { + // Code size 75 (0x4b) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0040 + + IL_0009: ldarg.0 + IL_000a: ldc.i4.0 + IL_000b: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0010: stloc.0 + IL_0011: ldloc.0 + IL_0012: brfalse.s IL_001a + + IL_0014: ldloc.0 + IL_0015: ldc.i4.1 + IL_0016: beq.s IL_0025 + + IL_0018: br.s IL_0030 + + IL_001a: ldstr "case 0" + IL_001f: call void [mscorlib]System.Console::WriteLine(string) + IL_0024: ret + + IL_0025: ldstr "case 1" + IL_002a: call void [mscorlib]System.Console::WriteLine(string) + IL_002f: ret + + IL_0030: ldarg.0 + IL_0031: ldc.i4.1 + IL_0032: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0037: brfalse.s IL_004a + + IL_0039: ldc.i4.1 + IL_003a: call void [mscorlib]System.Console::WriteLine(int32) + IL_003f: ret + + IL_0040: ldstr "else" + IL_0045: call void [mscorlib]System.Console::WriteLine(string) + IL_004a: ret + } // end of method ReduceNesting::NestedSwitchIf + + .method public hidebysig instance void + EarlyExit1() cil managed + { + // Code size 39 (0x27) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brtrue.s IL_0026 + + IL_0009: ldc.i4.0 + IL_000a: stloc.0 + IL_000b: br.s IL_0017 + + IL_000d: ldloc.0 + IL_000e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0013: ldloc.0 + IL_0014: ldc.i4.1 + IL_0015: add + IL_0016: stloc.0 + IL_0017: ldloc.0 + IL_0018: ldc.i4.s 10 + IL_001a: blt.s IL_000d + + IL_001c: ldstr "end" + IL_0021: call void [mscorlib]System.Console::WriteLine(string) + IL_0026: ret + } // end of method ReduceNesting::EarlyExit1 + + .method public hidebysig instance void + EarlyExit2() cil managed + { + // Code size 55 (0x37) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_000a + + IL_0009: ret + + IL_000a: ldc.i4.0 + IL_000b: stloc.0 + IL_000c: br.s IL_0027 + + IL_000e: ldloc.0 + IL_000f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0014: ldloc.0 + IL_0015: ldc.i4.2 + IL_0016: rem + IL_0017: brtrue.s IL_0023 + + IL_0019: ldstr "even" + IL_001e: call void [mscorlib]System.Console::WriteLine(string) + IL_0023: ldloc.0 + IL_0024: ldc.i4.1 + IL_0025: add + IL_0026: stloc.0 + IL_0027: ldloc.0 + IL_0028: ldc.i4.s 10 + IL_002a: blt.s IL_000e + + IL_002c: ldstr "end" + IL_0031: call void [mscorlib]System.Console::WriteLine(string) + IL_0036: ret + } // end of method ReduceNesting::EarlyExit2 + + .method public hidebysig instance void + BalancedIf() cil managed + { + // Code size 61 (0x3d) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_0023 + + IL_0009: ldstr "true" + IL_000e: call void [mscorlib]System.Console::WriteLine(string) + IL_0013: ldarg.0 + IL_0014: ldc.i4.1 + IL_0015: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_001a: brfalse.s IL_003c + + IL_001c: ldc.i4.1 + IL_001d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0022: ret + + IL_0023: ldarg.0 + IL_0024: ldc.i4.2 + IL_0025: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_002a: brfalse.s IL_0032 + + IL_002c: ldc.i4.2 + IL_002d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0032: ldstr "false" + IL_0037: call void [mscorlib]System.Console::WriteLine(string) + IL_003c: ret + } // end of method ReduceNesting::BalancedIf + + .method public hidebysig instance string + ComplexCase1(string s) cil managed + { + // Code size 178 (0xb2) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: ldarg.0 + IL_0001: ldc.i4.0 + IL_0002: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0007: brfalse.s IL_000b + + IL_0009: ldarg.1 + IL_000a: ret + + IL_000b: ldc.i4.0 + IL_000c: stloc.0 + IL_000d: br IL_00a4 + + IL_0012: ldarg.0 + IL_0013: ldc.i4.1 + IL_0014: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0019: brfalse.s IL_0023 + + IL_001b: ldc.i4.1 + IL_001c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0021: br.s IL_00a0 + + IL_0023: ldarg.0 + IL_0024: ldc.i4.2 + IL_0025: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_002a: brfalse.s IL_0076 + + IL_002c: ldloc.0 + IL_002d: ldc.i4.1 + IL_002e: beq.s IL_0038 + + IL_0030: ldloc.0 + IL_0031: ldc.i4.2 + IL_0032: sub + IL_0033: ldc.i4.1 + IL_0034: ble.un.s IL_0064 + + IL_0036: br.s IL_006e + + IL_0038: ldarg.0 + IL_0039: ldc.i4.3 + IL_003a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_003f: brfalse.s IL_0049 + + IL_0041: ldc.i4.3 + IL_0042: call void [mscorlib]System.Console::WriteLine(int32) + IL_0047: br.s IL_006e + + IL_0049: ldstr "case1" + IL_004e: call void [mscorlib]System.Console::WriteLine(string) + IL_0053: ldarg.0 + IL_0054: ldc.i4.4 + IL_0055: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_005a: brfalse.s IL_006e + + IL_005c: ldc.i4.4 + IL_005d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0062: br.s IL_006e + + IL_0064: ldstr "case23" + IL_0069: call void [mscorlib]System.Console::WriteLine(string) + IL_006e: ldc.i4.2 + IL_006f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0074: br.s IL_00a0 + + IL_0076: ldarg.0 + IL_0077: ldc.i4.5 + IL_0078: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_007d: brfalse.s IL_0087 + + IL_007f: ldc.i4.5 + IL_0080: call void [mscorlib]System.Console::WriteLine(int32) + IL_0085: br.s IL_00a0 + + IL_0087: ldarg.0 + IL_0088: ldc.i4.6 + IL_0089: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_008e: brfalse.s IL_0096 + + IL_0090: ldc.i4.6 + IL_0091: call void [mscorlib]System.Console::WriteLine(int32) + IL_0096: ldstr "else" + IL_009b: call void [mscorlib]System.Console::WriteLine(string) + IL_00a0: ldloc.0 + IL_00a1: ldc.i4.1 + IL_00a2: add + IL_00a3: stloc.0 + IL_00a4: ldloc.0 + IL_00a5: ldarg.1 + IL_00a6: callvirt instance int32 [mscorlib]System.String::get_Length() + IL_00ab: blt IL_0012 + + IL_00b0: ldarg.1 + IL_00b1: ret + } // end of method ReduceNesting::ComplexCase1 + + .method family hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method ReduceNesting::.ctor + +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.roslyn.il new file mode 100644 index 000000000..c4058adaf --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ReduceNesting.roslyn.il @@ -0,0 +1,954 @@ + + + + +// Metadata version: v4.0.30319 +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. + .ver 4:0:0:0 +} +.assembly ReduceNesting +{ + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) + .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx + 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. + + // --- The following custom attribute is added automatically, do not uncomment ------- + // .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) + + .permissionset reqmin + = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module ReduceNesting.dll +.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) +.imagebase 0x10000000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY + + +// =============== CLASS MEMBERS DECLARATION =================== + +.class public abstract auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting + extends [mscorlib]System.Object +{ + .method public hidebysig newslot abstract virtual + instance bool B(int32 i) cil managed + { + } // end of method ReduceNesting::B + + .method public hidebysig newslot abstract virtual + instance int32 I(int32 i) cil managed + { + } // end of method ReduceNesting::I + + .method public hidebysig instance void + IfIf() cil managed + { + // Code size 54 (0x36) + .maxstack 2 + .locals init (bool V_0, + bool V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_0016 + + IL_000c: nop + IL_000d: ldc.i4.0 + IL_000e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0013: nop + IL_0014: br.s IL_0035 + + IL_0016: ldarg.0 + IL_0017: ldc.i4.1 + IL_0018: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_001d: stloc.1 + IL_001e: ldloc.1 + IL_001f: brfalse.s IL_002a + + IL_0021: nop + IL_0022: ldc.i4.1 + IL_0023: call void [mscorlib]System.Console::WriteLine(int32) + IL_0028: nop + IL_0029: nop + IL_002a: ldstr "end" + IL_002f: call void [mscorlib]System.Console::WriteLine(string) + IL_0034: nop + IL_0035: ret + } // end of method ReduceNesting::IfIf + + .method public hidebysig instance void + IfSwitch() cil managed + { + // Code size 92 (0x5c) + .maxstack 2 + .locals init (bool V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_0016 + + IL_000c: nop + IL_000d: ldc.i4.0 + IL_000e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0013: nop + IL_0014: br.s IL_005b + + IL_0016: ldstr "switch" + IL_001b: call void [mscorlib]System.Console::WriteLine(string) + IL_0020: nop + IL_0021: ldarg.0 + IL_0022: ldc.i4.0 + IL_0023: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0028: stloc.1 + IL_0029: ldloc.1 + IL_002a: brfalse.s IL_0034 + + IL_002c: br.s IL_002e + + IL_002e: ldloc.1 + IL_002f: ldc.i4.1 + IL_0030: beq.s IL_0041 + + IL_0032: br.s IL_004e + + IL_0034: ldstr "case 0" + IL_0039: call void [mscorlib]System.Console::WriteLine(string) + IL_003e: nop + IL_003f: br.s IL_005b + + IL_0041: ldstr "case 1" + IL_0046: call void [mscorlib]System.Console::WriteLine(string) + IL_004b: nop + IL_004c: br.s IL_005b + + IL_004e: ldstr "end" + IL_0053: call void [mscorlib]System.Console::WriteLine(string) + IL_0058: nop + IL_0059: br.s IL_005b + + IL_005b: ret + } // end of method ReduceNesting::IfSwitch + + .method public hidebysig instance void + IfSwitchSwitch() cil managed + { + // Code size 148 (0x94) + .maxstack 2 + .locals init (bool V_0, + int32 V_1, + int32 V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_0016 + + IL_000c: nop + IL_000d: ldc.i4.0 + IL_000e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0013: nop + IL_0014: br.s IL_0093 + + IL_0016: ldstr "switch 0" + IL_001b: call void [mscorlib]System.Console::WriteLine(string) + IL_0020: nop + IL_0021: ldarg.0 + IL_0022: ldc.i4.1 + IL_0023: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0028: stloc.1 + IL_0029: ldloc.1 + IL_002a: brfalse.s IL_0034 + + IL_002c: br.s IL_002e + + IL_002e: ldloc.1 + IL_002f: ldc.i4.1 + IL_0030: beq.s IL_0041 + + IL_0032: br.s IL_004e + + IL_0034: ldstr "case 0" + IL_0039: call void [mscorlib]System.Console::WriteLine(string) + IL_003e: nop + IL_003f: br.s IL_0093 + + IL_0041: ldstr "case 1" + IL_0046: call void [mscorlib]System.Console::WriteLine(string) + IL_004b: nop + IL_004c: br.s IL_0093 + + IL_004e: ldstr "switch 1" + IL_0053: call void [mscorlib]System.Console::WriteLine(string) + IL_0058: nop + IL_0059: ldarg.0 + IL_005a: ldc.i4.1 + IL_005b: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0060: stloc.2 + IL_0061: ldloc.2 + IL_0062: brfalse.s IL_006c + + IL_0064: br.s IL_0066 + + IL_0066: ldloc.2 + IL_0067: ldc.i4.1 + IL_0068: beq.s IL_0079 + + IL_006a: br.s IL_0086 + + IL_006c: ldstr "case 0" + IL_0071: call void [mscorlib]System.Console::WriteLine(string) + IL_0076: nop + IL_0077: br.s IL_0093 + + IL_0079: ldstr "case 1" + IL_007e: call void [mscorlib]System.Console::WriteLine(string) + IL_0083: nop + IL_0084: br.s IL_0093 + + IL_0086: ldstr "end" + IL_008b: call void [mscorlib]System.Console::WriteLine(string) + IL_0090: nop + IL_0091: br.s IL_0093 + + IL_0093: ret + } // end of method ReduceNesting::IfSwitchSwitch + + .method public hidebysig instance void + IfLoop() cil managed + { + // Code size 60 (0x3c) + .maxstack 2 + .locals init (bool V_0, + int32 V_1, + bool V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_0016 + + IL_000c: nop + IL_000d: ldc.i4.0 + IL_000e: call void [mscorlib]System.Console::WriteLine(int32) + IL_0013: nop + IL_0014: br.s IL_003b + + IL_0016: ldc.i4.0 + IL_0017: stloc.1 + IL_0018: br.s IL_0027 + + IL_001a: nop + IL_001b: ldloc.1 + IL_001c: call void [mscorlib]System.Console::WriteLine(int32) + IL_0021: nop + IL_0022: nop + IL_0023: ldloc.1 + IL_0024: ldc.i4.1 + IL_0025: add + IL_0026: stloc.1 + IL_0027: ldloc.1 + IL_0028: ldc.i4.s 10 + IL_002a: clt + IL_002c: stloc.2 + IL_002d: ldloc.2 + IL_002e: brtrue.s IL_001a + + IL_0030: ldstr "end" + IL_0035: call void [mscorlib]System.Console::WriteLine(string) + IL_003a: nop + IL_003b: ret + } // end of method ReduceNesting::IfLoop + + .method public hidebysig instance void + LoopContinue() cil managed + { + // Code size 80 (0x50) + .maxstack 2 + .locals init (int32 V_0, + bool V_1, + bool V_2, + bool V_3) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0046 + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: call void [mscorlib]System.Console::WriteLine(int32) + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: ldc.i4.0 + IL_000f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0014: stloc.1 + IL_0015: ldloc.1 + IL_0016: brfalse.s IL_0022 + + IL_0018: nop + IL_0019: ldc.i4.0 + IL_001a: call void [mscorlib]System.Console::WriteLine(int32) + IL_001f: nop + IL_0020: br.s IL_0042 + + IL_0022: ldarg.0 + IL_0023: ldc.i4.1 + IL_0024: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0029: stloc.2 + IL_002a: ldloc.2 + IL_002b: brfalse.s IL_0036 + + IL_002d: nop + IL_002e: ldc.i4.1 + IL_002f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0034: nop + IL_0035: nop + IL_0036: ldstr "loop-tail" + IL_003b: call void [mscorlib]System.Console::WriteLine(string) + IL_0040: nop + IL_0041: nop + IL_0042: ldloc.0 + IL_0043: ldc.i4.1 + IL_0044: add + IL_0045: stloc.0 + IL_0046: ldloc.0 + IL_0047: ldc.i4.s 10 + IL_0049: clt + IL_004b: stloc.3 + IL_004c: ldloc.3 + IL_004d: brtrue.s IL_0005 + + IL_004f: ret + } // end of method ReduceNesting::LoopContinue + + .method public hidebysig instance void + LoopBreak() cil managed + { + // Code size 115 (0x73) + .maxstack 2 + .locals init (int32 V_0, + bool V_1, + bool V_2, + bool V_3, + bool V_4) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_005c + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: call void [mscorlib]System.Console::WriteLine(int32) + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: ldc.i4.0 + IL_000f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0014: stloc.1 + IL_0015: ldloc.1 + IL_0016: brfalse.s IL_0022 + + IL_0018: nop + IL_0019: ldc.i4.0 + IL_001a: call void [mscorlib]System.Console::WriteLine(int32) + IL_001f: nop + IL_0020: br.s IL_0058 + + IL_0022: ldarg.0 + IL_0023: ldc.i4.1 + IL_0024: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0029: stloc.2 + IL_002a: ldloc.2 + IL_002b: brfalse.s IL_0037 + + IL_002d: nop + IL_002e: ldc.i4.1 + IL_002f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0034: nop + IL_0035: br.s IL_0067 + + IL_0037: ldarg.0 + IL_0038: ldc.i4.2 + IL_0039: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_003e: stloc.3 + IL_003f: ldloc.3 + IL_0040: brfalse.s IL_004b + + IL_0042: nop + IL_0043: ldc.i4.2 + IL_0044: call void [mscorlib]System.Console::WriteLine(int32) + IL_0049: nop + IL_004a: nop + IL_004b: ldstr "break" + IL_0050: call void [mscorlib]System.Console::WriteLine(string) + IL_0055: nop + IL_0056: br.s IL_0067 + + IL_0058: ldloc.0 + IL_0059: ldc.i4.1 + IL_005a: add + IL_005b: stloc.0 + IL_005c: ldloc.0 + IL_005d: ldc.i4.s 10 + IL_005f: clt + IL_0061: stloc.s V_4 + IL_0063: ldloc.s V_4 + IL_0065: brtrue.s IL_0005 + + IL_0067: ldstr "end" + IL_006c: call void [mscorlib]System.Console::WriteLine(string) + IL_0071: nop + IL_0072: ret + } // end of method ReduceNesting::LoopBreak + + .method public hidebysig instance void + LoopBreakElseIf() cil managed + { + // Code size 105 (0x69) + .maxstack 2 + .locals init (int32 V_0, + bool V_1, + bool V_2, + bool V_3, + bool V_4) + IL_0000: nop + IL_0001: ldc.i4.0 + IL_0002: stloc.0 + IL_0003: br.s IL_0052 + + IL_0005: nop + IL_0006: ldloc.0 + IL_0007: call void [mscorlib]System.Console::WriteLine(int32) + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: ldc.i4.0 + IL_000f: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0014: stloc.1 + IL_0015: ldloc.1 + IL_0016: brfalse.s IL_0022 + + IL_0018: nop + IL_0019: ldc.i4.0 + IL_001a: call void [mscorlib]System.Console::WriteLine(int32) + IL_001f: nop + IL_0020: br.s IL_004e + + IL_0022: ldarg.0 + IL_0023: ldc.i4.1 + IL_0024: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0029: stloc.2 + IL_002a: ldloc.2 + IL_002b: brfalse.s IL_0038 + + IL_002d: nop + IL_002e: ldc.i4.1 + IL_002f: call void [mscorlib]System.Console::WriteLine(int32) + IL_0034: nop + IL_0035: nop + IL_0036: br.s IL_004c + + IL_0038: ldarg.0 + IL_0039: ldc.i4.2 + IL_003a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_003f: stloc.3 + IL_0040: ldloc.3 + IL_0041: brfalse.s IL_004c + + IL_0043: nop + IL_0044: ldc.i4.2 + IL_0045: call void [mscorlib]System.Console::WriteLine(int32) + IL_004a: nop + IL_004b: nop + IL_004c: br.s IL_005d + + IL_004e: ldloc.0 + IL_004f: ldc.i4.1 + IL_0050: add + IL_0051: stloc.0 + IL_0052: ldloc.0 + IL_0053: ldc.i4.s 10 + IL_0055: clt + IL_0057: stloc.s V_4 + IL_0059: ldloc.s V_4 + IL_005b: brtrue.s IL_0005 + + IL_005d: ldstr "end" + IL_0062: call void [mscorlib]System.Console::WriteLine(string) + IL_0067: nop + IL_0068: ret + } // end of method ReduceNesting::LoopBreakElseIf + + .method public hidebysig instance void + SwitchIf() cil managed + { + // Code size 78 (0x4e) + .maxstack 2 + .locals init (int32 V_0, + bool V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_0014 + + IL_000c: br.s IL_000e + + IL_000e: ldloc.0 + IL_000f: ldc.i4.1 + IL_0010: beq.s IL_0021 + + IL_0012: br.s IL_002e + + IL_0014: ldstr "case 0" + IL_0019: call void [mscorlib]System.Console::WriteLine(string) + IL_001e: nop + IL_001f: br.s IL_004d + + IL_0021: ldstr "case 1" + IL_0026: call void [mscorlib]System.Console::WriteLine(string) + IL_002b: nop + IL_002c: br.s IL_004d + + IL_002e: ldarg.0 + IL_002f: ldc.i4.0 + IL_0030: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0035: stloc.1 + IL_0036: ldloc.1 + IL_0037: brfalse.s IL_0042 + + IL_0039: nop + IL_003a: ldc.i4.0 + IL_003b: call void [mscorlib]System.Console::WriteLine(int32) + IL_0040: nop + IL_0041: nop + IL_0042: ldstr "end" + IL_0047: call void [mscorlib]System.Console::WriteLine(string) + IL_004c: nop + IL_004d: ret + } // end of method ReduceNesting::SwitchIf + + .method public hidebysig instance void + NestedSwitchIf() cil managed + { + // Code size 95 (0x5f) + .maxstack 2 + .locals init (bool V_0, + int32 V_1, + bool V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_0051 + + IL_000c: nop + IL_000d: ldarg.0 + IL_000e: ldc.i4.0 + IL_000f: callvirt instance int32 ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::I(int32) + IL_0014: stloc.1 + IL_0015: ldloc.1 + IL_0016: brfalse.s IL_0020 + + IL_0018: br.s IL_001a + + IL_001a: ldloc.1 + IL_001b: ldc.i4.1 + IL_001c: beq.s IL_002d + + IL_001e: br.s IL_003a + + IL_0020: ldstr "case 0" + IL_0025: call void [mscorlib]System.Console::WriteLine(string) + IL_002a: nop + IL_002b: br.s IL_005e + + IL_002d: ldstr "case 1" + IL_0032: call void [mscorlib]System.Console::WriteLine(string) + IL_0037: nop + IL_0038: br.s IL_005e + + IL_003a: ldarg.0 + IL_003b: ldc.i4.1 + IL_003c: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0041: stloc.2 + IL_0042: ldloc.2 + IL_0043: brfalse.s IL_004e + + IL_0045: nop + IL_0046: ldc.i4.1 + IL_0047: call void [mscorlib]System.Console::WriteLine(int32) + IL_004c: nop + IL_004d: nop + IL_004e: nop + IL_004f: br.s IL_005e + + IL_0051: nop + IL_0052: ldstr "else" + IL_0057: call void [mscorlib]System.Console::WriteLine(string) + IL_005c: nop + IL_005d: nop + IL_005e: ret + } // end of method ReduceNesting::NestedSwitchIf + + .method public hidebysig instance void + EarlyExit1() cil managed + { + // Code size 55 (0x37) + .maxstack 2 + .locals init (bool V_0, + int32 V_1, + bool V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: ldc.i4.0 + IL_0009: ceq + IL_000b: stloc.0 + IL_000c: ldloc.0 + IL_000d: brfalse.s IL_0036 + + IL_000f: nop + IL_0010: ldc.i4.0 + IL_0011: stloc.1 + IL_0012: br.s IL_0021 + + IL_0014: nop + IL_0015: ldloc.1 + IL_0016: call void [mscorlib]System.Console::WriteLine(int32) + IL_001b: nop + IL_001c: nop + IL_001d: ldloc.1 + IL_001e: ldc.i4.1 + IL_001f: add + IL_0020: stloc.1 + IL_0021: ldloc.1 + IL_0022: ldc.i4.s 10 + IL_0024: clt + IL_0026: stloc.2 + IL_0027: ldloc.2 + IL_0028: brtrue.s IL_0014 + + IL_002a: ldstr "end" + IL_002f: call void [mscorlib]System.Console::WriteLine(string) + IL_0034: nop + IL_0035: nop + IL_0036: ret + } // end of method ReduceNesting::EarlyExit1 + + .method public hidebysig instance void + EarlyExit2() cil managed + { + // Code size 76 (0x4c) + .maxstack 2 + .locals init (bool V_0, + int32 V_1, + bool V_2, + bool V_3) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_000f + + IL_000c: nop + IL_000d: br.s IL_004b + + IL_000f: ldc.i4.0 + IL_0010: stloc.1 + IL_0011: br.s IL_0037 + + IL_0013: nop + IL_0014: ldloc.1 + IL_0015: call void [mscorlib]System.Console::WriteLine(int32) + IL_001a: nop + IL_001b: ldloc.1 + IL_001c: ldc.i4.2 + IL_001d: rem + IL_001e: ldc.i4.0 + IL_001f: ceq + IL_0021: stloc.2 + IL_0022: ldloc.2 + IL_0023: brfalse.s IL_0032 + + IL_0025: nop + IL_0026: ldstr "even" + IL_002b: call void [mscorlib]System.Console::WriteLine(string) + IL_0030: nop + IL_0031: nop + IL_0032: nop + IL_0033: ldloc.1 + IL_0034: ldc.i4.1 + IL_0035: add + IL_0036: stloc.1 + IL_0037: ldloc.1 + IL_0038: ldc.i4.s 10 + IL_003a: clt + IL_003c: stloc.3 + IL_003d: ldloc.3 + IL_003e: brtrue.s IL_0013 + + IL_0040: ldstr "end" + IL_0045: call void [mscorlib]System.Console::WriteLine(string) + IL_004a: nop + IL_004b: ret + } // end of method ReduceNesting::EarlyExit2 + + .method public hidebysig instance void + BalancedIf() cil managed + { + // Code size 81 (0x51) + .maxstack 2 + .locals init (bool V_0, + bool V_1, + bool V_2) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_002f + + IL_000c: nop + IL_000d: ldstr "true" + IL_0012: call void [mscorlib]System.Console::WriteLine(string) + IL_0017: nop + IL_0018: ldarg.0 + IL_0019: ldc.i4.1 + IL_001a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_001f: stloc.1 + IL_0020: ldloc.1 + IL_0021: brfalse.s IL_002c + + IL_0023: nop + IL_0024: ldc.i4.1 + IL_0025: call void [mscorlib]System.Console::WriteLine(int32) + IL_002a: nop + IL_002b: nop + IL_002c: nop + IL_002d: br.s IL_0050 + + IL_002f: nop + IL_0030: ldarg.0 + IL_0031: ldc.i4.2 + IL_0032: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0037: stloc.2 + IL_0038: ldloc.2 + IL_0039: brfalse.s IL_0044 + + IL_003b: nop + IL_003c: ldc.i4.2 + IL_003d: call void [mscorlib]System.Console::WriteLine(int32) + IL_0042: nop + IL_0043: nop + IL_0044: ldstr "false" + IL_0049: call void [mscorlib]System.Console::WriteLine(string) + IL_004e: nop + IL_004f: nop + IL_0050: ret + } // end of method ReduceNesting::BalancedIf + + .method public hidebysig instance string + ComplexCase1(string s) cil managed + { + // Code size 255 (0xff) + .maxstack 2 + .locals init (bool V_0, + string V_1, + int32 V_2, + bool V_3, + bool V_4, + int32 V_5, + bool V_6, + bool V_7, + bool V_8, + bool V_9, + bool V_10) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.0 + IL_0003: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0008: stloc.0 + IL_0009: ldloc.0 + IL_000a: brfalse.s IL_0014 + + IL_000c: nop + IL_000d: ldarg.1 + IL_000e: stloc.1 + IL_000f: br IL_00fd + + IL_0014: ldc.i4.0 + IL_0015: stloc.2 + IL_0016: br IL_00e7 + + IL_001b: nop + IL_001c: ldarg.0 + IL_001d: ldc.i4.1 + IL_001e: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_0023: stloc.3 + IL_0024: ldloc.3 + IL_0025: brfalse.s IL_0035 + + IL_0027: nop + IL_0028: ldc.i4.1 + IL_0029: call void [mscorlib]System.Console::WriteLine(int32) + IL_002e: nop + IL_002f: nop + IL_0030: br IL_00e2 + + IL_0035: ldarg.0 + IL_0036: ldc.i4.2 + IL_0037: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_003c: stloc.s V_4 + IL_003e: ldloc.s V_4 + IL_0040: brfalse.s IL_00a7 + + IL_0042: nop + IL_0043: ldloc.2 + IL_0044: stloc.s V_5 + IL_0046: ldloc.s V_5 + IL_0048: ldc.i4.1 + IL_0049: beq.s IL_0056 + + IL_004b: br.s IL_004d + + IL_004d: ldloc.s V_5 + IL_004f: ldc.i4.2 + IL_0050: sub + IL_0051: ldc.i4.1 + IL_0052: ble.un.s IL_0090 + + IL_0054: br.s IL_009d + + IL_0056: ldarg.0 + IL_0057: ldc.i4.3 + IL_0058: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_005d: stloc.s V_6 + IL_005f: ldloc.s V_6 + IL_0061: brfalse.s IL_006d + + IL_0063: nop + IL_0064: ldc.i4.3 + IL_0065: call void [mscorlib]System.Console::WriteLine(int32) + IL_006a: nop + IL_006b: br.s IL_009d + + IL_006d: ldstr "case1" + IL_0072: call void [mscorlib]System.Console::WriteLine(string) + IL_0077: nop + IL_0078: ldarg.0 + IL_0079: ldc.i4.4 + IL_007a: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_007f: stloc.s V_7 + IL_0081: ldloc.s V_7 + IL_0083: brfalse.s IL_008e + + IL_0085: nop + IL_0086: ldc.i4.4 + IL_0087: call void [mscorlib]System.Console::WriteLine(int32) + IL_008c: nop + IL_008d: nop + IL_008e: br.s IL_009d + + IL_0090: ldstr "case23" + IL_0095: call void [mscorlib]System.Console::WriteLine(string) + IL_009a: nop + IL_009b: br.s IL_009d + + IL_009d: ldc.i4.2 + IL_009e: call void [mscorlib]System.Console::WriteLine(int32) + IL_00a3: nop + IL_00a4: nop + IL_00a5: br.s IL_00e2 + + IL_00a7: ldarg.0 + IL_00a8: ldc.i4.5 + IL_00a9: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_00ae: stloc.s V_8 + IL_00b0: ldloc.s V_8 + IL_00b2: brfalse.s IL_00bf + + IL_00b4: nop + IL_00b5: ldc.i4.5 + IL_00b6: call void [mscorlib]System.Console::WriteLine(int32) + IL_00bb: nop + IL_00bc: nop + IL_00bd: br.s IL_00e2 + + IL_00bf: nop + IL_00c0: ldarg.0 + IL_00c1: ldc.i4.6 + IL_00c2: callvirt instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting::B(int32) + IL_00c7: stloc.s V_9 + IL_00c9: ldloc.s V_9 + IL_00cb: brfalse.s IL_00d6 + + IL_00cd: nop + IL_00ce: ldc.i4.6 + IL_00cf: call void [mscorlib]System.Console::WriteLine(int32) + IL_00d4: nop + IL_00d5: nop + IL_00d6: ldstr "else" + IL_00db: call void [mscorlib]System.Console::WriteLine(string) + IL_00e0: nop + IL_00e1: nop + IL_00e2: nop + IL_00e3: ldloc.2 + IL_00e4: ldc.i4.1 + IL_00e5: add + IL_00e6: stloc.2 + IL_00e7: ldloc.2 + IL_00e8: ldarg.1 + IL_00e9: callvirt instance int32 [mscorlib]System.String::get_Length() + IL_00ee: clt + IL_00f0: stloc.s V_10 + IL_00f2: ldloc.s V_10 + IL_00f4: brtrue IL_001b + + IL_00f9: ldarg.1 + IL_00fa: stloc.1 + IL_00fb: br.s IL_00fd + + IL_00fd: ldloc.1 + IL_00fe: ret + } // end of method ReduceNesting::ComplexCase1 + + .method family hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method ReduceNesting::.ctor + +} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.ReduceNesting + + +// ============================================================= + +// *********** DISASSEMBLY COMPLETE *********************** diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs index 9328792e7..aa26c7ce2 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs @@ -153,6 +153,7 @@ namespace ICSharpCode.Decompiler.CSharp new ProxyCallReplacer(), new DelegateConstruction(), new HighLevelLoopTransform(), + new ReduceNestingTransform(), new IntroduceDynamicTypeOnLocals(), new AssignVariableNames(), }; diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 1c57853f4..7d64852ea 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -267,6 +267,7 @@ + diff --git a/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs new file mode 100644 index 000000000..e791a5c41 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs @@ -0,0 +1,418 @@ +// Copyright (c) 2018 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Diagnostics; +using System.Linq; +using ICSharpCode.Decompiler.IL.ControlFlow; +using ICSharpCode.Decompiler.IL.Transforms; +using ICSharpCode.Decompiler.Util; + +namespace ICSharpCode.Decompiler.IL +{ + /// + /// Improves code quality by duplicating keyword exits to reduce nesting and restoring IL order. + /// + /// + /// ConditionDetection and DetectSwitchBody both have agressive inlining policies for else blocks and default cases respectively. + /// This can lead to excessive indentation when the entire rest of the method/loop is included in the else block/default case. + /// When an If/SwitchInstruction is followed immediately by a keyword exit, the exit can be moved into the child blocks + /// allowing the else block or default case to be moved after the if/switch as all prior cases exit. + /// Most importantly, this transformatino does not change the IL order of any code. + /// + /// ConditionDetection also has a block exit priority system to assist exit point reduction which in some cases ignores IL order. + /// After HighLevelLoopTransform has run, all structures have been detected and preference can be returned to maintaining IL ordering. + /// + public class ReduceNestingTransform : IILTransform + { + private ILTransformContext context; + + public void Run(ILFunction function, ILTransformContext context) + { + this.context = context; + Visit((BlockContainer)function.Body, null); + } + + private void Visit(BlockContainer container, Block continueTarget) + { + switch (container.Kind) { + case ContainerKind.Loop: + case ContainerKind.While: + continueTarget = container.EntryPoint; + break; + case ContainerKind.DoWhile: + case ContainerKind.For: + continueTarget = container.Blocks.Last(); + break; + } + + foreach (var block in container.Blocks) + Visit(block, continueTarget); + } + + /// + /// Visits a block in context + /// + /// + /// Marks the target block of continue statements. + /// The instruction following the end point of the block. Can only be null if the end point is unreachable. + private void Visit(Block block, Block continueTarget, ILInstruction nextInstruction = null) + { + Debug.Assert(block.HasFlag(InstructionFlags.EndPointUnreachable) || nextInstruction != null); + + // process each instruction in the block. + for (int i = 0; i < block.Instructions.Count; i++) { + // Transformations may be applied to the current and following instructions but already processed instructions will not be changed + var inst = block.Instructions[i]; + + // the next instruction to be executed. Transformations will change the next instruction, so this is a method instead of a variable + ILInstruction NextInsn() => i + 1 < block.Instructions.Count ? block.Instructions[i + 1] : nextInstruction; + + switch (inst) { + case BlockContainer container: + // visit the contents of the container + Visit(container, continueTarget); + + // reduce nesting in switch blocks + if (container.Kind == ContainerKind.Switch && + CanDuplicateExit(NextInsn(), continueTarget) && + ReduceNesting(block, container, NextInsn())) + RemoveRedundantExit(block, nextInstruction); + + break; + case IfInstruction ifInst: + ImproveILOrdering(block, ifInst); + + // reduce nesting in if/else blocks + if (CanDuplicateExit(NextInsn(), continueTarget) && ReduceNesting(block, ifInst, NextInsn())) + RemoveRedundantExit(block, nextInstruction); + + // visit content blocks + if (ifInst.TrueInst is Block trueBlock) + Visit(trueBlock, continueTarget, NextInsn()); + + if (ifInst.FalseInst is Block falseBlock) { + if (ifInst.TrueInst.HasFlag(InstructionFlags.EndPointUnreachable)) { + ExtractElseBlock(ifInst); + break; + } + + Visit(falseBlock, continueTarget, NextInsn()); + } + break; + } + } + } + + /// + /// For an if statement with an unreachable end point and no else block, + /// inverts to match IL order of the first statement of each branch + /// + private void ImproveILOrdering(Block block, IfInstruction ifInst) + { + if (!block.HasFlag(InstructionFlags.EndPointUnreachable) + || !ifInst.TrueInst.HasFlag(InstructionFlags.EndPointUnreachable) + || !ifInst.FalseInst.MatchNop()) + return; + + Debug.Assert(ifInst != block.Instructions.Last()); + + var trueRange = ConditionDetection.GetILRange(ifInst.TrueInst); + var falseRange = ConditionDetection.GetILRange(block.Instructions[block.Instructions.IndexOf(ifInst)+1]); + if (!trueRange.IsEmpty && !falseRange.IsEmpty && falseRange.Start < trueRange.Start) + ConditionDetection.InvertIf(block, ifInst, context); + } + + /// + /// Reduce Nesting in if/else statements by duplicating an exit instruction. + /// Does not affect IL order + /// + private bool ReduceNesting(Block block, IfInstruction ifInst, ILInstruction exitInst) + { + // start tallying stats for heuristics from then and else-if blocks + int maxStatements = 0, maxDepth = 0; + UpdateStats(ifInst.TrueInst, ref maxStatements, ref maxDepth); + + // if (cond) { ... } exit; + if (ifInst.FalseInst.MatchNop()) { + // a separate heuristic tp ShouldReduceNesting as there is visual balancing to be performed based on number of statments + if (maxDepth < 2) + return false; + + // -> + // if (!cond) exit; + // ...; exit; + EnsureEndPointUnreachable(ifInst.TrueInst, exitInst); + EnsureEndPointUnreachable(block, exitInst); + ConditionDetection.InvertIf(block, ifInst, context); + return true; + } + + // else-if trees are considered as a single group from the root IfInstruction + if (GetElseIfParent(ifInst) != null) + return false; + + // find the else block and tally stats for each else-if block + while (Block.Unwrap(ifInst.FalseInst) is IfInstruction elseIfInst) { + UpdateStats(elseIfInst.TrueInst, ref maxStatements, ref maxDepth); + ifInst = elseIfInst; + } + + if (!ShouldReduceNesting(ifInst.FalseInst, maxStatements, maxDepth)) + return false; + + // extract the else block and insert exit points all the way up the else-if tree + do { + var elseIfInst = GetElseIfParent(ifInst); + + // if (cond) { ... } else { ... } exit; + // -> + // if (cond) { ...; exit; } + // ...; exit; + EnsureEndPointUnreachable(ifInst.TrueInst, exitInst); + ExtractElseBlock(ifInst); + ifInst = elseIfInst; + } while (ifInst != null); + + return true; + } + + /// + /// Reduce Nesting in switch statements by replacing break; in cases with the block exit, and extracting the default case + /// Does not affect IL order + /// + private bool ReduceNesting(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) + return false; + + // find the default section, and ensure it has only one incoming edge + var switchInst = (SwitchInstruction)switchContainer.EntryPoint.Instructions.Single(); + var defaultSection = switchInst.Sections.MaxBy(s => s.Labels.Count()); + if (!defaultSection.Body.MatchBranch(out var defaultBlock) || defaultBlock.IncomingEdgeCount != 1) + return false; + + // tally stats for heuristic from each case block + int maxStatements = 0, maxDepth = 0; + foreach (var section in switchInst.Sections) + if (section != defaultSection && section.Body.MatchBranch(out var caseBlock) && caseBlock.Parent == switchContainer) + UpdateStats(caseBlock, ref maxStatements, ref maxDepth); + + if (!ShouldReduceNesting(defaultBlock, maxStatements, maxDepth)) + return false; + + Debug.Assert(defaultBlock.HasFlag(InstructionFlags.EndPointUnreachable)); + + // ensure the default case dominator tree has no exits (branches to other cases) + var cfg = new ControlFlowGraph(switchContainer, context.CancellationToken); + var defaultNode = cfg.GetNode(defaultBlock); + var defaultTree = TreeTraversal.PreOrder(defaultNode, n => n.DominatorTreeChildren).ToList(); + if (defaultTree.SelectMany(n => n.Successors).Any(n => !defaultNode.Dominates(n))) + return false; + + EnsureEndPointUnreachable(parentBlock, exitInst); + context.Step("Extract default case of switch", switchContainer); + + // replace all break; statements with the exitInst + var leaveInstructions = switchContainer.Descendants.Where(inst => inst.MatchLeave(switchContainer)); + foreach (var leaveInst in leaveInstructions.ToArray()) + leaveInst.ReplaceWith(exitInst.Clone()); + + // replace the default section branch with a break; + defaultSection.Body.ReplaceWith(new Leave(switchContainer)); + + // remove all default blocks from the switch container + var defaultBlocks = defaultTree.Select(c => (Block)c.UserData).ToList(); + foreach (var block in defaultBlocks) + switchContainer.Blocks.Remove(block); + + // replace the parent block exit with the default case instructions + 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); + + return true; + } + + /// + /// Checks if an exit is a duplicable keyword exit (return; break; continue;) + /// + private bool CanDuplicateExit(ILInstruction exit, Block continueTarget) => + exit != null && (exit is Leave leave && leave.Value.MatchNop() || exit.MatchBranch(continueTarget)); + + /// + /// Ensures the end point of a block is unreachable by duplicating and appending the [exit] instruction following the end point + /// + /// The instruction/block of interest + /// The next instruction to be executed (provided inst does not exit) + private void EnsureEndPointUnreachable(ILInstruction inst, ILInstruction fallthroughExit) + { + if (!(inst is Block block)) { + Debug.Assert(inst.HasFlag(InstructionFlags.EndPointUnreachable)); + return; + } + + if (!block.HasFlag(InstructionFlags.EndPointUnreachable)) { + context.Step("Duplicate block exit", fallthroughExit); + block.Instructions.Add(fallthroughExit.Clone()); + } + } + + /// + /// Removes a redundant block exit instruction. + /// + private void RemoveRedundantExit(Block block, ILInstruction implicitExit) + { + if (block.Instructions.Last().Match(implicitExit).Success) { + context.Step("Remove redundant exit", block.Instructions.Last()); + block.Instructions.RemoveLast(); + } + } + + /// + /// Determines if an IfInstruction is an else-if and returns the preceeding (parent) IfInstruction + /// + /// [else-]if (parent-cond) else { ifInst } + /// + private IfInstruction GetElseIfParent(IfInstruction ifInst) + { + Debug.Assert(ifInst.Parent is Block); + if (Block.Unwrap(ifInst.Parent) == ifInst && // only instruction in block + ifInst.Parent.Parent is IfInstruction elseIfInst && // parent of block is an IfInstruction + elseIfInst.FalseInst == ifInst.Parent) // part of the false branch not the true branch + return elseIfInst; + + return null; + } + + /// + /// Adds a code path to the current heuristic tally + /// + private void UpdateStats(ILInstruction inst, ref int maxStatements, ref int maxDepth) + { + int numStatements = 0; + ComputeStats(inst, ref numStatements, ref maxDepth, 0); + maxStatements = Math.Max(numStatements, maxStatements); + } + + /// + /// Recursively computes the number of statements and maximum nested depth of an instruction + /// + private void ComputeStats(ILInstruction inst, ref int numStatements, ref int maxDepth, int currentDepth) + { + switch (inst) { + case Block block: + foreach (var i in block.Instructions) + ComputeStats(i, ref numStatements, ref maxDepth, currentDepth); + break; + case BlockContainer container: + numStatements++; // one statement for the container head (switch/loop) + + var containerBody = container.EntryPoint; + if (container.Kind == ContainerKind.For || container.Kind == ContainerKind.While) { + if (!container.MatchConditionBlock(container.EntryPoint, out _, out containerBody)) + throw new NotSupportedException("Invalid condition block in loop."); + } + + // add the nested body + ComputeStats(containerBody, ref numStatements, ref maxDepth, currentDepth + 1); + break; + case IfInstruction ifInst: + numStatements++; // one statement for the if/condition itself + + // nested then instruction + ComputeStats(ifInst.TrueInst, ref numStatements, ref maxDepth, currentDepth + 1); + + // include all nested else-if instructions at the same depth + var elseInst = ifInst.FalseInst; + while (Block.Unwrap(elseInst) is IfInstruction elseIfInst) { + numStatements++; + ComputeStats(elseIfInst.TrueInst, ref numStatements, ref maxDepth, currentDepth + 1); + elseInst = elseIfInst.FalseInst; + } + + // include all nested else instruction + ComputeStats(elseInst, ref numStatements, ref maxDepth, currentDepth + 1); + break; + case SwitchInstruction switchInst: + // one statement per case label + numStatements += switchInst.Sections.Count + 1; + // add all the case blocks at the current depth + // most formatters indent switch blocks twice, but we don't want this heuristic to be based on formatting + // so we remain conservative and only include the increase in depth from the container and not the labels + foreach (var section in switchInst.Sections) + if (section.Body.MatchBranch(out var caseBlock) && caseBlock.Parent == switchInst.Parent.Parent) + ComputeStats(caseBlock, ref numStatements, ref maxDepth, currentDepth); + break; + default: + // just a regular statement + numStatements++; + if (currentDepth > maxDepth) + maxDepth = currentDepth; + break; + } + } + + /// + /// Heuristic to determine whether it is worth duplicating exits into the preceeding sibling blocks (then/else-if/case) + /// in order to reduce the nesting of inst by 1 + /// + /// The instruction heading the nested candidate block + /// The number of statements in the largest sibling block + /// The relative depth of the most nested statement in the sibling blocks + /// + private bool ShouldReduceNesting(ILInstruction inst, int maxStatements, int maxDepth) + { + int maxStatements2 = 0, maxDepth2 = 0; + UpdateStats(inst, ref maxStatements2, ref maxDepth2); + // if the max depth is 2, always reduce nesting (total depth 3 or more) + // if the max depth is 1, reduce nesting if this block is the largest + // otherwise reduce nesting only if this block is twice as large as any other + return maxDepth2 >= 2 || maxDepth2 >= 1 && maxStatements2 > maxStatements || maxStatements2 >= 2*maxStatements; + } + + /// + /// if (cond) { ...; exit; } else { ... } + /// ...; + /// -> + /// if (cond) { ...; exit; } + /// ...; + /// ...; + /// + /// + private void ExtractElseBlock(IfInstruction ifInst) + { + Debug.Assert(ifInst.TrueInst.HasFlag(InstructionFlags.EndPointUnreachable)); + var block = (Block)ifInst.Parent; + var falseBlock = (Block)ifInst.FalseInst; + + context.Step("Extract else block", ifInst); + int insertAt = block.Instructions.IndexOf(ifInst) + 1; + for (int i = 0; i < falseBlock.Instructions.Count; i++) + block.Instructions.Insert(insertAt++, falseBlock.Instructions[i]); + + ifInst.FalseInst = new Nop(); + } + } +}