private string GenerateAll()
        {
            var allCode       = new CodeBuilder();
            var classInfo     = _classInfo;
            var classSyntax   = _classInfo.ContainingClassSyntax;
            var namespaceName = classInfo.ContainingClassSymbol.ContainingNamespace.ToDisplayString();

            var methodGens    = _methodInfos.Select(mi => new CalculatorMethodGenerator(_context, classInfo, mi)).ToList();
            var targetMethods = new TargetMethodsInfo(_methodInfos);

            // copy all the usings from the original file
            var root = (CompilationUnitSyntax)classSyntax.SyntaxTree.GetRoot();

            allCode.AddHeaderLine(root.Usings.ToFullString());
            allCode.AddHeaderLine();

            // namespace
            allCode.AddBlockHeader($"namespace {namespaceName}");

            // class declaration
            var classModifiersString = classSyntax.Modifiers.ToFullString();

            if (!classModifiersString.Contains("partial"))
            {
                _context.ReportUnsupportedSyntaxError(classSyntax, $"Target class '{_classInfo.ContainingClassSymbol.Name}' for '{classInfo.RecursionId}' is not partial");
                return(null);
            }

            allCode.AddBlockHeader($"{classModifiersString} class {_classInfo.ContainingClassSymbol.Name}");

            allCode.AddHeaderLine();
            allCode.AddHeaderLine(GenerateProxyMethods(methodGens));

            allCode.AddHeaderLine();
            allCode.AddHeaderLine(GenerateParamsStructs(classInfo, methodGens));

            allCode.AddHeaderLine();
            allCode.AddHeaderLine(GenerateCalculatorClass(classInfo, methodGens, targetMethods));

            return(allCode.BuildString());
        }
        private SyntaxNode ReplaceReturn(TargetMethodsInfo targetMethods, ReturnStatementSyntax origNode, ReturnStatementSyntax curNode)
        {
            //Support cases of "return RecursiveCall(different params)" like GCD
            if (curNode.Expression.Kind() == SyntaxKind.InvocationExpression)
            {
                var inv          = (InvocationExpressionSyntax)curNode.Expression;
                var targetMethod = GetInvocationRecursiveCallTarget(targetMethods, inv);
                if (targetMethod != null)
                {
                    // only needed for mutual recursion where fields might be different
                    var copyReturnValueLine = (_methodInfo != targetMethod) && _methodInfo.ShouldGenerateReturnField
                        ? $"{_methodInfo.ReturnFieldName} = {targetMethod.ReturnFieldName}; // copy the return value"
                        : "";

                    return(SyntaxUtils.GetBlockFromCodeString(origNode, @$ "
                            yield return new {targetMethod.MethodParamsStructName}{targetMethod.GenericParams}{inv.ArgumentList.ToFullString()};
                            {copyReturnValueLine}
                            yield break;"));
                }
            }

            return(SyntaxUtils.GetBlockFromCodeString(origNode, @$ "
                    {_methodInfo.ReturnFieldName} = {origNode.Expression.ToFullString()};
        internal string GenerateCalculatorMethodBody(TargetMethodsInfo targetMethods)
        {
            var code = new CodeBuilder();

            // unpack params
            code.AddHeaderLine("\t\t// unpack params");
            code.AddHeaderLine(string.Join("\n",
                                           _methodInfo.MethodSyntax.ParameterList.Parameters.Select(parameterSyntax =>
            {
                var paramSymbol = _methodInfo.MethodModel.GetDeclaredSymbol(parameterSyntax);
                return($"\t\tvar {paramSymbol.Name} = {ParamsVarName}.{paramSymbol.Name};");
            })));

            // find all recursive invocations
            var nodesToReplace = CollectInvocationsWalker.CollectInvocations(_context, _methodInfo, targetMethods);

            if (nodesToReplace.ContainsCriticalFailure)
            {
                _context.Log(_methodInfo.MethodSyntax.GetLocation(), $"An unsupported code was found for '{_methodInfo.MethodSymbol.Name}'. Abort processing.");
                return(null);
            }

            _context.Log(_methodInfo.MethodSyntax.GetLocation(), $"'{_methodInfo.MethodSymbol.Name}':" +
                         $" {nodesToReplace.VoidCalls.Count} void call(s)" +
                         $" {nodesToReplace.Assignments.Count} assignment(s)" +
                         $", {nodesToReplace.DeclarationAndAssignments.Count} var declaration(s)" +
                         $", {nodesToReplace.ReturnsRecursive.Count} recursive call(s) in return(s)" +
                         $", {nodesToReplace.Returns.Count} return(s)");


            // process all supported kinds of recursive invocations
            var allNodesToReplace = nodesToReplace.Returns.Cast <StatementSyntax>()
                                    .Concat(nodesToReplace.ReturnsRecursive)
                                    .Concat(nodesToReplace.VoidCalls.Select(t => t.containingStatement))
                                    .Concat(nodesToReplace.Assignments.Select((t) => t.containingStatement))
                                    .Concat(nodesToReplace.DeclarationAndAssignments.Select(t => t.containingStatement));
            var newRoot = _methodInfo.MethodSyntax.Body.ReplaceNodes(allNodesToReplace, (origNode, curNode) =>
            {
                // _context.Log("!! " + origNode.Kind() + " " + origNode.ToFullStringTrimmed());
                switch (origNode.Kind())
                {
                case SyntaxKind.ReturnStatement:
                    return(ReplaceReturn(targetMethods, (ReturnStatementSyntax)origNode, (ReturnStatementSyntax)curNode));

                case SyntaxKind.ExpressionStatement:
                    var origExpressionNode = (ExpressionStatementSyntax)origNode;
                    var expression         = origExpressionNode.Expression;
                    switch (expression.Kind())
                    {
                    case SyntaxKind.InvocationExpression:
                        return(ReplaceVoidCall(targetMethods, origExpressionNode, (ExpressionStatementSyntax)curNode));

                    case SyntaxKind.SimpleAssignmentExpression:
                        return(ReplaceAssignment(targetMethods, origExpressionNode, (ExpressionStatementSyntax)curNode));

                    default:
                        throw new AntiSOGenException($"Unexpected expression kind {expression.Kind()} to replace {origNode.ToFullStringTrimmed()}");
                    }


                case SyntaxKind.LocalDeclarationStatement:
                    return(ReplaceLocalVarDeclrAssignment(targetMethods, (LocalDeclarationStatementSyntax)origNode, (LocalDeclarationStatementSyntax)curNode));

                default:
                    throw new AntiSOGenException($"Unexpected statement kind {origNode.Kind()} to replace {origNode.ToFullStringTrimmed()}");
                }
            });

            code.AddHeaderLine("\t\t// method body");
            code.AddHeader(newRoot.ToFullString());
            return(code.BuildString());
        }
        private string GenerateSimpleCalculatorClass(RecursiveCalculatorClassInfo classInfo, List <CalculatorMethodGenerator> methodGens, TargetMethodsInfo targetMethods)
        {
            var code = new CodeBuilder();

            var methodGen  = methodGens.Single();
            var methodInfo = methodGen.MethodInfo;

            code.AddBlockHeader(@$ "    private class {classInfo.CalculatorClassName}{classInfo.GenericParams} :
                        AntiSO.Infrastructure.SimpleRecursionRunner<{methodInfo.MethodParamsStructName}{methodInfo.GenericParams}>
 private string GenerateCalculatorClass(RecursiveCalculatorClassInfo classInfo, List <CalculatorMethodGenerator> methodGens, TargetMethodsInfo targetMethods)
 {
     if (classInfo.IsMultiSite)
     {
         // mutual recursion with a dispatcher method
         return(GenerateMultiSiteCalculatorClass(classInfo, methodGens, targetMethods));
     }
     else
     {
         // simple recursion
         return(GenerateSimpleCalculatorClass(classInfo, methodGens, targetMethods));
     }
 }