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 @@ @@ -1,51 +1,254 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.VisualBasic.CompilerServices;
[StandardModule]
internal sealed class AsyncProgram
namespace ICSharpCode.Decompiler.Tests.TestCases.VBPretty
{
[STAThread]
public static void Main(string[] args)
public class Async
{
Task task = new Task(ProcessDataAsync);
task.Start();
task.Wait();
Console.ReadLine();
}
private int memberField;
public static async void ProcessDataAsync()
{
Task<int> task = HandleFileAsync("C:\\enable1.txt");
Console.WriteLine("Please wait, processing");
Console.WriteLine("Count: " + await task);
}
private static bool True()
{
return true;
}
public static async Task<int> HandleFileAsync(string file)
{
Console.WriteLine("HandleFile enter");
int num = 0;
checked
public async void SimpleVoidMethod()
{
Console.WriteLine("Before");
await Task.Delay(TimeSpan.FromSeconds(1.0));
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();
num += text.Length;
int num2 = 0;
do
Console.WriteLine("Body");
}
}
public async Task Issue2366a()
{
while (true)
{
try
{
await Task.CompletedTask;
}
catch (Exception projectError)
{
if (text.GetHashCode() == 0)
{
num--;
}
num2++;
} while (num2 <= 10000);
ProjectData.SetProjectError(projectError);
ProjectData.ClearProjectError();
}
}
}
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;
}
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 @@ @@ -1,48 +1,181 @@
Imports System
Imports System.IO
Imports System.Collections.Generic
Imports System.Threading.Tasks
Imports System.Runtime.CompilerServices
Module AsyncProgram
' Sample taken verbatim from https://www.dotnetperls.com/async-vbnet
Sub Main(args As String())
Dim task = New Task(AddressOf ProcessDataAsync)
' Start and wait for task to end.
task.Start()
task.Wait()
Console.ReadLine()
End Sub
Async Sub ProcessDataAsync()
' Create a task Of Integer.
' ... Use HandleFileAsync method with a large file.
Dim task As Task(Of Integer) = HandleFileAsync("C:\enable1.txt")
' This statement runs while HandleFileAsync executes.
Console.WriteLine("Please wait, processing")
' Use await to wait for task to complete.
Dim result As Integer = Await task
Console.WriteLine("Count: " + result.ToString())
End Sub
Async Function HandleFileAsync(ByVal file As String) As Task(Of Integer)
Console.WriteLine("HandleFile enter")
' Open the file.
Dim count As Integer = 0
Using reader As StreamReader = New StreamReader(file)
Dim value As String = Await reader.ReadToEndAsync()
count += value.Length
' Do a slow computation on the file.
For i = 0 To 10000 Step 1
Dim x = value.GetHashCode()
If x = 0 Then
count -= 1
End If
Next
End Using
Console.WriteLine("HandleFile exit")
Return count
End Function
End Module
Namespace ICSharpCode.Decompiler.Tests.TestCases.VBPretty
Public Class Async
Private memberField As Integer
Private Shared Function [True]() As Boolean
Return True
End Function
Public Async Sub SimpleVoidMethod()
Console.WriteLine("Before")
Await Task.Delay(TimeSpan.FromSeconds(1.0))
Console.WriteLine("After")
End Sub
Public Async Sub VoidMethodWithoutAwait()
Console.WriteLine("No Await")
End Sub
Public Async Sub EmptyVoidMethod()
End Sub
Public Async Sub AwaitYield()
Await Task.Yield()
End Sub
Public Async Sub AwaitDefaultYieldAwaitable()
Await CType(Nothing, YieldAwaitable)
End Sub
Public Async Sub AwaitDefaultHopToThreadPool()
' unlike YieldAwaitable which implements ICriticalNotifyCompletion,
' the HopToThreadPoolAwaitable struct only implements
' INotifyCompletion, so this results in different codegen
Await CType(Nothing, HopToThreadPoolAwaitable)
End Sub
Public Async Function SimpleVoidTaskMethod() As Task
Console.WriteLine("Before")
Await Task.Delay(TimeSpan.FromSeconds(1.0))
Console.WriteLine("After")
End Function
Public Async Function TaskMethodWithoutAwait() As Task
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 @@ -92,7 +92,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
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
@ -142,7 +142,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -142,7 +142,7 @@ namespace ICSharpCode.Decompiler.Tests
}
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());
Tester.RepeatOnIOError(() => File.Delete(decompiled));

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

@ -196,6 +196,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -196,6 +196,10 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
{
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'.

Loading…
Cancel
Save