Skip to content

Commit

Permalink
Merge pull request dotnet#42775 from CyrusNajmabadi/foreachDeconstruct
Browse files Browse the repository at this point in the history
Fix deconstruction in await-foreach statements
  • Loading branch information
CyrusNajmabadi authored Mar 26, 2020
2 parents f7bc0bd + b1652e8 commit a38b1e5
Show file tree
Hide file tree
Showing 6 changed files with 190 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,128 @@ public abstract partial class AbstractCSharpDiagnosticProviderBasedUserDiagnosti

protected override TestWorkspace CreateWorkspaceFromFile(string initialMarkup, TestParameters parameters)
=> TestWorkspace.CreateCSharp(initialMarkup, parameters.parseOptions, parameters.compilationOptions);

protected const string IAsyncEnumerable = @"
namespace System
{
public interface IAsyncDisposable
{
System.Threading.Tasks.ValueTask DisposeAsync();
}
}
namespace System.Runtime.CompilerServices
{
using System.Threading.Tasks;
public sealed class AsyncMethodBuilderAttribute : Attribute
{
public AsyncMethodBuilderAttribute(Type builderType) { }
public Type BuilderType { get; }
}
public struct AsyncValueTaskMethodBuilder
{
public ValueTask Task => default;
public static AsyncValueTaskMethodBuilder Create() => default;
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : INotifyCompletion
where TStateMachine : IAsyncStateMachine {}
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine)
where TAwaiter : ICriticalNotifyCompletion
where TStateMachine : IAsyncStateMachine {}
public void SetException(Exception exception) {}
public void SetResult() {}
public void SetStateMachine(IAsyncStateMachine stateMachine) {}
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine {}
}
public readonly struct ValueTaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
{
public bool IsCompleted => default;
public void GetResult() { }
public void OnCompleted(Action continuation) { }
public void UnsafeOnCompleted(Action continuation) { }
}
public readonly struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, INotifyCompletion
{
public bool IsCompleted => default;
public TResult GetResult() => default;
public void OnCompleted(Action continuation) { }
public void UnsafeOnCompleted(Action continuation) { }
}
}
namespace System.Threading.Tasks
{
using System.Runtime.CompilerServices;
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))]
public readonly struct ValueTask : IEquatable<ValueTask>
{
public ValueTask(Task task) {}
public ValueTask(IValueTaskSource source, short token) {}
public bool IsCompleted => default;
public bool IsCompletedSuccessfully => default;
public bool IsFaulted => default;
public bool IsCanceled => default;
public Task AsTask() => default;
public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext) => default;
public override bool Equals(object obj) => default;
public bool Equals(ValueTask other) => default;
public ValueTaskAwaiter GetAwaiter() => default;
public override int GetHashCode() => default;
public ValueTask Preserve() => default;
public static bool operator ==(ValueTask left, ValueTask right) => default;
public static bool operator !=(ValueTask left, ValueTask right) => default;
}
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]
public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>
{
public ValueTask(TResult result) {}
public ValueTask(Task<TResult> task) {}
public ValueTask(IValueTaskSource<TResult> source, short token) {}
public bool IsFaulted => default;
public bool IsCompletedSuccessfully => default;
public bool IsCompleted => default;
public bool IsCanceled => default;
public TResult Result => default;
public Task<TResult> AsTask() => default;
public ConfiguredValueTaskAwaitable<TResult> ConfigureAwait(bool continueOnCapturedContext) => default;
public bool Equals(ValueTask<TResult> other) => default;
public override bool Equals(object obj) => default;
public ValueTaskAwaiter<TResult> GetAwaiter() => default;
public override int GetHashCode() => default;
public ValueTask<TResult> Preserve() => default;
public override string ToString() => default;
public static bool operator ==(ValueTask<TResult> left, ValueTask<TResult> right) => default;
public static bool operator !=(ValueTask<TResult> left, ValueTask<TResult> right) => default;
}
}
namespace System.Collections.Generic
{
public interface IAsyncEnumerable<out T>
{
IAsyncEnumerator<T> GetAsyncEnumerator();
}
public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
System.Threading.Tasks.ValueTask<bool> MoveNextAsync();
T Current { get; }
}
}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -785,29 +785,6 @@ async IAsyncEnumerator<int> Test()
await TestInRegularAndScriptAsync(initial, expected);
}

const string IAsyncEnumerable = @"
namespace System
{
public interface IAsyncDisposable
{
ValueTask DisposeAsync();
}
}
namespace System.Collections.Generic
{
public interface IAsyncEnumerable<out T>
{
IAsyncEnumerator<T> GetAsyncEnumerator();
}
public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
ValueTask<bool> MoveNextAsync();
T Current { get; }
}
}";

[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeMethodAsynchronous)]
public async Task AwaitInMember()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,28 +826,5 @@ IEnumerator<int> M()
}
}" + IAsyncEnumerable);
}

private const string IAsyncEnumerable = @"
namespace System
{
public interface IAsyncDisposable
{
ValueTask DisposeAsync();
}
}
namespace System.Collections.Generic
{
public interface IAsyncEnumerable<out T>
{
IAsyncEnumerator<T> GetAsyncEnumerator();
}
public interface IAsyncEnumerator<out T> : IAsyncDisposable
{
ValueTask<bool> MoveNextAsync();
T Current { get; }
}
}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,11 @@ internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProvider

private static readonly TestParameters s_asyncStreamsFeature = new TestParameters(parseOptions: new CSharpParseOptions(LanguageVersion.CSharp8));

private readonly string AsyncStreams = @"
namespace System.Collections.Generic
{
public interface IAsyncEnumerable<out T>
{
IAsyncEnumerator<T> GetAsyncEnumerator();
}
public interface IAsyncEnumerator<out T> : System.IAsyncDisposable
{
System.Threading.Tasks.ValueTask<bool> MoveNextAsync();
T Current { get; }
}
}
namespace System
{
public interface IAsyncDisposable
{
System.Threading.Tasks.ValueTask DisposeAsync();
}
}
";

[Fact]
public async Task FixAllForeach()
{
await TestInRegularAndScript1Async(
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.Collections.Generic.IAsyncEnumerable<int> collection)
Expand All @@ -56,7 +33,7 @@ void M(System.Collections.Generic.IAsyncEnumerable<int> collection)
foreach (var j in collection) { }
}
}",
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.Collections.Generic.IAsyncEnumerable<int> collection)
Expand All @@ -71,7 +48,7 @@ void M(System.Collections.Generic.IAsyncEnumerable<int> collection)
public async Task FixAllForeachDeconstruction()
{
await TestInRegularAndScript1Async(
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.Collections.Generic.IAsyncEnumerable<(int, int)> collection)
Expand All @@ -80,7 +57,7 @@ void M(System.Collections.Generic.IAsyncEnumerable<(int, int)> collection)
foreach (var (k, l) in collection) { }
}
}",
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.Collections.Generic.IAsyncEnumerable<(int, int)> collection)
Expand All @@ -95,7 +72,7 @@ void M(System.Collections.Generic.IAsyncEnumerable<(int, int)> collection)
public async Task FixAllUsingStatement()
{
await TestInRegularAndScript1Async(
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.IAsyncDisposable disposable)
Expand All @@ -104,7 +81,7 @@ void M(System.IAsyncDisposable disposable)
using (var j = disposable) { }
}
}",
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.IAsyncDisposable disposable)
Expand All @@ -119,7 +96,7 @@ void M(System.IAsyncDisposable disposable)
public async Task FixAllUsingDeclaration()
{
await TestInRegularAndScript1Async(
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.IAsyncDisposable disposable)
Expand All @@ -128,7 +105,7 @@ void M(System.IAsyncDisposable disposable)
using var j = disposable;
}
}",
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.IAsyncDisposable disposable)
Expand All @@ -143,7 +120,7 @@ void M(System.IAsyncDisposable disposable)
public async Task FixForeach()
{
await TestInRegularAndScript1Async(
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.Collections.Generic.IAsyncEnumerable<int> collection)
Expand All @@ -153,7 +130,7 @@ void M(System.Collections.Generic.IAsyncEnumerable<int> collection)
}
}
}",
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.Collections.Generic.IAsyncEnumerable<int> collection)
Expand All @@ -169,7 +146,7 @@ void M(System.Collections.Generic.IAsyncEnumerable<int> collection)
public async Task FixForeachDeconstruction()
{
await TestInRegularAndScript1Async(
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.Collections.Generic.IAsyncEnumerable<(int, int)> collection)
Expand All @@ -179,7 +156,7 @@ void M(System.Collections.Generic.IAsyncEnumerable<(int, int)> collection)
}
}
}",
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.Collections.Generic.IAsyncEnumerable<(int, int)> collection)
Expand All @@ -195,7 +172,7 @@ void M(System.Collections.Generic.IAsyncEnumerable<(int, int)> collection)
public async Task FixUsingStatement()
{
await TestInRegularAndScript1Async(
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.IAsyncDisposable disposable)
Expand All @@ -205,7 +182,7 @@ void M(System.IAsyncDisposable disposable)
}
}
}",
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.IAsyncDisposable disposable)
Expand All @@ -221,15 +198,15 @@ void M(System.IAsyncDisposable disposable)
public async Task FixUsingDeclaration()
{
await TestInRegularAndScript1Async(
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.IAsyncDisposable disposable)
{
using var i = disposable[||];
}
}",
AsyncStreams + @"
IAsyncEnumerable + @"
class Program
{
void M(System.IAsyncDisposable disposable)
Expand Down
Loading

0 comments on commit a38b1e5

Please sign in to comment.