static async Task<Document> Fix(Document document, AwaitExpressionSyntax node, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var expression = Checker.FindExpressionForConfigureAwait(node); if (expression != null) { if (!Checker.IsConfigureAwait(expression.Expression)) { var falseExpression = SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression); var newExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, expression, SyntaxFactory.IdentifierName(Checker.ConfigureAwaitIdentifier)), SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(falseExpression) }))); return document.WithSyntaxRoot(root.ReplaceNode(expression, newExpression.WithAdditionalAnnotations(Formatter.Annotation))); } if (!Checker.HasFalseArgument(expression.ArgumentList)) { var falseExpression = SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression); var newExpression = SyntaxFactory.InvocationExpression(expression.Expression, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(falseExpression) }))); return document.WithSyntaxRoot(root.ReplaceNode(expression, newExpression.WithAdditionalAnnotations(Formatter.Annotation))); } } else { var falseExpression = SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression); var newExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, node.Expression, SyntaxFactory.IdentifierName(Checker.ConfigureAwaitIdentifier)), SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(falseExpression) }))); return document.WithSyntaxRoot(root.ReplaceNode(node.Expression, newExpression.WithAdditionalAnnotations(Formatter.Annotation))); } throw new InvalidOperationException(); }
private static ExpressionSyntax TrySimplify(this AwaitExpressionSyntax awaitExpression, ExpressionSyntax originalSyntax, SemanticModel semanticModel, CancellationToken cancellationToken) { if (awaitExpression == null) { throw new ArgumentNullException(nameof(awaitExpression)); } // await Task.FromResult(x) => x. if (semanticModel != null) { var awaitedInvocation = awaitExpression.Expression as InvocationExpressionSyntax; var awaitedInvocationMemberAccess = awaitedInvocation?.Expression as MemberAccessExpressionSyntax; if (awaitedInvocationMemberAccess?.Name.Identifier.Text == nameof(Task.FromResult)) { // Is the FromResult method on the Task or Task<T> class? var memberOwnerSymbol = semanticModel.GetSymbolInfo(originalSyntax, cancellationToken).Symbol; if (Utils.IsTask(memberOwnerSymbol?.ContainingType)) { var simplified = awaitedInvocation.ArgumentList.Arguments.Single().Expression; return(simplified); } } } return(awaitExpression); }
/// <summary> /// Rewrites the await statement. /// </summary> /// <param name="node">ExpressionSyntax</param> /// <param name="model">SemanticModel</param> /// <returns>SyntaxNode</returns> private SyntaxNode RewriteStatement(ExpressionSyntax node, SemanticModel model) { AwaitExpressionSyntax awaitExpression = node as AwaitExpressionSyntax; ExpressionSyntax rewrittenNode = node; ITypeSymbol typeSymbol = model.GetTypeInfo(awaitExpression.Expression).Type; if (typeSymbol is INamedTypeSymbol) { string text = null; INamedTypeSymbol namedTypeSymbol = typeSymbol as INamedTypeSymbol; if (namedTypeSymbol.IsGenericType && namedTypeSymbol.TypeArguments.Count() == 1) { text = $"Microsoft.PSharp.Actors.ActorModel.GetResult<{namedTypeSymbol.TypeArguments[0]}>({awaitExpression.Expression})"; } else { text = $"Microsoft.PSharp.Actors.ActorModel.Wait({awaitExpression.Expression})"; } var waitExpression = SyntaxFactory.ParseExpression(text); waitExpression = waitExpression.WithTriviaFrom(node); rewrittenNode = waitExpression; } return(rewrittenNode); }
private static CheckResult CheckNode(AwaitExpressionSyntax awaitNode) { var possibleConfigureAwait = FindExpressionForConfigureAwait(awaitNode); var good = possibleConfigureAwait != null && IsConfigureAwait(possibleConfigureAwait.Expression) && HasFalseArgument(possibleConfigureAwait.ArgumentList); return(new CheckResult(good, awaitNode.GetLocation())); }
private static ExpressionSyntax ExtractExpressionFromAwait(AwaitExpressionSyntax awaitExpression, SemanticModel semanticModel, CancellationToken cancellationToken) { ExpressionSyntax expression = awaitExpression.Expression; var typeSymbol = semanticModel.GetTypeSymbol(expression, cancellationToken) as INamedTypeSymbol; if (typeSymbol != null) { if (typeSymbol.Equals(semanticModel.GetTypeByMetadataName(MetadataNames.System_Runtime_CompilerServices_ConfiguredTaskAwaitable)) || typeSymbol.ConstructedFrom.Equals(semanticModel.GetTypeByMetadataName(MetadataNames.System_Runtime_CompilerServices_ConfiguredTaskAwaitable_T))) { var invocation = expression as InvocationExpressionSyntax; if (invocation != null) { var memberAccess = invocation.Expression as MemberAccessExpressionSyntax; if (string.Equals(memberAccess?.Name?.Identifier.ValueText, "ConfigureAwait", StringComparison.Ordinal)) { expression = memberAccess.Expression; } } } } return(expression.WithTriviaFrom(awaitExpression)); }
private static HashSet <AwaitExpressionSyntax> GetAwaitExpressionsFromIfStatement( IfStatementSyntax ifStatement, bool endsWithElse) { HashSet <AwaitExpressionSyntax> awaitExpressions = null; foreach (IfStatementOrElseClause ifOrElse in ifStatement.GetChain()) { if (ifOrElse.IsElse && !endsWithElse) { return(null); } AwaitExpressionSyntax awaitExpression = GetLastReturnAwaitExpressionOfDefault(ifOrElse.Statement); if (awaitExpression != null) { (awaitExpressions ?? (awaitExpressions = new HashSet <AwaitExpressionSyntax>())).Add(awaitExpression); } else { return(null); } } return(awaitExpressions); }
private void AnalyzeAwaitExpression(SyntaxNodeAnalysisContext context) { AwaitExpressionSyntax awaitExpressionSyntax = (AwaitExpressionSyntax)context.Node; IdentifierNameSyntax identifierNameSyntaxAwaitingOn = awaitExpressionSyntax.Expression as IdentifierNameSyntax; if (identifierNameSyntaxAwaitingOn == null) { return; } SyntaxNode currentNode = identifierNameSyntaxAwaitingOn; // Step 1: Find the async delegate or lambda expression that matches the await SyntaxNode delegateOrLambdaNode = this.FindAsyncDelegateOrLambdaExpressiomMatchingAwait(awaitExpressionSyntax); if (delegateOrLambdaNode == null) { return; } // Step 2: Check whether it is called by Jtf.Run InvocationExpressionSyntax invocationExpressionSyntax = this.FindInvocationOfDelegateOrLambdaExpression(delegateOrLambdaNode); if (invocationExpressionSyntax == null || !this.IsInvocationExpressionACallToJtfRun(context, invocationExpressionSyntax)) { return; } this.ReportDiagnosticIfSymbolIsExternalTask(context, awaitExpressionSyntax.Expression, identifierNameSyntaxAwaitingOn, delegateOrLambdaNode); }
private static Task <Document> ChangeTypeAndAddAwait( Document document, SyntaxNode declaration, VariableDeclarationSyntax variableDeclaration, TypeSyntax type, ExpressionSyntax expression, ITypeSymbol newTypeSymbol, SemanticModel semanticModel, CancellationToken cancellationToken) { AwaitExpressionSyntax newExpression = SyntaxFactory.AwaitExpression(expression).WithTriviaFrom(expression); VariableDeclarationSyntax newVariableDeclaration = variableDeclaration.ReplaceNode(expression, newExpression); TypeSyntax newType = newTypeSymbol.ToMinimalTypeSyntax(semanticModel, type.SpanStart).WithTriviaFrom(type); newVariableDeclaration = newVariableDeclaration.WithType(newType); if (!SyntaxInfo.ModifierListInfo(declaration).IsAsync) { SyntaxNode newDeclaration = declaration .ReplaceNode(variableDeclaration, newVariableDeclaration) .InsertModifier(SyntaxKind.AsyncKeyword); return(document.ReplaceNodeAsync(declaration, newDeclaration, cancellationToken)); } return(document.ReplaceNodeAsync(variableDeclaration, newVariableDeclaration, cancellationToken)); }
private async Task <Solution> AddConfigureAwaitAsync(Document document, AwaitExpressionSyntax awaitSyntax, CancellationToken cancellationToken) { // Add .ConfigureAwait(false) to the operand of await var originalAwaitedExpression = awaitSyntax.Expression; var replacementAwaitedExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, originalAwaitedExpression, SyntaxFactory.IdentifierName("ConfigureAwait"))) .WithArgumentList( SyntaxFactory.ArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression))))); // Replace the original operand with the new one var replacementAwaitSyntax = awaitSyntax.WithExpression(replacementAwaitedExpression); // Replace the await in the syntax tree var root = await document.GetSyntaxRootAsync(cancellationToken); var updatedRoot = root.ReplaceNode(awaitSyntax, replacementAwaitSyntax); // Replace the syntax tree in the document var originalSolution = document.Project.Solution; var newSolution = originalSolution.WithDocumentSyntaxRoot(document.Id, updatedRoot); return(newSolution); }
public static Task <Document> ChangeTypeAndAddAwaitAsync( Document document, VariableDeclarationSyntax variableDeclaration, VariableDeclaratorSyntax variableDeclarator, SyntaxNode containingDeclaration, ITypeSymbol newTypeSymbol, CancellationToken cancellationToken) { TypeSyntax type = variableDeclaration.Type; ExpressionSyntax value = variableDeclarator.Initializer.Value; AwaitExpressionSyntax newValue = AwaitExpression(value.WithoutTrivia()).WithTriviaFrom(value); TypeSyntax newType = ChangeType(type, newTypeSymbol); VariableDeclarationSyntax newVariableDeclaration = variableDeclaration .ReplaceNode(value, newValue) .WithType(newType); if (!SyntaxInfo.ModifierListInfo(containingDeclaration).IsAsync) { SyntaxNode newDeclaration = containingDeclaration .ReplaceNode(variableDeclaration, newVariableDeclaration) .InsertModifier(SyntaxKind.AsyncKeyword); return(document.ReplaceNodeAsync(containingDeclaration, newDeclaration, cancellationToken)); } return(document.ReplaceNodeAsync(variableDeclaration, newVariableDeclaration, cancellationToken)); }
private static ExpressionSyntax RemoveAsyncKeywordFromLambdaExpression(LambdaExpressionSyntax lambdaExpression, AwaitExpressionSyntax awaitExpression) { if (lambdaExpression is SimpleLambdaExpressionSyntax simpleLambdaExpression) { return(simpleLambdaExpression.ReplaceNode(awaitExpression, awaitExpression.Expression) .WithAsyncKeyword(default)
private static async Task <Document> ChangeTypeAndAddAwaitAsync( Document document, VariableDeclarationSyntax variableDeclaration, ITypeSymbol typeSymbol, CancellationToken cancellationToken = default(CancellationToken)) { SyntaxNode oldRoot = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); ExpressionSyntax initializerValue = variableDeclaration.Variables[0].Initializer.Value; AwaitExpressionSyntax newInitializerValue = SyntaxFactory.AwaitExpression(initializerValue) .WithTriviaFrom(initializerValue); VariableDeclarationSyntax newNode = variableDeclaration.ReplaceNode(initializerValue, newInitializerValue); newNode = newNode .WithType( CSharpFactory.Type(typeSymbol) .WithTriviaFrom(variableDeclaration.Type) .WithSimplifierAnnotation()); SyntaxNode newRoot = oldRoot.ReplaceNode(variableDeclaration, newNode); return(document.WithSyntaxRoot(newRoot)); }
private bool TryHandleAwait(AwaitExpressionSyntax @await) { if (@await == null) { return(false); } if (AsyncAwait.TryGetAwaitedInvocation(@await, this.semanticModel, this.cancellationToken, out InvocationExpressionSyntax invocation)) { this.awaits = true; var symbol = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken); if (symbol != null) { if (symbol.DeclaringSyntaxReferences.Length == 0) { this.AddReturnValue(invocation); } else { return(this.TryHandleInvocation(invocation)); } } return(true); } return(false); }
private static AnalysisResult HasConfigureAwaitFalse(AwaitExpressionSyntax awaitNode) { InvocationExpressionSyntax configureAwaitExpression = FindConfigureAwaitExpression(awaitNode); bool hasConfigureAwaitFalse = configureAwaitExpression != null && IsExpressionConfigureAwaitFalse(configureAwaitExpression); return(new AnalysisResult(hasConfigureAwaitFalse, awaitNode.GetLocation())); }
private static void ChangeTypeAndAddAwait( CodeFixContext context, Diagnostic diagnostic, ExpressionSyntax expression, VariableDeclarationSyntax variableDeclaration, TypeSyntax type, ITypeSymbol newTypeSymbol, SemanticModel semanticModel) { AwaitExpressionSyntax newExpression = SyntaxFactory.AwaitExpression(expression).WithTriviaFrom(expression); VariableDeclarationSyntax newNode = variableDeclaration.ReplaceNode(expression, newExpression); TypeSyntax newType = newTypeSymbol.ToMinimalTypeSyntax(semanticModel, type.SpanStart).WithTriviaFrom(type); newNode = newNode.WithType(newType); string typeName = SymbolDisplay.ToMinimalDisplayString(newTypeSymbol, semanticModel, type.SpanStart, SymbolDisplayFormats.Default); CodeAction codeAction = CodeAction.Create( $"Change type to '{typeName}' and add await", cancellationToken => context.Document.ReplaceNodeAsync(variableDeclaration, newNode, cancellationToken), EquivalenceKey.Create(diagnostic, CodeFixIdentifiers.ChangeTypeAccordingToInitializer, "AddAwait")); context.RegisterCodeFix(codeAction, diagnostic); }
static async Task <Document> Fix(Document document, AwaitExpressionSyntax node, CancellationToken cancellationToken) { var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false); var(invocation, expression) = Checker.FindNodeFor(node); if (invocation != null) { if (!Checker.IsConfigureAwait(invocation.Expression)) { var falseExpression = SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression); var newExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, invocation, SyntaxFactory.IdentifierName(Checker.ConfigureAwaitIdentifier)), SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(falseExpression) }))); return(document.WithSyntaxRoot(root.ReplaceNode(invocation, newExpression.WithAdditionalAnnotations(Formatter.Annotation)))); } if (!Checker.HasFalseArgument(invocation.ArgumentList)) { var falseExpression = SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression); var newExpression = SyntaxFactory.InvocationExpression(invocation.Expression, SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(falseExpression) }))); return(document.WithSyntaxRoot(root.ReplaceNode(invocation, newExpression.WithAdditionalAnnotations(Formatter.Annotation)))); } } else { var falseExpression = SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression); var newExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, PrepareNode(expression), SyntaxFactory.IdentifierName(Checker.ConfigureAwaitIdentifier)), SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.Argument(falseExpression) }))); return(document.WithSyntaxRoot(root.ReplaceNode(expression, newExpression.WithAdditionalAnnotations(Formatter.Annotation))));
private void AnalyzeNode(SyntaxNodeAnalysisContext context) { AwaitExpressionSyntax awaitExpressionSyntax = (AwaitExpressionSyntax)context.Node; IdentifierNameSyntax identifierNameSyntaxAwaitingOn = awaitExpressionSyntax.Expression as IdentifierNameSyntax; if (identifierNameSyntaxAwaitingOn == null) { return; } SyntaxNode currentNode = identifierNameSyntaxAwaitingOn; // Step 1: Find the async delegate or lambda expression that matches the await SyntaxNode delegateOrLambdaNode = this.FindAsyncDelegateOrLambdaExpressiomMatchingAwait(awaitExpressionSyntax); if (delegateOrLambdaNode == null) { return; } // Step 2: Check whether it is called by Jtf.Run InvocationExpressionSyntax invocationExpressionSyntax = this.FindInvocationOfDelegateOrLambdaExpression(delegateOrLambdaNode); if (invocationExpressionSyntax == null || !this.IsInvocationExpressionACallToJtfRun(context, invocationExpressionSyntax)) { return; } // Step 3: Is the symbol we are waiting on a System.Threading.Tasks.Task SymbolInfo symbolAwaitingOn = context.SemanticModel.GetSymbolInfo(identifierNameSyntaxAwaitingOn); ILocalSymbol localSymbol = symbolAwaitingOn.Symbol as ILocalSymbol; if (localSymbol?.Type == null || localSymbol.Type.Name != nameof(Task) || !localSymbol.Type.BelongsToNamespace(Namespaces.SystemThreadingTasks)) { return; } // Step 4: Report warning if the task was not initialized within the current delegate or lambda expression BlockSyntax delegateBlock = this.GetBlockOfDelegateOrLambdaExpression(delegateOrLambdaNode); // Run data flow analysis to understand where the task was defined DataFlowAnalysis dataFlowAnalysis; // When possible (await is direct child of the block), execute data flow analysis by passing first and last statement to capture only what happens before the await // Check if the await is direct child of the code block (first parent is ExpressionStantement, second parent is the block itself) if (awaitExpressionSyntax.Parent.Parent.Equals(delegateBlock)) { dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(delegateBlock.ChildNodes().First(), awaitExpressionSyntax.Parent); } else { // Otherwise analyze the data flow for the entire block. One caveat: it doesn't distinguish if the initalization happens after the await. dataFlowAnalysis = context.SemanticModel.AnalyzeDataFlow(delegateBlock); } if (!dataFlowAnalysis.WrittenInside.Contains(symbolAwaitingOn.Symbol)) { context.ReportDiagnostic(Diagnostic.Create(Descriptor, awaitExpressionSyntax.Expression.GetLocation())); } }
private Doc PrintAwaitExpressionSyntax(AwaitExpressionSyntax node) { return(Concat( this.PrintSyntaxToken(node.AwaitKeyword, " "), this.Print(node.Expression) )); }
private bool IsTaskOfT(AwaitExpressionSyntax awaitExpression, SemanticModel semanticModel) { var type = semanticModel.GetTypeInfo(awaitExpression.Expression); return(type.Type?.UnwrapGenericIfNeeded()?.Equals( semanticModel.GetClrType(typeof(Task <>))) == true); }
public static bool CanRefactor( AwaitExpressionSyntax awaitExpression, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { if (awaitExpression == null) { throw new ArgumentNullException(nameof(awaitExpression)); } if (semanticModel == null) { throw new ArgumentNullException(nameof(semanticModel)); } ExpressionSyntax expression = awaitExpression.Expression; if (expression?.IsKind(SyntaxKind.InvocationExpression) == true) { var methodSymbol = semanticModel.GetSymbol(expression, cancellationToken) as IMethodSymbol; return(methodSymbol?.ReturnType.IsTaskOrDerivedFromTask(semanticModel) == true && semanticModel.GetTypeByMetadataName(MetadataNames.System_Runtime_CompilerServices_ConfiguredTaskAwaitable_T) != null); } return(false); }
internal static bool TryGetAwaitedInvocation(AwaitExpressionSyntax awaitExpression, [NotNullWhen(true)] out InvocationExpressionSyntax?result) { switch (awaitExpression) { case { Expression: InvocationExpressionSyntax invocation } when TryPeelConfigureAwait(invocation, out result) : return(true);
public static CheckerResult CheckNode(AwaitExpressionSyntax awaitNode) { var possibleConfigureAwait = FindExpressionForConfigureAwait(awaitNode); var good = possibleConfigureAwait != null && IsProperConfigureAwait(possibleConfigureAwait); return(new CheckerResult(good, awaitNode.GetLocation())); }
private static bool VerifyAwaitType(AwaitExpressionSyntax awaitExpression, ITypeSymbol typeArgument, SemanticModel semanticModel, CancellationToken cancellationToken) { if (!typeArgument.Equals(semanticModel.GetTypeSymbol(awaitExpression, cancellationToken))) { return(false); } ExpressionSyntax expression = awaitExpression.Expression; ITypeSymbol expressionTypeSymbol = semanticModel.GetTypeSymbol(expression, cancellationToken); if (expressionTypeSymbol == null) { return(false); } if (expressionTypeSymbol.OriginalDefinition.EqualsOrInheritsFrom(MetadataNames.System_Threading_Tasks_Task_T)) { return(true); } SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(expression); return(invocationInfo.Success && invocationInfo.Arguments.Count == 1 && invocationInfo.NameText == "ConfigureAwait" && expressionTypeSymbol.OriginalDefinition.HasMetadataName(MetadataNames.System_Runtime_CompilerServices_ConfiguredTaskAwaitable_T)); }
private static bool VerifyTypes( SyntaxNode node, AwaitExpressionSyntax awaitExpression, SemanticModel semanticModel, CancellationToken cancellationToken) { IMethodSymbol methodSymbol = GetMethodSymbol(node, semanticModel, cancellationToken); if (methodSymbol == null) { return(false); } ITypeSymbol returnType = methodSymbol.ReturnType; if (returnType?.OriginalDefinition.EqualsOrInheritsFrom(MetadataNames.System_Threading_Tasks_Task_T) != true) { return(false); } ITypeSymbol typeArgument = ((INamedTypeSymbol)returnType).TypeArguments.SingleOrDefault(shouldThrow: false); if (typeArgument == null) { return(false); } return(VerifyAwaitType(awaitExpression, typeArgument, semanticModel, cancellationToken)); }
private static bool VerifySwitchStatement( SwitchStatementSyntax switchStatement, int expectedCount, bool containsDefaultSection) { int count = 0; foreach (SwitchSectionSyntax section in switchStatement.Sections) { if (section.ContainsDefaultLabel() && !containsDefaultSection) { return(false); } AwaitExpressionSyntax awaitExpression = GetAwaitExpression(section.Statements.LastOrDefault()); if (awaitExpression == null) { return(false); } count++; } return(expectedCount == count); }
private static bool VerifyIfStatement( IfStatementSyntax ifStatement, int expectedCount, bool endsWithElse) { int count = 0; foreach (IfStatementOrElseClause ifOrElse in ifStatement.AsCascade()) { if (ifOrElse.IsElse && !endsWithElse) { return(false); } AwaitExpressionSyntax awaitExpression = GetAwaitExpression(ifOrElse.Statement); if (awaitExpression == null) { return(false); } count++; } return(expectedCount == count); }
public static async Task <Document> RefactorAsync( Document document, AwaitExpressionSyntax awaitExpressionSyntax, CancellationToken cancellationToken = default(CancellationToken)) { if (document == null) { throw new ArgumentNullException(nameof(document)); } if (awaitExpressionSyntax == null) { throw new ArgumentNullException(nameof(awaitExpressionSyntax)); } SyntaxNode root = await document .GetSyntaxRootAsync(cancellationToken) .ConfigureAwait(false); var invocation = (InvocationExpressionSyntax)awaitExpressionSyntax.Expression; InvocationExpressionSyntax newInvocation = InvocationExpression( SimpleMemberAccessExpression(invocation.WithoutTrailingTrivia(), IdentifierName("ConfigureAwait")), ArgumentList(Argument(FalseLiteralExpression()))); newInvocation = newInvocation.WithTrailingTrivia(invocation.GetTrailingTrivia()); root = root.ReplaceNode(invocation, newInvocation); return(document.WithSyntaxRoot(root)); }
public static CheckerResult CheckNode(AwaitExpressionSyntax awaitNode, SemanticModel semanticModel) { var location = awaitNode.GetLocation(); var possibleConfigureAwait = FindExpressionForConfigureAwait(awaitNode); if (possibleConfigureAwait != null && IsConfigureAwait(possibleConfigureAwait.Expression)) { if (HasFalseArgument(possibleConfigureAwait.ArgumentList)) { return(new CheckerResult(CheckerProblem.NoProblem, location)); } else { return(new CheckerResult(CheckerProblem.ConfigureAwaitWithTrue, location)); } } else { var can = CanHaveConfigureAwait(awaitNode.Expression, semanticModel); var problem = can ? CheckerProblem.MissingConfigureAwaitFalse : CheckerProblem.NoProblem; return(new CheckerResult(problem, location)); } }
private static bool MustUseConfigureAwait(SyntaxNodeAnalysisContext context, AwaitExpressionSyntax node) { if (HasPreviousConfigureAwait(context, node)) { return(true); } var containingClass = GetParentSymbol <INamedTypeSymbol>(context.SemanticModel, node, context.CancellationToken); if (containingClass != null) { if (containingClass.InheritsFrom(context.Compilation.GetTypeByMetadataName("System.Windows.Threading.DispatcherObject")) || // WPF containingClass.Implements(context.Compilation.GetTypeByMetadataName("System.Windows.Input.ICommand")) || // WPF containingClass.InheritsFrom(context.Compilation.GetTypeByMetadataName("System.Windows.Forms.Control")) || // WinForms containingClass.InheritsFrom(context.Compilation.GetTypeByMetadataName("System.Web.UI.WebControls.WebControl")) || // ASP.NET (Webforms) containingClass.InheritsFrom(context.Compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.ControllerBase")) || // ASP.NET Core (as there is no SynchronizationContext, ConfigureAwait(false) is useless) containingClass.Implements(context.Compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.Razor.IRazorPage")) || // ASP.NET Core containingClass.Implements(context.Compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Razor.TagHelpers.ITagHelper")) || // ASP.NET Core containingClass.Implements(context.Compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Razor.TagHelpers.ITagHelperComponent")) || // ASP.NET Core containingClass.Implements(context.Compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Mvc.Filters.IFilterMetadata")) || containingClass.Implements(context.Compilation.GetTypeByMetadataName("Microsoft.AspNetCore.Components.IComponent"))) // Blazor has a synchronization context, see https://github.com/meziantou/Meziantou.Analyzer/issues/96 { return(false); } } var containingMethod = GetParentSymbol <IMethodSymbol>(context.SemanticModel, node, context.CancellationToken); if (containingMethod != null && containingMethod.IsUnitTestMethod()) { return(false); } return(true); }
public static Doc Print(AwaitExpressionSyntax node) { return(Doc.Concat( Token.PrintWithSuffix(node.AwaitKeyword, " "), Node.Print(node.Expression) )); }
private static ExpressionSyntax TrySimplify(this AwaitExpressionSyntax awaitExpression, ExpressionSyntax originalSyntax, SemanticModel semanticModel) { if (awaitExpression == null) { throw new ArgumentNullException(nameof(awaitExpression)); } // await Task.FromResult(x) => x. if (semanticModel != null) { var awaitedInvocation = awaitExpression.Expression as InvocationExpressionSyntax; var awaitedInvocationMemberAccess = awaitedInvocation?.Expression as MemberAccessExpressionSyntax; if (awaitedInvocationMemberAccess?.Name.Identifier.Text == nameof(Task.FromResult)) { // Is the FromResult method on the Task or Task<T> class? var memberOwnerSymbol = semanticModel.GetSymbolInfo(originalSyntax).Symbol; if (memberOwnerSymbol?.ContainingType?.Name == nameof(Task) && memberOwnerSymbol.ContainingType.BelongsToNamespace(Namespaces.SystemThreadingTasks)) { var simplified = awaitedInvocation.ArgumentList.Arguments.Single().Expression; return simplified; } } } return awaitExpression; }
private async Task<Document> AddConfigureAwait(Document document, AwaitExpressionSyntax awaitSyntax, bool value, CancellationToken cancellationToken) { var oldExpression = awaitSyntax.Expression; var newExpression = SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, oldExpression, SyntaxFactory.IdentifierName("ConfigureAwait")), SyntaxFactory.ArgumentList( SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument( SyntaxFactory.LiteralExpression( value ? SyntaxKind.TrueLiteralExpression : SyntaxKind.FalseLiteralExpression))))); return await document.ReplaceAsync(oldExpression, newExpression, cancellationToken).ConfigureAwait(false); }
public override AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node) { if (node.Kind() != SyntaxKind.AwaitExpression) { throw new ArgumentException("node.Kind==" + node.Kind()); } var bound = GetUpperBoundNode(node); BoundAwaitExpression boundAwait = ((bound as BoundExpressionStatement)?.Expression ?? bound) as BoundAwaitExpression; if (boundAwait == null) { return default(AwaitExpressionInfo); } return new AwaitExpressionInfo(boundAwait.GetAwaiter, boundAwait.IsCompleted, boundAwait.GetResult, boundAwait.IsDynamic); }
private ProgramState ProcessAwait(ProgramState programState, AwaitExpressionSyntax awaitExpression) { var identifier = awaitExpression.Expression as IdentifierNameSyntax; if (identifier == null) { return programState; } var symbol = semanticModel.GetSymbolInfo(identifier).Symbol; return ProcessIdentifier(programState, identifier, symbol); }
private IEnumerable<ITypeSymbol> InferTypeInAwaitExpression(AwaitExpressionSyntax awaitExpression, SyntaxToken? previousToken = null) { // If we have a position, then we must be after the prefix token. Contract.ThrowIfTrue(previousToken.HasValue && previousToken.Value != awaitExpression.AwaitKeyword); // await <expression> var types = InferTypes(awaitExpression); var task = this.Compilation.TaskType(); var taskOfT = this.Compilation.TaskOfTType(); if (task == null || taskOfT == null) { return SpecializedCollections.EmptyEnumerable<ITypeSymbol>(); } if (!types.Any()) { return SpecializedCollections.SingletonEnumerable(task); } return types.Select(t => t.SpecialType == SpecialType.System_Void ? task : taskOfT.Construct(t)); }
private static void AddAwaitExpressionTerms(AwaitExpressionSyntax awaitExpression, IList<string> terms, ref ExpressionType expressionType) { expressionType = ExpressionType.Invalid; var flags = ExpressionType.Invalid; // Ask our subexpression for terms AddSubExpressionTerms(awaitExpression.Expression, terms, ref flags); // Is our expression a valid term? AddIfValidTerm(awaitExpression.Expression, flags, terms); }
private BoundExpression BindAwait(AwaitExpressionSyntax node, DiagnosticBag diagnostics) { BoundExpression expression = BindValue(node.Expression, diagnostics, BindValueKind.RValue); return BindAwait(expression, node, diagnostics); }
public static CheckerResult CheckNode(AwaitExpressionSyntax awaitNode) { var possibleConfigureAwait = FindExpressionForConfigureAwait(awaitNode); var good = possibleConfigureAwait != null && IsProperConfigureAwait(possibleConfigureAwait); return new CheckerResult(good, awaitNode.GetLocation()); }
private BoundExpression HoistExpression( BoundExpression expr, AwaitExpressionSyntax awaitSyntaxOpt, int syntaxOffset, bool isRef, ArrayBuilder<BoundExpression> sideEffects, ArrayBuilder<StateMachineFieldSymbol> hoistedFields, ref bool needsSacrificialEvaluation) { switch (expr.Kind) { case BoundKind.ArrayAccess: { var array = (BoundArrayAccess)expr; BoundExpression expression = HoistExpression(array.Expression, awaitSyntaxOpt, syntaxOffset, false, sideEffects, hoistedFields, ref needsSacrificialEvaluation); var indices = ArrayBuilder<BoundExpression>.GetInstance(); foreach (var index in array.Indices) { indices.Add(HoistExpression(index, awaitSyntaxOpt, syntaxOffset, false, sideEffects, hoistedFields, ref needsSacrificialEvaluation)); } needsSacrificialEvaluation = true; // need to force array index out of bounds exceptions return array.Update(expression, indices.ToImmutableAndFree(), array.Type); } case BoundKind.FieldAccess: { var field = (BoundFieldAccess)expr; if (field.FieldSymbol.IsStatic) { // the address of a static field, and the value of a readonly static field, is stable if (isRef || field.FieldSymbol.IsReadOnly) return expr; goto default; } if (!isRef) { goto default; } var isFieldOfStruct = !field.FieldSymbol.ContainingType.IsReferenceType; var receiver = HoistExpression(field.ReceiverOpt, awaitSyntaxOpt, syntaxOffset, isFieldOfStruct, sideEffects, hoistedFields, ref needsSacrificialEvaluation); if (receiver.Kind != BoundKind.ThisReference && !isFieldOfStruct) { needsSacrificialEvaluation = true; // need the null check in field receiver } return F.Field(receiver, field.FieldSymbol); } case BoundKind.ThisReference: case BoundKind.BaseReference: case BoundKind.DefaultOperator: return expr; default: if (expr.ConstantValue != null) { return expr; } if (isRef) { throw ExceptionUtilities.UnexpectedValue(expr.Kind); } TypeSymbol fieldType = expr.Type; StateMachineFieldSymbol hoistedField; if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug) { const SynthesizedLocalKind kind = SynthesizedLocalKind.AwaitByRefSpill; Debug.Assert(awaitSyntaxOpt != null); int ordinal = _synthesizedLocalOrdinals.AssignLocalOrdinal(kind, syntaxOffset); var id = new LocalDebugId(syntaxOffset, ordinal); // Editing await expression is not allowed. Thus all spilled fields will be present in the previous state machine. // However, it may happen that the type changes, in which case we need to allocate a new slot. int slotIndex; if (slotAllocatorOpt == null || !slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex( awaitSyntaxOpt, F.ModuleBuilderOpt.Translate(fieldType, awaitSyntaxOpt, Diagnostics), kind, id, Diagnostics, out slotIndex)) { slotIndex = _nextFreeHoistedLocalSlot++; } string fieldName = GeneratedNames.MakeHoistedLocalFieldName(kind, slotIndex); hoistedField = F.StateMachineField(expr.Type, fieldName, new LocalSlotDebugInfo(kind, id), slotIndex); } else { hoistedField = GetOrAllocateReusableHoistedField(fieldType); } hoistedFields.Add(hoistedField); var replacement = F.Field(F.This(), hoistedField); sideEffects.Add(F.AssignmentExpression(replacement, expr)); return replacement; } }
private bool IsTaskOfT(AwaitExpressionSyntax awaitExpression, SemanticModel semanticModel) { var type = semanticModel.GetTypeInfo(awaitExpression.Expression); return type.Type?.UnwrapGenericIfNeeded()?.Equals( semanticModel.GetClrType(typeof(Task<>))) == true; }
/// <summary> /// Gets await expression info. /// </summary> /// <param name="node">The node.</param> public abstract AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node);
public void VisitAwaitExpression(AwaitExpressionSyntax node) { if (node == null) throw new ArgumentNullException("node"); node.Validate(); ExpressionStart(node); _writer.WriteKeyword(PrinterKeyword.Await); _writer.WriteSpace(); node.Expression.Accept(this); ExpressionEnd(node); }
/// <summary> /// /// </summary> /// <param name="node"></param> public override sealed void VisitAwaitExpression(AwaitExpressionSyntax node) { this.OnNodeVisited(node, this.type.IsInstanceOfType(node)); base.VisitAwaitExpression(node); }
public override void VisitAwaitExpression(AwaitExpressionSyntax node) { _containsAwait = true; }
public override void VisitAwaitExpression(AwaitExpressionSyntax node) { Fail = true; }
public AwaitExpressionTranslation(AwaitExpressionSyntax syntax, SyntaxTranslation parent) : base(syntax, parent) { Expression = syntax.Expression.Get<ExpressionTranslation>(this); }
public override AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node) { MemberSemanticModel memberModel = GetMemberModel(node); return memberModel == null ? default(AwaitExpressionInfo) : memberModel.GetAwaitExpressionInfo(node); }
public override JsNode VisitAwaitExpression(AwaitExpressionSyntax node) { var operand = (JsExpression)node.Expression.Accept(this); /* var expressionInfo = stateGenerator.Transformer.model.GetAwaitExpressionInfo(node); if (expressionInfo.GetResultMethod == null) { var classText = node.FirstAncestorOrSelf<ClassDeclarationSyntax>().NormalizeWhitespace().ToString(); var diagnostics = model.GetDiagnostics().Select(x => x.ToString()).ToArray(); } var returnsVoid = expressionInfo.GetResultMethod.ReturnsVoid; */ var expressionInfo = stateGenerator.Transformer.model.GetTypeInfo(node).ConvertedType; var returnsVoid = expressionInfo.SpecialType == SpecialType.System_Void; var operandType = model.GetTypeInfo(node.Expression).ConvertedType; var awaiterMethodName = ((INamedTypeSymbol)operandType).GetMethodByName("GetAwaiter").GetMemberName(); // Store the awaiter in a field var awaiterIdentifier = stateGenerator.HoistVariable(new LiftedVariableKey("$awaiter")); var awaiter = awaiterIdentifier.GetReference(); stateGenerator.CurrentState.Add(awaiter.Assign(operand.Member(awaiterMethodName).Invoke()).Express()); var nextState = stateGenerator.InsertState(); JsExpression result = null; if (!returnsVoid) { // If the await returns a value, store it in a field var resultIdentifier = stateGenerator.HoistVariable(new LiftedVariableKey("$result")); result = resultIdentifier.GetReference(); // Make sure the field gets set from the awaiter at the beginning of the next state. nextState.Add(result.Assign(awaiter.Member("GetResult").Invoke()).Express()); } else { // We still need to call GetResult even if void in order to propagate exceptions nextState.Add(awaiter.Member("GetResult").Invoke().Express()); } // Set the state to the next state stateGenerator.CurrentState.Add(stateGenerator.ChangeState(nextState)); stateGenerator.CurrentState.Add(Js.If( awaiter.Member("get_IsCompleted").Invoke(), // If the awaiter is already completed, go to the next state stateGenerator.GotoTop(), // Otherwise await for completion Js.Block( // Start the async process Js.Reference(builder) .Member("TrueAwaitOnCompleted") .Invoke(awaiterIdentifier.GetReference(), Js.Reference(stateMachine)) .Express(), Js.Return() ) )); stateGenerator.CurrentState = nextState; return result ?? Js.Null(); }
public override AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node) { using (Logger.LogBlock(FunctionId.CSharp_SemanticModel_GetAwaitExpressionInfo, message: this.SyntaxTree.FilePath)) { MemberSemanticModel memberModel = GetMemberModel(node); return memberModel == null ? default(AwaitExpressionInfo) : memberModel.GetAwaitExpressionInfo(node); } }
/// <summary> /// /// </summary> /// <param name="node"></param> public override sealed void VisitAwaitExpression(AwaitExpressionSyntax node) { this.OnNodeVisited(node); if (!this.traverseRootOnly) base.VisitAwaitExpression(node); }