internal static NodesToReplace CollectInvocations(GeneratorExecutionContext context, RecursiveMethodInfo methodInfo, TargetMethodsInfo targetMethodsInfo) { var walker = new CollectInvocationsWalker(context, methodInfo.MethodModel, targetMethodsInfo); walker.Visit(methodInfo.MethodSyntax.Body); return(walker._nodesToReplace); }
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()); }