Browse Source

Extend VBPretty Async test code

pull/2853/head
ElektroKill 3 years ago
parent
commit
341074aa58
No known key found for this signature in database
GPG Key ID: 7E3C5C084E40E3EC
  1. 271
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/Async.cs
  2. 223
      ICSharpCode.Decompiler.Tests/TestCases/VBPretty/Async.vb
  3. 4
      ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs
  4. 4
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

271
ICSharpCode.Decompiler.Tests/TestCases/VBPretty/Async.cs

@ -1,51 +1,254 @@
using System; using System;
using System.IO; using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.VisualBasic.CompilerServices; using Microsoft.VisualBasic.CompilerServices;
[StandardModule] namespace ICSharpCode.Decompiler.Tests.TestCases.VBPretty
internal sealed class AsyncProgram
{ {
[STAThread] public class Async
public static void Main(string[] args)
{ {
Task task = new Task(ProcessDataAsync); private int memberField;
task.Start();
task.Wait();
Console.ReadLine();
}
public static async void ProcessDataAsync() private static bool True()
{ {
Task<int> task = HandleFileAsync("C:\\enable1.txt"); return true;
Console.WriteLine("Please wait, processing"); }
Console.WriteLine("Count: " + await task);
}
public static async Task<int> HandleFileAsync(string file) public async void SimpleVoidMethod()
{ {
Console.WriteLine("HandleFile enter"); Console.WriteLine("Before");
int num = 0; await Task.Delay(TimeSpan.FromSeconds(1.0));
checked Console.WriteLine("After");
}
public async void VoidMethodWithoutAwait()
{
Console.WriteLine("No Await");
}
public async void EmptyVoidMethod()
{
}
public async void AwaitYield()
{
await Task.Yield();
}
public async void AwaitDefaultYieldAwaitable()
{ {
using (StreamReader streamReader = new StreamReader(file)) #if LEGACY_VBC || (OPTIMIZE && !ROSLYN4)
YieldAwaitable yieldAwaitable = default(YieldAwaitable);
YieldAwaitable yieldAwaitable2 = yieldAwaitable;
await yieldAwaitable2;
#else
await default(YieldAwaitable);
#endif
}
public async void AwaitDefaultHopToThreadPool()
{
#if LEGACY_VBC || (OPTIMIZE && !ROSLYN4)
HopToThreadPoolAwaitable hopToThreadPoolAwaitable = default(HopToThreadPoolAwaitable);
HopToThreadPoolAwaitable hopToThreadPoolAwaitable2 = hopToThreadPoolAwaitable;
await hopToThreadPoolAwaitable2;
#else
await default(HopToThreadPoolAwaitable);
#endif
}
public async Task SimpleVoidTaskMethod()
{
Console.WriteLine("Before");
await Task.Delay(TimeSpan.FromSeconds(1.0));
Console.WriteLine("After");
}
public async Task TaskMethodWithoutAwait()
{
Console.WriteLine("No Await");
}
public async Task CapturingThis()
{
await Task.Delay(memberField);
}
public async Task CapturingThisWithoutAwait()
{
Console.WriteLine(memberField);
}
public async Task<bool> SimpleBoolTaskMethod()
{
Console.WriteLine("Before");
await Task.Delay(TimeSpan.FromSeconds(1.0));
Console.WriteLine("After");
return true;
}
public async void TwoAwaitsWithDifferentAwaiterTypes()
{
Console.WriteLine("Before");
if (await SimpleBoolTaskMethod())
{
await Task.Delay(TimeSpan.FromSeconds(1.0));
}
Console.WriteLine("After");
}
public async void AwaitInLoopCondition()
{
while (await SimpleBoolTaskMethod())
{ {
string text = await streamReader.ReadToEndAsync(); Console.WriteLine("Body");
num += text.Length; }
int num2 = 0; }
do
public async Task Issue2366a()
{
while (true)
{
try
{
await Task.CompletedTask;
}
catch (Exception projectError)
{ {
if (text.GetHashCode() == 0) ProjectData.SetProjectError(projectError);
{ ProjectData.ClearProjectError();
num--; }
}
num2++;
} while (num2 <= 10000);
} }
}
Console.WriteLine("HandleFile exit"); public static async Task<int> GetIntegerSumAsync(IEnumerable<int> items)
{
await Task.Delay(100);
int num = 0;
foreach (int item in items)
{
num = checked(num + item);
}
return num; return num;
} }
public async Task AsyncCatch(bool b, Task<int> task1, Task<int> task2)
{
try
{
Console.WriteLine("Start try");
await task1;
Console.WriteLine("End try");
}
catch (Exception projectError)
{
ProjectData.SetProjectError(projectError);
Console.WriteLine("No await");
ProjectData.ClearProjectError();
}
}
public async Task AsyncCatchThrow(bool b, Task<int> task1, Task<int> task2)
{
try
{
Console.WriteLine("Start try");
await task1;
Console.WriteLine("End try");
}
catch (Exception projectError)
{
ProjectData.SetProjectError(projectError);
Console.WriteLine("No await");
throw;
}
}
public async Task AsyncFinally(bool b, Task<int> task1, Task<int> task2)
{
try
{
Console.WriteLine("Start try");
await task1;
Console.WriteLine("End try");
}
finally
{
Console.WriteLine("No await");
}
}
public static async Task AlwaysThrow()
{
throw new Exception();
}
public static async Task InfiniteLoop()
{
while (true)
{
}
}
public static async Task InfiniteLoopWithAwait()
{
while (true)
{
await Task.Delay(10);
}
}
public async Task AsyncWithLocalVar()
{
object objectValue = RuntimeHelpers.GetObjectValue(new object());
await UseObj(RuntimeHelpers.GetObjectValue(objectValue));
await UseObj(RuntimeHelpers.GetObjectValue(objectValue));
}
public static async Task UseObj(object a)
{
}
}
public struct AsyncInStruct
{
private int i;
public async Task<int> Test(AsyncInStruct xx)
{
checked
{
xx.i++;
i++;
await Task.Yield();
return i + xx.i;
}
}
}
public struct HopToThreadPoolAwaitable : INotifyCompletion
{
public bool IsCompleted { get; set; }
public HopToThreadPoolAwaitable GetAwaiter()
{
return this;
}
public void OnCompleted(Action continuation)
{
Task.Run(continuation);
}
void INotifyCompletion.OnCompleted(Action continuation)
{
//ILSpy generated this explicit interface implementation from .override directive in OnCompleted
this.OnCompleted(continuation);
}
public void GetResult()
{
}
} }
} }

223
ICSharpCode.Decompiler.Tests/TestCases/VBPretty/Async.vb

@ -1,48 +1,181 @@
Imports System Imports System
Imports System.IO Imports System.Collections.Generic
Imports System.Threading.Tasks Imports System.Threading.Tasks
Imports System.Runtime.CompilerServices
Module AsyncProgram Namespace ICSharpCode.Decompiler.Tests.TestCases.VBPretty
' Sample taken verbatim from https://www.dotnetperls.com/async-vbnet Public Class Async
Sub Main(args As String()) Private memberField As Integer
Dim task = New Task(AddressOf ProcessDataAsync)
' Start and wait for task to end. Private Shared Function [True]() As Boolean
task.Start() Return True
task.Wait() End Function
Console.ReadLine()
End Sub Public Async Sub SimpleVoidMethod()
Console.WriteLine("Before")
Async Sub ProcessDataAsync() Await Task.Delay(TimeSpan.FromSeconds(1.0))
' Create a task Of Integer. Console.WriteLine("After")
' ... Use HandleFileAsync method with a large file. End Sub
Dim task As Task(Of Integer) = HandleFileAsync("C:\enable1.txt")
' This statement runs while HandleFileAsync executes. Public Async Sub VoidMethodWithoutAwait()
Console.WriteLine("Please wait, processing") Console.WriteLine("No Await")
' Use await to wait for task to complete. End Sub
Dim result As Integer = Await task
Console.WriteLine("Count: " + result.ToString()) Public Async Sub EmptyVoidMethod()
End Sub End Sub
Async Function HandleFileAsync(ByVal file As String) As Task(Of Integer) Public Async Sub AwaitYield()
Console.WriteLine("HandleFile enter") Await Task.Yield()
End Sub
' Open the file.
Dim count As Integer = 0 Public Async Sub AwaitDefaultYieldAwaitable()
Using reader As StreamReader = New StreamReader(file) Await CType(Nothing, YieldAwaitable)
Dim value As String = Await reader.ReadToEndAsync() End Sub
count += value.Length
Public Async Sub AwaitDefaultHopToThreadPool()
' Do a slow computation on the file. ' unlike YieldAwaitable which implements ICriticalNotifyCompletion,
For i = 0 To 10000 Step 1 ' the HopToThreadPoolAwaitable struct only implements
Dim x = value.GetHashCode() ' INotifyCompletion, so this results in different codegen
If x = 0 Then Await CType(Nothing, HopToThreadPoolAwaitable)
count -= 1 End Sub
End If
Public Async Function SimpleVoidTaskMethod() As Task
Next Console.WriteLine("Before")
End Using Await Task.Delay(TimeSpan.FromSeconds(1.0))
Console.WriteLine("After")
Console.WriteLine("HandleFile exit") End Function
Return count
End Function Public Async Function TaskMethodWithoutAwait() As Task
End Module Console.WriteLine("No Await")
End Function
Public Async Function CapturingThis() As Task
Await Task.Delay(memberField)
End Function
Public Async Function CapturingThisWithoutAwait() As Task
Console.WriteLine(memberField)
End Function
Public Async Function SimpleBoolTaskMethod() As Task(Of Boolean)
Console.WriteLine("Before")
Await Task.Delay(TimeSpan.FromSeconds(1.0))
Console.WriteLine("After")
Return True
End Function
Public Async Sub TwoAwaitsWithDifferentAwaiterTypes()
Console.WriteLine("Before")
If Await SimpleBoolTaskMethod() Then
Await Task.Delay(TimeSpan.FromSeconds(1.0))
End If
Console.WriteLine("After")
End Sub
Public Async Sub AwaitInLoopCondition()
While Await SimpleBoolTaskMethod()
Console.WriteLine("Body")
End While
End Sub
Public Async Function Issue2366a() As Task
While True
Try
Await Task.CompletedTask
Catch
End Try
End While
End Function
Public Shared Async Function GetIntegerSumAsync(ByVal items As IEnumerable(Of Integer)) As Task(Of Integer)
Await Task.Delay(100)
Dim num = 0
For Each item In items
num += item
Next
Return num
End Function
Public Async Function AsyncCatch(ByVal b As Boolean, ByVal task1 As Task(Of Integer), ByVal task2 As Task(Of Integer)) As Task
Try
Console.WriteLine("Start try")
Await task1
Console.WriteLine("End try")
Catch ex As Exception
Console.WriteLine("No await")
End Try
End Function
Public Async Function AsyncCatchThrow(ByVal b As Boolean, ByVal task1 As Task(Of Integer), ByVal task2 As Task(Of Integer)) As Task
Try
Console.WriteLine("Start try")
Await task1
Console.WriteLine("End try")
Catch ex As Exception
Console.WriteLine("No await")
Throw
End Try
End Function
Public Async Function AsyncFinally(ByVal b As Boolean, ByVal task1 As Task(Of Integer), ByVal task2 As Task(Of Integer)) As Task
Try
Console.WriteLine("Start try")
Await task1
Console.WriteLine("End try")
Finally
Console.WriteLine("No await")
End Try
End Function
Public Shared Async Function AlwaysThrow() As Task
Throw New Exception
End Function
Public Shared Async Function InfiniteLoop() As Task
While True
End While
End Function
Public Shared Async Function InfiniteLoopWithAwait() As Task
While True
Await Task.Delay(10)
End While
End Function
Public Async Function AsyncWithLocalVar() As Task
Dim a As Object = New Object()
Await UseObj(a)
Await UseObj(a)
End Function
Public Shared Async Function UseObj(ByVal a As Object) As Task
End Function
End Class
Public Structure AsyncInStruct
Private i As Integer
Public Async Function Test(ByVal xx As AsyncInStruct) As Task(Of Integer)
xx.i += 1
i += 1
Await Task.Yield()
Return i + xx.i
End Function
End Structure
Public Structure HopToThreadPoolAwaitable
Implements INotifyCompletion
Public Property IsCompleted As Boolean
Public Function GetAwaiter() As HopToThreadPoolAwaitable
Return Me
End Function
Public Sub OnCompleted(ByVal continuation As Action) Implements INotifyCompletion.OnCompleted
Task.Run(continuation)
End Sub
Public Sub GetResult()
End Sub
End Structure
End Namespace

4
ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs

@ -92,7 +92,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test] [Test]
public async Task Async([ValueSource(nameof(defaultOptions))] CompilerOptions options) public async Task Async([ValueSource(nameof(defaultOptions))] CompilerOptions options)
{ {
await Run(options: options); await Run(options: options | CompilerOptions.Library);
} }
[Test] // TODO: legacy VB compound assign [Test] // TODO: legacy VB compound assign
@ -142,7 +142,7 @@ namespace ICSharpCode.Decompiler.Tests
} }
var executable = await Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile).ConfigureAwait(false); var executable = await Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile).ConfigureAwait(false);
var decompiled = await Tester.DecompileCSharp(executable.PathToAssembly, settings).ConfigureAwait(false); var decompiled = await Tester.DecompileCSharp(executable.PathToAssembly, settings ?? new DecompilerSettings { FileScopedNamespaces = false }).ConfigureAwait(false);
CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(options).ToArray()); CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(options).ToArray());
Tester.RepeatOnIOError(() => File.Delete(decompiled)); Tester.RepeatOnIOError(() => File.Delete(decompiled));

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

@ -196,6 +196,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{ {
CopyPropagation.Propagate(stloc, context); CopyPropagation.Propagate(stloc, context);
} }
// Remove lone 'ldc.i4', present in older Roslyn VB compiler output
foreach (var block in function.Descendants.OfType<Block>())
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.LdcI4);
} }
// Copy-propagate temporaries holding a copy of 'this'. // Copy-propagate temporaries holding a copy of 'this'.

Loading…
Cancel
Save