using System; using System.Collections.Generic; using CTA.Rules.Actions.ActionHelpers; using CTA.Rules.Config; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Editing; namespace CTA.Rules.Actions.Csharp { /// /// List of actions that can run on Method Declarations /// public class MethodDeclarationActions { public Func GetAddCommentAction(string comment, string dontUseCTAPrefix = null) { MethodDeclarationSyntax AddComment(SyntaxGenerator syntaxGenerator, MethodDeclarationSyntax node) { return (MethodDeclarationSyntax)CommentHelper.AddCSharpComment(node, comment, dontUseCTAPrefix); } return AddComment; } public Func GetAppendExpressionAction(string expression) { // TODO: This will add an expression at the bottom of a method body, in the future we should add granularity for where to add the expression within a method body Func AppendExpression = (SyntaxGenerator syntaxGenerator, MethodDeclarationSyntax node) => { StatementSyntax statementExpression = SyntaxFactory.ParseStatement(expression).NormalizeWhitespace(); if(!statementExpression.FullSpan.IsEmpty) { BlockSyntax nodeBody = node.Body; nodeBody = nodeBody.AddStatements(statementExpression); node = node.WithBody(nodeBody); } return node; }; return AppendExpression; } public Func GetChangeMethodNameAction(string newMethodName) { MethodDeclarationSyntax ChangeMethodName(SyntaxGenerator syntaxGenerator, MethodDeclarationSyntax node) { var newMethodNode = node; newMethodNode = newMethodNode.WithIdentifier(SyntaxFactory.Identifier(newMethodName)); return newMethodNode; } return ChangeMethodName; } public Func GetChangeMethodToReturnTaskTypeAction(string newMethodName) { MethodDeclarationSyntax ChangeMethodToReturnTaskType(SyntaxGenerator syntaxGenerator, MethodDeclarationSyntax node) { TypeSyntax asyncReturnType; if (node.ReturnType.ToFullString().Trim().Equals("void", StringComparison.OrdinalIgnoreCase)) { asyncReturnType = SyntaxFactory.IdentifierName("Task").WithTrailingTrivia(SyntaxFactory.Space); } else { var currentTrivia = node.ReturnType.GetTrailingTrivia(); asyncReturnType = SyntaxFactory.GenericName(SyntaxFactory.Identifier("Task")).WithTypeArgumentList(SyntaxFactory.TypeArgumentList(SyntaxFactory.SingletonSeparatedList(node.ReturnType.WithoutTrailingTrivia()))).WithTrailingTrivia(currentTrivia); } var newMethodNode = node.WithReturnType(asyncReturnType); return newMethodNode; } return ChangeMethodToReturnTaskType; } public Func GetRemoveMethodParametersAction() { MethodDeclarationSyntax RemoveMethodParametersAction(SyntaxGenerator syntaxGenerator, MethodDeclarationSyntax node) { List parameters = new List(); var newMethodNode = node.WithParameterList(SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters)).NormalizeWhitespace()); return newMethodNode; } return RemoveMethodParametersAction; } public Func GetAddParametersToMethodAction(string types, string identifiers) { MethodDeclarationSyntax AddParametersToMethodAction(SyntaxGenerator syntaxGenerator, MethodDeclarationSyntax node) { var newMethodNode = node; if (!string.IsNullOrWhiteSpace(identifiers) && !string.IsNullOrWhiteSpace(types)) { var identifiersArray = identifiers.Split(',', StringSplitOptions.RemoveEmptyEntries); var typesArray = types.Split(',', StringSplitOptions.RemoveEmptyEntries); if (identifiersArray.Length == typesArray.Length) { List parameters = new List(); for (int i = 0; i < identifiersArray.Length; i++) { parameters.Add(SyntaxFactory.Parameter(SyntaxFactory.Identifier(identifiersArray[i])).WithType(SyntaxFactory.ParseTypeName(typesArray[i]))); } newMethodNode = node.AddParameterListParameters(parameters.ToArray()); } }; return newMethodNode; } return AddParametersToMethodAction; } public Func GetCommentMethodAction(string comment = null, string dontUseCTAPrefix = null) { MethodDeclarationSyntax CommentMethodAction(SyntaxGenerator syntaxGenerator, MethodDeclarationSyntax node) { var startComment = SyntaxFactory.SyntaxTrivia(SyntaxKind.MultiLineCommentTrivia, "/*"); var endComment = SyntaxFactory.SyntaxTrivia(SyntaxKind.MultiLineCommentTrivia, "*/"); var newMethodNode = node.WithLeadingTrivia(new SyntaxTriviaList(startComment)).WithTrailingTrivia(new SyntaxTriviaList(endComment)); node = node.ReplaceNode(node, newMethodNode); if (!string.IsNullOrWhiteSpace(comment)) { var addCommentsToMethodFunc = GetAddCommentAction(comment, dontUseCTAPrefix); return addCommentsToMethodFunc(syntaxGenerator, node); } return node; } return CommentMethodAction; } public Func GetAddExpressionToMethodAction(string expression) { MethodDeclarationSyntax AddExpressionToMethodAction(SyntaxGenerator syntaxGenerator, MethodDeclarationSyntax node) { var newMethodNode = node; StatementSyntax parsedExpression = SyntaxFactory.ParseStatement(expression).NormalizeWhitespace(); if (!parsedExpression.FullSpan.IsEmpty) { newMethodNode = node.AddBodyStatements(new StatementSyntax[] { parsedExpression }); } return newMethodNode; } return AddExpressionToMethodAction; } } }