From 59d8ae904bc990281655f6220ae343f5012195e4 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Tue, 18 Aug 2026 21:35:25 +0200 Subject: [PATCH] Fix tests on Windows with legacy csc. There's an additional local variable when decompiling the non-optimized code; and explicitly putting that variable into the test case just makes it fail due to yet another additional variable. --- .../TestCases/Pretty/AsyncAwaitPatterns.cs | 63 ++++++------------- .../IL/Instructions/Branch.cs | 9 +++ .../IL/Instructions/Leave.cs | 15 +++-- 3 files changed, 34 insertions(+), 53 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncAwaitPatterns.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncAwaitPatterns.cs index ede40cd29..61db4f542 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncAwaitPatterns.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncAwaitPatterns.cs @@ -81,70 +81,52 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait Console.WriteLine(await Get()); } +#if ROSLYN2 || OPT public async Task BinaryOperator() { -#if ROSLYN2 || OPT Console.WriteLine(await Get() + await Get()); -#else - int value = await Get() + await Get(); - Console.WriteLine(value); -#endif } +#endif +#if ROSLYN2 || OPT public async Task UnaryOperator() { -#if ROSLYN2 || OPT Console.WriteLine(-(await Get())); -#else - int value = -(await Get()); - Console.WriteLine(value); -#endif } +#endif +#if ROSLYN2 || OPT public async Task MemberAccessOnResult() { -#if ROSLYN2 || OPT Console.WriteLine((await GetString()).Length); -#else - int length = (await GetString()).Length; - Console.WriteLine(length); -#endif } +#endif +#if ROSLYN2 || OPT public async Task IndexerOnResult() { -#if ROSLYN2 || OPT Console.WriteLine((await GetString())[0]); -#else - char value = (await GetString())[0]; - Console.WriteLine(value); -#endif } +#endif +#if ROSLYN2 || OPT public async Task CoalesceOnResult() { -#if ROSLYN2 || OPT Console.WriteLine((await GetString()) ?? "null"); -#else - string value = (await GetString()) ?? "null"; - Console.WriteLine(value); -#endif } +#endif public async Task ThrowAwaitedException() { throw await GetException(); } +#if ROSLYN2 || OPT public async Task Checked() { -#if ROSLYN2 || OPT Console.WriteLine(checked(await Get() + 1)); -#else - int value = checked(await Get() + 1); - Console.WriteLine(value); -#endif } +#endif #if CS60 public async Task TryFinally() @@ -253,15 +235,12 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait } #endif +#if ROSLYN2 || OPT public async Task AwaitInGenericMethod(Task task) { -#if ROSLYN2 || OPT Console.WriteLine(await task); -#else - object value = await task; - Console.WriteLine(value); -#endif } +#endif } public static class AwaiterExtensions @@ -510,25 +489,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.AsyncAwait } #endif +#if ROSLYN2 public async Task ExtensionAwaiterOverTaskArray(Task[] tasks) { -#if ROSLYN2 || OPT Console.WriteLine((await tasks)[0]); -#else - int value = (await tasks)[0]; - Console.WriteLine(value); -#endif } +#endif +#if ROSLYN2 public async Task ExtensionAwaiterOverTaskList(List> tasks) { -#if ROSLYN2 || OPT Console.WriteLine((await tasks)[0]); -#else - int value = (await tasks)[0]; - Console.WriteLine(value); -#endif } +#endif public async Task GenericAwaitableType(GenericAwaitable awaitable) { diff --git a/ICSharpCode.Decompiler/IL/Instructions/Branch.cs b/ICSharpCode.Decompiler/IL/Instructions/Branch.cs index 9f5aee745..1cb7b206b 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Branch.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Branch.cs @@ -27,6 +27,7 @@ namespace ICSharpCode.Decompiler.IL /// /// /// When jumping to the entrypoint of the current block container, the branch represents a continue statement. + /// Will implicitly execute finally blocks when jumping out of a try-block. /// partial class Branch : SimpleInstruction, IBranchOrLeaveInstruction { @@ -129,6 +130,14 @@ namespace ICSharpCode.Decompiler.IL interface IBranchOrLeaveInstruction { + /// + /// The block container that directly contains the jump target. + /// BlockContainer TargetContainer { get; } + + /// + /// Gets whether this branch executes at least one finally block before reaching the jump target. + /// + bool TriggersFinallyBlock { get; } } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/Leave.cs b/ICSharpCode.Decompiler/IL/Instructions/Leave.cs index 4d231e9b3..2b44e210d 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Leave.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Leave.cs @@ -22,14 +22,14 @@ using System.Diagnostics; namespace ICSharpCode.Decompiler.IL { /// - /// Unconditional branch. goto target; + /// Unconditional branch to end of block container. + /// Return is represented using IsLeavingFunction and an (optional) return value. + /// The block container evaluates to the value produced by the argument of the leave instruction. /// /// - /// When jumping to the entrypoint of the current block container, the branch represents a continue statement. - /// - /// Phase-1 execution of a branch is a no-op. - /// Phase-2 execution removes PopCount elements from the evaluation stack - /// and jumps to the target block. + /// While Branch jumps to the start of a block, Leave jumps to the end of a BlockContainer. + /// Leave often represents break; or return;. + /// Will implicitly execute finally blocks when jumping out of a try-block. /// partial class Leave : ILInstruction, IBranchOrLeaveInstruction { @@ -87,8 +87,7 @@ namespace ICSharpCode.Decompiler.IL /// Gets whether the leave instruction is directly leaving the whole ILFunction. /// (TargetContainer == main container of the function). /// - /// This is only valid for functions returning void (representing value-less "return;"), - /// and for iterators (representing "yield break;"). + /// Indicates the leave instruction represents a return statement. /// /// Note: returns false for leave instructions that indirectly leave the function /// (e.g. leaving a try block, and the try-finally construct is immediately followed