private async Task <SyntaxNode> GetChangedCallerAsync(Document document,
                                                              TInvocationSyntax calleeInvocationNode,
                                                              IMethodSymbol calleeMethodSymbol,
                                                              ISymbol callerSymbol,
                                                              SyntaxNode callerDeclarationNode,
                                                              TStatementSyntax?statementContainsInvocation,
                                                              TExpressionSyntax rawInlineExpression,
                                                              MethodParametersInfo methodParametersInfo,
                                                              InlineMethodContext inlineMethodContext,
                                                              CancellationToken cancellationToken)
        {
            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var syntaxGenerator  = SyntaxGenerator.GetGenerator(document);
            var callerNodeEditor = new SyntaxEditor(callerDeclarationNode, syntaxGenerator);

            if (inlineMethodContext.ContainsAwaitExpression)
            {
                // If the inline content has 'await' expression, then make sure the caller is changed to 'async' method
                // if its return type is awaitable. In all other cases, do nothing.
                if (callerSymbol is IMethodSymbol callerMethodSymbol &&
                    callerMethodSymbol.IsOrdinaryMethod() &&
                    !callerMethodSymbol.IsAsync &&
                    (callerMethodSymbol.ReturnsVoid ||
                     callerMethodSymbol.IsAwaitableNonDynamic(semanticModel, callerDeclarationNode.SpanStart)))
                {
                    var declarationModifiers = DeclarationModifiers.From(callerSymbol).WithAsync(true);
                    callerNodeEditor.SetModifiers(callerDeclarationNode, declarationModifiers);
                }
            }

            if (statementContainsInvocation != null)
            {
                foreach (var statement in inlineMethodContext.StatementsToInsertBeforeInvocationOfCallee)
                {
                    // Add a CarriageReturn to make sure for VB the statement would be in different line.
                    callerNodeEditor.InsertBefore(statementContainsInvocation,
                                                  statement.WithAppendedTrailingTrivia(_syntaxFacts.ElasticCarriageReturnLineFeed));
                }
            }

            var(nodeToReplace, inlineNode) = GetInlineNode(
                calleeInvocationNode,
                calleeMethodSymbol,
                statementContainsInvocation,
                rawInlineExpression,
                methodParametersInfo,
                inlineMethodContext,
                semanticModel,
                syntaxGenerator, cancellationToken);
            callerNodeEditor.ReplaceNode(nodeToReplace, (node, generator) => inlineNode);

            return(callerNodeEditor.GetChangedRoot());
        }
        private async Task <InlineMethodContext> GetInlineMethodContextAsync(
            Document document,
            TMethodDeclarationSyntax calleeMethodNode,
            TInvocationSyntax calleeInvocationNode,
            IMethodSymbol calleeMethodSymbol,
            TExpressionSyntax rawInlineExpression,
            MethodParametersInfo methodParametersInfo,
            CancellationToken cancellationToken)
        {
            var inlineExpression    = rawInlineExpression;
            var syntaxGenerator     = SyntaxGenerator.GetGenerator(document);
            var callerSemanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var calleeDocument      = document.Project.Solution.GetRequiredDocument(calleeMethodNode.SyntaxTree);
            var calleeSemanticModel = await calleeDocument.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            // Generate a map which the key is the symbol need renaming, value is the new name.
            // After inlining, there might be naming conflict because
            // case 1: caller's identifier is introduced to callee.
            // Example (for identifier):
            // Before:
            // void Caller()
            // {
            //     int i = 10;
            //     Callee(i)
            // }
            // void Callee(int j)
            // {
            //     DoSomething(out var i, j);
            // }
            // After inline it should be:
            // void Caller()
            // {
            //     int i = 10;
            //     DoSomething(out var i1, i);
            // }
            // void Callee(int j)
            // {
            //     DoSomething(out var i, j);
            // }
            // Case 2: callee's parameter is introduced to caller
            // Before:
            // void Caller()
            // {
            //     int i = 0;
            //     int j = 1;
            //     Callee(Foo())
            // }
            // void Callee(int i)
            // {
            //     Bar(i, out int j);
            // }
            // After:
            // void Caller()
            // {
            //     int i = 10;
            //     int j = 1;
            //     int i1 = Foo();
            //     Bar(i1, out int j2);
            // }
            // void Callee(int i)
            // {
            //     Bar(i, out int j);
            // }
            var renameTable = ComputeRenameTable(
                _semanticFactsService,
                callerSemanticModel,
                calleeSemanticModel,
                calleeInvocationNode,
                rawInlineExpression,
                methodParametersInfo.ParametersToGenerateFreshVariablesFor
                .SelectAsArray(parameterAndArgument => parameterAndArgument.parameterSymbol), cancellationToken);

            // Generate all the statements need to be put in the caller.
            // Use the parameter's name to generate declarations in caller might cause conflict in the caller,
            // so the rename table is needed to provide with a valid name.
            // Example:
            // Before:
            // void Caller(int i, int j)
            // {
            //     Callee(Foo(), Bar());
            // }
            // void Callee(int i, int j)
            // {
            //     DoSomething(i, j);
            // }
            // After:
            // void Caller(int i, int j)
            // {
            //     int i1 = Foo();
            //     int j1 = Bar();
            //     DoSomething(i1, j1)
            // }
            // void Callee(int i, int j)
            // {
            //     DoSomething(i, j);
            // }
            // Here two declaration is generated.
            // Another case is
            // void Caller()
            // {
            //     Callee(out int i)
            // }
            // void Callee(out int j)
            // {
            //     DoSomething(out j, out int i);
            // }
            // After:
            // void Caller()
            // {
            //     int i = 10;
            //     DoSomething(out i, out int i2);
            // }
            // void Callee(out int j)
            // {
            //     DoSomething(out j, out int i);
            // }
            var localDeclarationStatementsNeedInsert = GetLocalDeclarationStatementsNeedInsert(
                syntaxGenerator,
                methodParametersInfo.ParametersToGenerateFreshVariablesFor,
                methodParametersInfo.MergeInlineContentAndVariableDeclarationArgument
                    ? ImmutableArray <(IParameterSymbol, string)> .Empty
                    : methodParametersInfo.ParametersWithVariableDeclarationArgument,
                renameTable);

            // Get a table which the key is the symbol needs replacement. Value is the replacement syntax node
            // Included 3 cases:
            // 1. Type arguments (generics)
            // Example:
            // Before:
            // void Caller()
            // {
            //     Callee<int>();
            // }
            // void Callee<T>() => Print(typeof<T>);
            // After:
            // void Caller()
            // {
            //     Print(typeof<int>);
            // }
            // void Callee<T>() => Print(typeof<int>);
            // 2. Literal replacement
            // Example:
            // Before:
            // void Caller()
            // {
            //     Callee(20)
            // }
            // void Callee(int i, int j = 10)
            // {
            //     Bar(i, j);
            // }
            // After:
            // void Caller()
            // {
            //     Bar(20, 10);
            // }
            // void Callee(int i, int j = 10)
            // {
            //     Bar(i, j);
            // }
            // 3. Identifier
            // Example:
            // Before:
            // void Caller()
            // {
            //     int a, b, c;
            //     Callee(a, b)
            // }
            // void Callee(int i, int j)
            // {
            //     Bar(i, j, out int c);
            // }
            // After:
            // void Caller()
            // {
            //     int a, b, c;
            //     Bar(a, b, out int c1);
            // }
            // void Callee(int i, int j = 10)
            // {
            //     Bar(i, j, out int c);
            // }
            var replacementTable = ComputeReplacementTable(
                calleeMethodSymbol,
                methodParametersInfo.ParametersWithVariableDeclarationArgument,
                methodParametersInfo.ParametersToReplace,
                syntaxGenerator,
                renameTable);

            var containsAwaitExpression = ContainsAwaitExpression(rawInlineExpression);

            // Do the replacement work within the callee's body so that it can be inserted to the caller later.
            inlineExpression = await ReplaceAllSyntaxNodesForSymbolAsync(
                calleeDocument,
                inlineExpression,
                syntaxGenerator,
                replacementTable,
                cancellationToken).ConfigureAwait(false);

            return(new InlineMethodContext(
                       localDeclarationStatementsNeedInsert,
                       inlineExpression,
                       containsAwaitExpression));
        }
        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));
        }
        private void AddMethods(IHTMLElement htext)
        {
            var content = new IHTMLDiv().AttachTo(DocumentBody);
            content.Hide();

            var IsInterface = new IHTMLInput(ScriptCoreLib.Shared.HTMLInputTypeEnum.checkbox);
            new IHTMLDiv(
                new IHTMLLabel("is an interface: ", IsInterface), IsInterface
            ).AttachTo(content);

            var DelegatesParams = new IHTMLInput(ScriptCoreLib.Shared.HTMLInputTypeEnum.checkbox);
            new IHTMLDiv(
                new IHTMLLabel("delegates parameters to base constructor: ", DelegatesParams), DelegatesParams
            ).AttachTo(content);

            var update = default(Action);

            // var a = new IHTMLTextArea().AttachTo(content);

            IHTMLButton.Create(
                "Example code",
                delegate
                {
                    a.value =
@"addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
Registers an event listener object with an EventDispatcher object so that the listener receives notification of an event.
";

                    update();
                }
            ).AttachTo(content);



            var b = new IHTMLTextArea().AttachTo(content);

            htext.onclick +=
                delegate
                {
                    content.ToggleVisible();
                };

            a.style.display = ScriptCoreLib.JavaScript.DOM.IStyle.DisplayEnum.block;
            a.style.width = "100%";
            a.style.height = "20em";


            b.style.display = ScriptCoreLib.JavaScript.DOM.IStyle.DisplayEnum.block;
            b.style.width = "100%";
            b.style.height = "20em";

            b.readOnly = true;



            Action update_output =
                delegate
                {
                    var w = new StringBuilder();
                    var w2 = new StringBuilder();

                    var lines = a.Lines.ToArray();

                    w.AppendLine("#region Methods");
                    w2.AppendLine("#region Constructors");

                    for (int i = 0; i < lines.Length; i += 3)
                    {
                        if ((i + 1) < lines.Length)
                        {
                            var StaticKeyword = "[static]";

                            var Summary = lines[i + 1].Trim();
                            var MethodSig = lines[i].Trim();


                            if (!MethodSig.Contains("AIR-only"))
                            {
                                var q0 = MethodSig.Split(')');
                                var q1 = q0[0].Split('(');

                                var MethodName = FixVariableName(q1[0].Trim());
                                var MethodParameters = new MethodParametersInfo(q1[1].Trim());

                                var MethodReturnType = "";

                                if (q0[1].StartsWith(":"))
                                    MethodReturnType = FixTypeName(q0[1].Substring(1).Trim());



                                var IsConstructor = string.IsNullOrEmpty(MethodReturnType);

                                foreach (var v in MethodParameters.Variations)
                                {
                                    if (IsConstructor)
                                    {
                                        w2.AppendLine("/// <summary>");
                                        w2.AppendLine("/// " + Summary);
                                        w2.AppendLine("/// </summary>");

                                        if (DelegatesParams.@checked)
                                            w2.AppendLine("public " + MethodName + "(" + v + ") : base(" + v.NamesToString() + ")");
                                        else
                                            w2.AppendLine("public " + MethodName + "(" + v + ")");

                                        w2.AppendLine("{");
                                        w2.AppendLine("}");
                                        w2.AppendLine();
                                    }
                                    else
                                    {
                                        if (v.Parameters.Length == 0 && MethodName == "toString")
                                        {

                                        }
                                        else
                                        {
                                            w.AppendLine("/// <summary>");
                                            w.AppendLine("/// " + Summary);
                                            w.AppendLine("/// </summary>");

                                            var StaticModifier = Summary.Contains(StaticKeyword) ? "static " : "";

                                            if (IsInterface.@checked)
                                            {
                                                w.AppendLine(MethodReturnType + " " + MethodName + "(" + v + ");");

                                            }
                                            else
                                            {
                                                w.AppendLine("public " + StaticModifier + MethodReturnType + " " + MethodName + "(" + v + ")");
                                                w.AppendLine("{");

                                                if (MethodReturnType != "void")
                                                    w.AppendLine("  return default(" + MethodReturnType + ");");

                                                w.AppendLine("}");
                                            }
                                            w.AppendLine();

                                        }
                                    }
                                }




                            }


                        }
                    }

                    w.AppendLine("#endregion");
                    w2.AppendLine("#endregion");

                    if (!IsInterface.@checked)
                    {
                        w.AppendLine();
                        w.Append(w2.ToString());
                    }

                    b.value = w.ToString();
                };

            update =
                delegate
                {


                    try
                    {

                        update_output();
                        htext.style.color = Color.Blue;
                    }
                    catch (Exception ex)
                    {
                        htext.style.color = Color.Red;
                        b.value = "error: " + ex.Message;
                    }
                };

            IsInterface.onchange += delegate { update(); };
            DelegatesParams.onchange += delegate { update(); };

            a.onchange +=
                delegate
                {
                    update();
                };
        }