diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs index e7c9a17f2..842a90900 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs @@ -57,6 +57,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness await AwaitInCatch(Task.FromResult(1), Task.FromResult(2)); await AwaitInFinally(Task.FromResult(2), Task.FromResult(4)); await AwaitInCatchAndFinally(Task.FromResult(3), Task.FromResult(6), Task.FromResult(9)); + Console.WriteLine(await AwaitInFinallyInUsing(Task.FromResult(new StringWriter()), Task.FromResult(6), Task.FromResult(9))); #endif } @@ -264,6 +265,21 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness } Console.WriteLine("End Method"); } + + public async Task AwaitInFinallyInUsing(Task task1, Task task2, Task task3) + { + using (await task1) { + Console.WriteLine("Start using"); + try { + Console.WriteLine("Before return"); + return await task2; + } finally { + Console.WriteLine("Start finally"); + await task3; + Console.WriteLine("End finally"); + } + } + } #endif } } \ No newline at end of file diff --git a/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs b/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs index 60d39f6d9..b9efda882 100644 --- a/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs +++ b/ICSharpCode.Decompiler/IL/ControlFlow/AwaitInCatchTransform.cs @@ -221,17 +221,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow var tempStore = globalCopyVar.LoadInstructions[0].Parent as StLoc; if (tempStore == null || !MatchExceptionCaptureBlock(tempStore, out var exitOfFinally, out var afterFinally, out var blocksToRemove)) continue; - if (afterFinally.Instructions.Count < 2) - continue; - int offset = 0; - if (afterFinally.Instructions[0].MatchLdLoc(out var identifierVariable)) { - if (identifierVariable.LoadCount != 1 || identifierVariable.StoreCount != 1) - continue; - offset = 1; - } - if (!afterFinally.Instructions[offset].MatchStLoc(out var globalCopyVarSplitted, out var ldnull) || !ldnull.MatchLdNull()) - continue; - if (globalCopyVarSplitted.StoreCount != 1 || globalCopyVarSplitted.LoadCount != 0) + if (!MatchAfterFinallyBlock(ref afterFinally, blocksToRemove, out bool removeFirstInstructionInAfterFinally)) continue; var cfg = new ControlFlowGraph(container, context.CancellationToken); var exitOfFinallyNode = cfg.GetNode(exitOfFinally); @@ -269,9 +259,11 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow } var finallyContainer = new BlockContainer(); entryPointOfFinally.Remove(); - if (offset == 1) + if (removeFirstInstructionInAfterFinally) afterFinally.Instructions.RemoveAt(0); changedContainers.Add(container); + var outer = BlockContainer.FindClosestContainer(container.Parent); + if (outer != null) changedContainers.Add(outer); finallyContainer.Blocks.Add(entryPointOfFinally); exitOfFinally.Instructions.RemoveRange(tempStore.ChildIndex, 3); exitOfFinally.Instructions.Add(new Leave(finallyContainer)); @@ -366,5 +358,47 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow blocksToRemove.Add(captureBlock); return true; } + + static bool MatchAfterFinallyBlock(ref Block afterFinally, List blocksToRemove, out bool removeFirstInstructionInAfterFinally) + { + removeFirstInstructionInAfterFinally = false; + if (afterFinally.Instructions.Count < 2) + return false; + ILVariable globalCopyVarSplitted; + switch (afterFinally.Instructions[0]) { + case IfInstruction ifInst: + if (ifInst.Condition.MatchCompEquals(out var load, out var ldone) && ldone.MatchLdcI4(1) && load.MatchLdLoc(out var variable)) { + if (!ifInst.TrueInst.MatchBranch(out var targetBlock)) + return false; + blocksToRemove.Add(afterFinally); + afterFinally = targetBlock; + return true; + } else if (ifInst.Condition.MatchCompNotEquals(out load, out ldone) && ldone.MatchLdcI4(1) && load.MatchLdLoc(out variable)) { + if (!afterFinally.Instructions[1].MatchBranch(out var targetBlock)) + return false; + blocksToRemove.Add(afterFinally); + afterFinally = targetBlock; + return true; + } + return false; + case LdLoc ldLoc: + if (ldLoc.Variable.LoadCount != 1 || ldLoc.Variable.StoreCount != 1) + return false; + if (!afterFinally.Instructions[1].MatchStLoc(out globalCopyVarSplitted, out var ldnull) || !ldnull.MatchLdNull()) + return false; + removeFirstInstructionInAfterFinally = true; + break; + case StLoc stloc: + globalCopyVarSplitted = stloc.Variable; + if (!stloc.Value.MatchLdNull()) + return false; + break; + default: + return false; + } + if (globalCopyVarSplitted.StoreCount != 1 || globalCopyVarSplitted.LoadCount != 0) + return false; + return true; + } } }