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();
		}
Ejemplo n.º 2
0
        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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
    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()));
    }
Ejemplo n.º 5
0
            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));
            }
Ejemplo n.º 6
0
        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);
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 10
0
        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);
        }
Ejemplo n.º 14
0
        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()));
            }
        }
Ejemplo n.º 18
0
 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);
        }
Ejemplo n.º 21
0
 internal static bool TryGetAwaitedInvocation(AwaitExpressionSyntax awaitExpression, [NotNullWhen(true)] out InvocationExpressionSyntax?result)
 {
     switch (awaitExpression)
     {
     case { Expression: InvocationExpressionSyntax invocation }
         when TryPeelConfigureAwait(invocation, out result) :
             return(true);
Ejemplo n.º 22
0
        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));
            }
        }
Ejemplo n.º 29
0
        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);
        }
Ejemplo n.º 30
0
 public static Doc Print(AwaitExpressionSyntax node)
 {
     return(Doc.Concat(
                Token.PrintWithSuffix(node.AwaitKeyword, " "),
                Node.Print(node.Expression)
                ));
 }
Ejemplo n.º 31
0
        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);
 }
Ejemplo n.º 33
0
        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);
        }
Ejemplo n.º 37
0
        private BoundExpression BindAwait(AwaitExpressionSyntax node, DiagnosticBag diagnostics)
        {
            BoundExpression expression = BindValue(node.Expression, diagnostics, BindValueKind.RValue);

            return BindAwait(expression, node, diagnostics);
        }
Ejemplo n.º 38
0
		public static CheckerResult CheckNode(AwaitExpressionSyntax awaitNode)
		{
			var possibleConfigureAwait = FindExpressionForConfigureAwait(awaitNode);
			var good = possibleConfigureAwait != null && IsProperConfigureAwait(possibleConfigureAwait);
			return new CheckerResult(good, awaitNode.GetLocation());
		}
Ejemplo n.º 39
0
        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;
        }
Ejemplo n.º 41
0
 /// <summary>
 /// Gets await expression info.
 /// </summary>
 /// <param name="node">The node.</param>
 public abstract AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node);
Ejemplo n.º 42
0
        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);
 }
Ejemplo n.º 44
0
 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);
 }
Ejemplo n.º 47
0
 public override AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node)
 {
     MemberSemanticModel memberModel = GetMemberModel(node);
     return memberModel == null ? default(AwaitExpressionInfo) : memberModel.GetAwaitExpressionInfo(node);
 }
Ejemplo n.º 48
0
            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();
            }
Ejemplo n.º 49
0
 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);
     }
 }
Ejemplo n.º 50
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="node"></param>
 public override sealed void VisitAwaitExpression(AwaitExpressionSyntax node)
 {
     this.OnNodeVisited(node);
     if (!this.traverseRootOnly) base.VisitAwaitExpression(node);
 }