Exemplo n.º 1
0
 protected static SyntaxToken CreateUniqueName(
     ISemanticFactsService semanticFacts,
     SemanticModel model,
     SyntaxNode location,
     string baseName,
     CancellationToken cancellationToken
     ) =>
 semanticFacts.GenerateUniqueLocalName(
     model,
     location,
     containerOpt: null,
     baseName,
     cancellationToken
     );
        private (SyntaxNode nodeToReplace, SyntaxNode inlineNode) GetInlineNode(
            TInvocationSyntax calleeInvocationNode,
            IMethodSymbol calleeMethodSymbol,
            TStatementSyntax?statementContainsInvocation,
            TExpressionSyntax rawInlineExpression,
            MethodParametersInfo methodParametersInfo,
            InlineMethodContext inlineMethodContext,
            SemanticModel semanticModel,
            SyntaxGenerator syntaxGenerator,
            CancellationToken cancellationToken)
        {
            if (statementContainsInvocation != null)
            {
                if (methodParametersInfo.MergeInlineContentAndVariableDeclarationArgument)
                {
                    var rightHandSideValue = _syntaxFacts.GetRightHandSideOfAssignment(inlineMethodContext.InlineExpression);
                    var(parameterSymbol, name) = methodParametersInfo.ParametersWithVariableDeclarationArgument.Single();
                    var declarationNode = (TStatementSyntax)syntaxGenerator
                                          .LocalDeclarationStatement(parameterSymbol.Type, name, rightHandSideValue);
                    return(statementContainsInvocation, declarationNode.WithTriviaFrom(statementContainsInvocation));
                }

                if (_syntaxFacts.IsThrowStatement(rawInlineExpression.Parent) &&
                    _syntaxFacts.IsExpressionStatement(calleeInvocationNode.Parent))
                {
                    var throwStatement = (TStatementSyntax)syntaxGenerator
                                         .ThrowStatement(inlineMethodContext.InlineExpression);
                    return(statementContainsInvocation, throwStatement.WithTriviaFrom(statementContainsInvocation));
                }

                if (_syntaxFacts.IsThrowExpression(rawInlineExpression) &&
                    _syntaxFacts.IsExpressionStatement(calleeInvocationNode.Parent))
                {
                    // Example:
                    // Before:
                    // void Caller() { Callee(); }
                    // void Callee() => throw new Exception();
                    // After:
                    // void Caller() { throw new Exception(); }
                    // void Callee() => throw new Exception();
                    // Note: Throw expression is converted to throw statement
                    var throwStatement = (TStatementSyntax)syntaxGenerator
                                         .ThrowStatement(_syntaxFacts.GetExpressionOfThrowExpression(inlineMethodContext.InlineExpression));
                    return(statementContainsInvocation, throwStatement.WithTriviaFrom(statementContainsInvocation));
                }

                if (_syntaxFacts.IsExpressionStatement(calleeInvocationNode.Parent) &&
                    !calleeMethodSymbol.ReturnsVoid &&
                    !IsValidExpressionUnderExpressionStatement(inlineMethodContext.InlineExpression))
                {
                    // If the callee is invoked as ExpressionStatement, but the inlined expression in the callee can't be
                    // placed under ExpressionStatement
                    // Example:
                    // void Caller()
                    // {
                    //     Callee();
                    // }
                    // int Callee()
                    // {
                    //     return 1;
                    // };
                    // After it should be:
                    // void Caller()
                    // {
                    //     int temp = 1;
                    // }
                    // int Callee()
                    // {
                    //     return 1;
                    // };
                    // One variable declaration needs to be generated.
                    var unusedLocalName =
                        _semanticFactsService.GenerateUniqueLocalName(
                            semanticModel,
                            calleeInvocationNode,
                            containerOpt: null,
                            TemporaryName,
                            cancellationToken);

                    var localDeclarationNode = (TStatementSyntax)syntaxGenerator
                                               .LocalDeclarationStatement(calleeMethodSymbol.ReturnType, unusedLocalName.Text,
                                                                          inlineMethodContext.InlineExpression);
                    return(statementContainsInvocation, localDeclarationNode.WithTriviaFrom(statementContainsInvocation));
                }
            }

            if (_syntaxFacts.IsThrowStatement(rawInlineExpression.Parent))
            {
                // Example:
                // Before:
                // void Caller() => Callee();
                // void Callee() { throw new Exception(); }
                // After:
                // void Caller() => throw new Exception();
                // void Callee() { throw new Exception(); }
                // Note: Throw statement is converted to throw expression
                if (CanBeReplacedByThrowExpression(calleeInvocationNode))
                {
                    var throwExpression = (TExpressionSyntax)syntaxGenerator
                                          .ThrowExpression(inlineMethodContext.InlineExpression)
                                          .WithTriviaFrom(calleeInvocationNode);
                    return(calleeInvocationNode, throwExpression.WithTriviaFrom(calleeInvocationNode));
                }
            }

            var inlineExpression = inlineMethodContext.InlineExpression;

            if (!_syntaxFacts.IsExpressionStatement(calleeInvocationNode.Parent) &&
                !calleeMethodSymbol.ReturnsVoid &&
                !_syntaxFacts.IsThrowExpression(inlineMethodContext.InlineExpression))
            {
                // Add type cast and parenthesis to the inline expression.
                // It is required to cover cases like:
                // Case 1 (parenthesis added):
                // Before:
                // void Caller() { var x = 3 * Callee(); }
                // int Callee() { return 1 + 2; }
                //
                // After
                // void Caller() { var x = 3 * (1 + 2); }
                // int Callee() { return 1 + 2; }
                //
                // Case 2 (type cast)
                // Before:
                // void Caller() { var x = Callee(); }
                // long Callee() { return 1 }
                //
                // After
                // void Caller() { var x = (long)1; }
                // int Callee() { return 1; }
                //
                // Case 3 (type cast & additional parenthesis)
                // Before:
                // void Caller() { var x = Callee()(); }
                // Func<int> Callee() { return () => 1; }
                // After:
                // void Caller() { var x = ((Func<int>)(() => 1))(); }
                // Func<int> Callee() { return () => 1; }
                inlineExpression = (TExpressionSyntax)syntaxGenerator.AddParentheses(
                    syntaxGenerator.CastExpression(
                        GenerateTypeSyntax(calleeMethodSymbol.ReturnType, allowVar: false),
                        syntaxGenerator.AddParentheses(inlineMethodContext.InlineExpression)));
            }

            return(calleeInvocationNode, inlineExpression.WithTriviaFrom(calleeInvocationNode));
        }