Пример #1
0
        private bool TryHandleAwait(AwaitExpressionSyntax awaitExpression)
        {
            if (AsyncAwait.TryGetAwaitedInvocation(awaitExpression, this.semanticModel, this.cancellationToken, out var invocation) &&
                this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken) is ISymbol symbol)
            {
                if (symbol.TrySingleDeclaration(this.cancellationToken, out MemberDeclarationSyntax declaration) &&
                    declaration is MethodDeclarationSyntax methodDeclaration)
                {
                    if (methodDeclaration.Modifiers.Any(SyntaxKind.AsyncKeyword))
                    {
                        return(this.TryHandleInvocation(invocation, out _));
                    }

                    if (this.TryGetRecursive(awaitExpression, declaration, out var walker))
                    {
                        foreach (var value in walker.returnValues)
                        {
                            AwaitValue(value);
                        }
                    }
                }
                else
                {
                    AwaitValue(invocation);
                }

                this.returnValues.RemoveAll(x => IsParameter(x));
                return(true);
            }

            return(false);

            void AwaitValue(ExpressionSyntax expression)
            {
                if (AsyncAwait.TryAwaitTaskFromResult(expression, this.semanticModel, this.cancellationToken, out var awaited))
                {
                    if (awaited is IdentifierNameSyntax identifierName &&
                        symbol is IMethodSymbol method &&
                        method.Parameters.TryFirst(x => x.Name == identifierName.Identifier.ValueText, out var parameter))
                    {
                        if (this.search != ReturnValueSearch.RecursiveInside &&
                            invocation.TryFindArgument(parameter, out var argument))
                        {
                            this.AddReturnValue(argument.Expression);
                        }
                        else if (parameter.HasExplicitDefaultValue &&
                                 parameter.TrySingleDeclaration(this.cancellationToken, out var parameterDeclaration))
                        {
                            this.returnValues.Add(parameterDeclaration.Default?.Value);
                        }
                    }

                    this.AddReturnValue(awaited);
                }
                else if (AsyncAwait.TryAwaitTaskRun(expression, this.semanticModel, this.cancellationToken, out awaited))
                {
                    if (this.TryGetRecursive(awaited, awaited, out var walker))
                    {
                        foreach (var value in walker.returnValues)
                        {
                            AwaitValue(value);
                        }
                    }
                }
                else
                {
                    this.AddReturnValue(expression);
                }
            }

            bool IsParameter(ExpressionSyntax value)
            {
                return(value is IdentifierNameSyntax id &&
                       symbol is IMethodSymbol method &&
                       method.Parameters.TryFirst(x => x.Name == id.Identifier.ValueText, out _));
            }
        }
        private void AddReturnValue(ExpressionSyntax value)
        {
            if (this.awaits)
            {
                if (AsyncAwait.TryAwaitTaskRun(value, this.semanticModel, this.cancellationToken, out ExpressionSyntax awaited))
                {
                    using (var pooled = this.GetRecursive(awaited))
                    {
                        if (pooled.Item.values.Count == 0)
                        {
                            this.values.Add(awaited);
                        }
                        else
                        {
                            foreach (var returnValue in pooled.Item.values)
                            {
                                this.AddReturnValue(returnValue);
                            }
                        }
                    }

                    return;
                }

                if (AsyncAwait.TryAwaitTaskFromResult(value, this.semanticModel, this.cancellationToken, out awaited))
                {
                    this.AddReturnValue(awaited);
                    return;
                }

                if (this.search == Search.Recursive &&
                    value is AwaitExpressionSyntax @await)
                {
                    value = @await.Expression;
                }
            }

            if (this.search == Search.Recursive)
            {
                if (value is InvocationExpressionSyntax invocation)
                {
                    var method = this.semanticModel.GetSymbolSafe(invocation, this.cancellationToken);
                    if (method == null ||
                        method.DeclaringSyntaxReferences.Length == 0)
                    {
                        this.values.Add(value);
                    }
                    else
                    {
                        using (var pooled = this.GetRecursive(value))
                        {
                            foreach (var returnValue in pooled.Item.values)
                            {
                                this.AddReturnValue(returnValue);
                            }
                        }
                    }
                }
                else if (this.recursionLoop.Add(value) &&
                         this.semanticModel.IsEither <IParameterSymbol, ILocalSymbol>(value, this.cancellationToken))
                {
                    using (var pooled = AssignedValueWalker.Create(value, this.semanticModel, this.cancellationToken))
                    {
                        if (pooled.Item.Count == 0)
                        {
                            this.values.Add(value);
                        }
                        else
                        {
                            foreach (var assignment in pooled.Item)
                            {
                                this.AddReturnValue(assignment);
                            }
                        }
                    }
                }
                else
                {
                    this.values.Add(value);
                }
            }
            else
            {
                this.values.Add(value);
            }
        }