-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Closed
Labels
Area-CompilersConcept-APIThis issue involves adding, removing, clarification, or modification of an API.This issue involves adding, removing, clarification, or modification of an API.Feature - Runtime Asyncapi-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedblockingAPI needs to reviewed with priority to unblock workAPI needs to reviewed with priority to unblock work
Milestone
Description
Background and Motivation
Followup to #79818; in using the API in the SDK analyzers, we've realized that we also need async info for using declarations (both statement and local decl),
as well as await foreach. This adds APIs for accessing this information.
Proposed API
namespace Microsoft.CodeAnalysis.CSharp
{
public static class CSharpExtensions
{
+ public static AwaitExpressionInfo GetAwaitExpressionInfo(this SemanticModel? semanticModel, LocalDeclarationStatementSyntax awaitExpression);
+ public static AwaitExpressionInfo GetAwaitExpressionInfo(this SemanticModel? semanticModel, UsingStatementSyntax awaitExpression);
}
public class CSharpSemanticModel
{
+ public AwaitExpressionInfo GetAwaitExpressionInfo(LocalDeclarationStatementSyntax awaitExpression);
+ public AwaitExpressionInfo GetAwaitExpressionInfo(UsingStatementSyntax awaitExpression);
}
public struct ForEachStatementInfo
{
+ /// <summary>
+ /// Gets the awaitable info for the <see cref="MoveNextMethod"/> in an asynchronous foreach. <see langword="default"/> if this is a synchronous foreach.
+ /// </summary>
+ public AwaitExpressionInfo MoveNextAwaitableInfo { get; }
+ /// <summary>
+ /// Gets the awaitable info for the <see cref="DisposeMethod"/> in an asynchronous foreach. <see langword="default"/> if this is a synchronous foreach.
+ /// </summary>
+ public AwaitExpressionInfo DisposeAwaitableInfo { get; }
}
}Usage Examples
Await Using Declaration
// Analyze await using declaration
var tree = compilation.SyntaxTrees.First();
var model = compilation.GetSemanticModel(tree);
var awaitUsingDeclaration = tree.GetRoot()
.DescendantNodes()
.OfType<LocalDeclarationStatementSyntax>()
.First(n => n.AwaitKeyword.IsKind(SyntaxKind.AwaitKeyword));
var awaitInfo = model.GetAwaitExpressionInfo(awaitUsingDeclaration);
Console.WriteLine($"GetAwaiter: {awaitInfo.GetAwaiterMethod}");
Console.WriteLine($"IsCompleted: {awaitInfo.IsCompletedProperty}");
Console.WriteLine($"GetResult: {awaitInfo.GetResultMethod}");Await Using Statement
// Analyze await using statement
var awaitUsingStatement = tree.GetRoot()
.DescendantNodes()
.OfType<UsingStatementSyntax>()
.First(n => n.AwaitKeyword.IsKind(SyntaxKind.AwaitKeyword));
var awaitInfo = model.GetAwaitExpressionInfo(awaitUsingStatement);
// Access awaitable information for the dispose operationAwait Foreach
// Analyze await foreach statement
var awaitForeachStatement = tree.GetRoot()
.DescendantNodes()
.OfType<ForEachStatementSyntax>()
.First(n => n.AwaitKeyword.IsKind(SyntaxKind.AwaitKeyword));
var foreachInfo = model.GetForEachStatementInfo(awaitForeachStatement);
// Access awaitable info for MoveNextAsync()
var moveNextAwaitInfo = foreachInfo.MoveNextAwaitableInfo;
Console.WriteLine($"MoveNext GetAwaiter: {moveNextAwaitInfo.GetAwaiterMethod}");
// Access awaitable info for DisposeAsync()
var disposeAwaitInfo = foreachInfo.DisposeAwaitableInfo;
Console.WriteLine($"Dispose GetAwaiter: {disposeAwaitInfo.GetAwaiterMethod}");Alternative Designs
Risks
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Area-CompilersConcept-APIThis issue involves adding, removing, clarification, or modification of an API.This issue involves adding, removing, clarification, or modification of an API.Feature - Runtime Asyncapi-approvedAPI was approved in API review, it can be implementedAPI was approved in API review, it can be implementedblockingAPI needs to reviewed with priority to unblock workAPI needs to reviewed with priority to unblock work