示例#1
0
        private static void UpdateInvocationLocation(
            SyntaxNodeAnalysisContext context,
            ISymbol symbol,
            SimpleNameSyntax currentAccessNode,
            GetAccessInfoDelegate getAccessInfo)
        {
            var symbolInfo = _applicationBuilderSymbolInfos.GetOrCreateValue(symbol);

            var scopeEnclosingNode =
                currentAccessNode.FirstAncestorOrSelf <CSharpSyntaxNode>(IsScopeEnclosingNode);

            lock (symbolInfo)
            {
                if (!symbolInfo.Scopes.TryGetValue(scopeEnclosingNode, out var scopeInfo))
                {
                    symbolInfo.Scopes[scopeEnclosingNode] = scopeInfo = new ScopeInfo();
                }

                if (scopeInfo.DiagnosticReported)
                {
                    return;
                }

                ref var existingAccessInfo = ref getAccessInfo(scopeInfo);

                if (existingAccessInfo.location == null ||
                    currentAccessNode.GetLocation().SourceSpan.Start < existingAccessInfo.location.SourceSpan.Start)
                {
                    existingAccessInfo = (currentAccessNode.GetLocation(), currentAccessNode.ToString());
                    VerifyInvocationOrder(context, scopeInfo);
                }
            }
        private void IsAccessingThreadDotSleep(SimpleNameSyntax invokedFunction, SyntaxNodeAnalysisContext context, bool isAsync)
        {
            var invokedSymbol = context.SemanticModel.GetSymbolInfo(invokedFunction).Symbol;

            if (invokedSymbol == null)
            {
                return;
            }

            var isAccessedFunctionCorrect = invokedSymbol.Name == "Sleep";
            var isAccessedTypeCorrect     = invokedSymbol.ContainingType?.Name == "Thread";

            if (isAccessedFunctionCorrect && isAccessedTypeCorrect)
            {
                var dic = ImmutableDictionary.CreateBuilder <string, string>();
                dic.Add("isAsync", isAsync.ToString());

                var invocationNode = invokedFunction.FirstAncestorOrSelf <InvocationExpressionSyntax>();
                context.ReportDiagnostic(Diagnostic.Create(Rule, invocationNode.GetLocation(), dic.ToImmutable(), null));
            }
        }
            protected override async Task <Solution> GetChangedSolutionAsync(CancellationToken cancellationToken)
            {
                var document = this.document;
                var root     = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                // Find the synchronously blocking call member,
                // and bookmark it so we can find it again after some mutations have taken place.
                var syncAccessBookmark          = new SyntaxAnnotation();
                SimpleNameSyntax syncMethodName = (SimpleNameSyntax)root.FindNode(this.diagnostic.Location.SourceSpan);

                if (syncMethodName == null)
                {
                    var syncMemberAccess = root.FindNode(this.diagnostic.Location.SourceSpan).FirstAncestorOrSelf <MemberAccessExpressionSyntax>();
                    syncMethodName = syncMemberAccess.Name;
                }

                // When we give the Document a modified SyntaxRoot, yet another is created. So we first assign it to the Document,
                // then we query for the SyntaxRoot from the Document.
                document = document.WithSyntaxRoot(
                    root.ReplaceNode(syncMethodName, syncMethodName.WithAdditionalAnnotations(syncAccessBookmark)));
                root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

                syncMethodName = (SimpleNameSyntax)root.GetAnnotatedNodes(syncAccessBookmark).Single();

                // We'll need the semantic model later. But because we've annotated a node, that changes the SyntaxRoot
                // and that renders the default semantic model broken (even though we've already updated the document's SyntaxRoot?!).
                // So after acquiring the semantic model, update it with the new method body.
                var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                var originalAnonymousMethodContainerIfApplicable = syncMethodName.FirstAncestorOrSelf <AnonymousFunctionExpressionSyntax>();
                var originalMethodDeclaration = syncMethodName.FirstAncestorOrSelf <MethodDeclarationSyntax>();

                // Ensure that the method or anonymous delegate is using the async keyword.
                MethodDeclarationSyntax updatedMethod;

                if (originalAnonymousMethodContainerIfApplicable != null)
                {
                    updatedMethod = originalMethodDeclaration.ReplaceNode(
                        originalAnonymousMethodContainerIfApplicable,
                        originalAnonymousMethodContainerIfApplicable.MakeMethodAsync(semanticModel, cancellationToken));
                }
                else
                {
                    (document, updatedMethod) = await originalMethodDeclaration.MakeMethodAsync(document, cancellationToken).ConfigureAwait(false);

                    semanticModel = null; // out-dated
                }

                if (updatedMethod != originalMethodDeclaration)
                {
                    // Re-discover our synchronously blocking member.
                    syncMethodName = (SimpleNameSyntax)updatedMethod.GetAnnotatedNodes(syncAccessBookmark).Single();
                }

                var syncExpression = (ExpressionSyntax)syncMethodName.FirstAncestorOrSelf <InvocationExpressionSyntax>() ?? syncMethodName.FirstAncestorOrSelf <MemberAccessExpressionSyntax>();

                ExpressionSyntax awaitExpression;

                if (this.AlternativeAsyncMethod != string.Empty)
                {
                    // Replace the member being called and await the invocation expression.
                    // While doing so, move leading trivia to the surrounding await expression.
                    var asyncMethodName = syncMethodName.WithIdentifier(SyntaxFactory.Identifier(this.diagnostic.Properties[AsyncMethodKeyName]));
                    awaitExpression = SyntaxFactory.AwaitExpression(
                        syncExpression.ReplaceNode(syncMethodName, asyncMethodName).WithoutLeadingTrivia())
                                      .WithLeadingTrivia(syncExpression.GetLeadingTrivia());
                    if (!(syncExpression.Parent is ExpressionStatementSyntax))
                    {
                        awaitExpression = SyntaxFactory.ParenthesizedExpression(awaitExpression)
                                          .WithAdditionalAnnotations(Simplifier.Annotation);
                    }
                }
                else
                {
                    // Remove the member being accessed that causes a synchronous block and simply await the object.
                    var syncMemberAccess             = syncMethodName.FirstAncestorOrSelf <MemberAccessExpressionSyntax>();
                    var syncMemberStrippedExpression = syncMemberAccess.Expression;

                    // Special case a common pattern of calling task.GetAwaiter().GetResult() and remove both method calls.
                    var expressionMethodCall = (syncMemberStrippedExpression as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax;
                    if (expressionMethodCall?.Name.Identifier.Text == nameof(Task.GetAwaiter))
                    {
                        syncMemberStrippedExpression = expressionMethodCall.Expression;
                    }

                    awaitExpression = SyntaxFactory.AwaitExpression(syncMemberStrippedExpression.WithoutLeadingTrivia())
                                      .WithLeadingTrivia(syncMemberStrippedExpression.GetLeadingTrivia());
                }

                updatedMethod = updatedMethod
                                .ReplaceNode(syncExpression, awaitExpression);

                var newRoot     = root.ReplaceNode(originalMethodDeclaration, updatedMethod);
                var newDocument = document.WithSyntaxRoot(newRoot);

                return(newDocument.Project.Solution);
            }