public SyntaxNode Generate(CompilationContext context, ISettings settings) { // Create the root node and add usings, header, pragma var r4mvcNode = SyntaxFactory.CompilationUnit() .WithUsings("System.CodeDom.Compiler", "System.Diagnostics", "Microsoft.AspNet.Mvc") .WithHeader(_headerText) .WithPragmaCodes(false, pramaCodes); var controllers = _controllerRewriter.RewriteControllers(context.Compilation, R4MvcFileName); var generatedControllers = _controllerGenerator.GenerateControllers(context.Compilation, controllers).ToImmutableArray(); var staticFileNode = _staticFileGenerator.GenerateStaticFiles(settings); // add the dummy class using in the derived controller partial class var r4Namespace = SyntaxNodeHelpers.CreateNamespace(settings.R4MvcNamespace).WithDummyClass(); // create static MVC class and add controller fields var mvcStaticClass = SyntaxNodeHelpers.CreateClass(settings.HelpersPrefix, null, SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.PartialKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()) .WithControllerFields(controllers); r4mvcNode = r4mvcNode.AddMembers(generatedControllers.Cast <MemberDeclarationSyntax>().ToArray()) .AddMembers(staticFileNode) .AddMembers(r4Namespace) .AddMembers(mvcStaticClass) .NormalizeWhitespace() .WithPragmaCodes(true, pramaCodes); // NOTE reenable pragma codes after normalizing whitespace or it doesn't place on newline return(r4mvcNode); }
public ClassDeclarationSyntax GenerateR4Controller(INamedTypeSymbol controllerSymbol) { // create R4MVC_[Controller] class inheriting from partial var r4ControllerClass = SyntaxNodeHelpers.CreateClass( GetR4MVCControllerClassName(controllerSymbol), null, SyntaxKind.PublicKeyword, SyntaxKind.PartialKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()) .WithBaseTypes(controllerSymbol.ToQualifiedName()) .WithDefaultDummyBaseConstructor(false, SyntaxKind.PublicKeyword); r4ControllerClass = AddMethodOverrides(r4ControllerClass, controllerSymbol); return(r4ControllerClass); }
private ClassDeclarationSyntax AddParameterlessMethods(ClassDeclarationSyntax node, ITypeSymbol mvcSymbol) { var methods = mvcSymbol.GetPublicNonGeneratedMethods() .GroupBy(m => m.Name) .Where(g => !g.Any(m => m.Parameters.Length == 0)) .Select(g => MethodDeclaration(IdentifierName("IActionResult"), Identifier(g.Key)) .WithModifiers(SyntaxKind.PublicKeyword, SyntaxKind.VirtualKeyword) .WithAttributes(SyntaxNodeHelpers.CreateNonActionAttribute()) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()) .WithBody( Block( // return new R4Mvc_Microsoft_AspNetCore_Mvc_ActionResult(Area, Name, ActionNames.{Action}); ReturnStatement( ObjectCreationExpression(IdentifierName(Constants.ActionResultClass)) .WithArgumentList( IdentifierName("Area"), IdentifierName("Name"), SyntaxNodeHelpers.MemberAccess("ActionNames", g.Key)))))); return(node.AddMembers(methods.ToArray())); }
public void Generate(CSharpCompilation compilation, string projectRoot) { // create static MVC class and add controller fields var mvcStaticClass = SyntaxNodeHelpers.CreateClass(_settings.HelpersPrefix, null, SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.PartialKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()); // R4MVC namespace used for the areas and Dummy class var r4Namespace = SyntaxNodeHelpers.CreateNamespace(_settings.R4MvcNamespace) // add the dummy class using in the derived controller partial class .WithDummyClass(); var areaClasses = new Dictionary <string, ClassDeclarationSyntax>(); var controllers = _controllerRewriter.RewriteControllers(compilation, R4MvcFileName); var controllerDetails = controllers .Where(c => !c.SyntaxTree.FilePath.EndsWith(".generated.cs")) .Select(c => { var @namespace = c.Ancestors().OfType <NamespaceDeclarationSyntax>().First().Name.ToFullString().Trim(); var model = compilation.GetSemanticModel(c.SyntaxTree); var controllerSymbol = model.GetDeclaredSymbol(c); var controllerName = controllerSymbol.Name.TrimEnd("Controller"); var areaName = _controllerGenerator.GetControllerArea(controllerSymbol); return(new { FilePath = c.SyntaxTree.FilePath, Namespace = @namespace, Name = controllerName, Area = areaName, Symbol = controllerSymbol, }); }); var namespaceGroups = controllerDetails.GroupBy(c => c.Namespace); var rootControllerNames = controllerDetails.Where(c => string.IsNullOrEmpty(c.Area)).Select(c => c.Name).ToArray(); var allViewFiles = _viewLocator.FindViews(projectRoot); var generatedControllers = new List <NamespaceDeclarationSyntax>(); foreach (var nameGroup in namespaceGroups) { var namespaceNode = SyntaxNodeHelpers.CreateNamespace(nameGroup.Key); foreach (var controller in nameGroup) { var areaKey = rootControllerNames.Contains(controller.Area) ? controller.Area + "Area" : controller.Area; var genControllerClass = _controllerGenerator.GeneratePartialController(controller.Symbol, areaKey, controller.Area, controller.Name, projectRoot); var r4ControllerClass = _controllerGenerator.GenerateR4Controller(controller.Symbol); namespaceNode = namespaceNode .AddMembers(genControllerClass, r4ControllerClass); if (_settings.SplitIntoMutipleFiles) { var controllerFile = NewCompilationUnit() .AddMembers(namespaceNode); CompleteAndWriteFile(controllerFile, controller.FilePath.TrimEnd(".cs") + ".generated.cs"); namespaceNode = SyntaxNodeHelpers.CreateNamespace(nameGroup.Key); } if (!string.IsNullOrEmpty(controller.Area)) { if (!areaClasses.ContainsKey(controller.Area)) { string areaClass = controller.Area + "AreaClass"; areaClasses[controller.Area] = SyntaxNodeHelpers.CreateClass(areaClass, null, SyntaxKind.PublicKeyword); // change to field and property mvcStaticClass = mvcStaticClass.AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer("s_" + areaKey, areaClass, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword), SyntaxNodeHelpers.CreateProperty(areaKey, areaClass, IdentifierName("s_" + areaKey), SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword)); } areaClasses[controller.Area] = areaClasses[controller.Area].AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( controller.Name, $"{nameGroup.Key}.{genControllerClass.Identifier}", $"{nameGroup.Key}.{r4ControllerClass.Identifier}", SyntaxKind.PublicKeyword, SyntaxKind.ReadOnlyKeyword)); } else { mvcStaticClass = mvcStaticClass.AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( controller.Name, $"{nameGroup.Key}.{genControllerClass.Identifier}", $"{nameGroup.Key}.{r4ControllerClass.Identifier}", SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword)); } } if (!_settings.SplitIntoMutipleFiles) { generatedControllers.Add(namespaceNode); } } var views = _viewLocator.FindViews(projectRoot) .GroupBy(v => new { v.AreaName, v.ControllerName }); foreach (var viewSet in views) { if (controllerDetails.Any(c => c.Area == viewSet.Key.AreaName && c.Name == viewSet.Key.ControllerName)) { continue; } var className = !string.IsNullOrEmpty(viewSet.Key.AreaName) ? $"{viewSet.Key.AreaName}Area_{viewSet.Key.ControllerName}ControllerClass" : $"{viewSet.Key.ControllerName}ControllerClass"; var controllerClass = SyntaxNodeHelpers.CreateClass(className, null, SyntaxKind.PublicKeyword) .WithViewsClass(viewSet.Key.ControllerName, viewSet.Key.AreaName, viewSet); r4Namespace = r4Namespace.AddMembers(controllerClass); if (!string.IsNullOrEmpty(viewSet.Key.AreaName)) { areaClasses[viewSet.Key.AreaName] = areaClasses[viewSet.Key.AreaName].AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( viewSet.Key.ControllerName, $"{_settings.R4MvcNamespace}.{className}", $"{_settings.R4MvcNamespace}.{className}", SyntaxKind.PublicKeyword, SyntaxKind.ReadOnlyKeyword)); } else { mvcStaticClass = mvcStaticClass.AddMembers( SyntaxNodeHelpers.CreateFieldWithDefaultInitializer( viewSet.Key.ControllerName, $"{_settings.R4MvcNamespace}.{className}", $"{_settings.R4MvcNamespace}.{className}", SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword)); } } r4Namespace = r4Namespace.AddMembers(areaClasses.Values.ToArray()); var staticFileNode = _staticFileGenerator.GenerateStaticFiles(projectRoot); var actionResultClass = SyntaxNodeHelpers.CreateClass(Constants.ActionResultClass, null, SyntaxKind.InternalKeyword, SyntaxKind.PartialKeyword) .WithBaseTypes("ActionResult", "IR4MvcActionResult") .WithMethods(ConstructorDeclaration(Constants.ActionResultClass) .WithModifiers(SyntaxKind.PublicKeyword) .AddParameterListParameters( Parameter(Identifier("area")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("controller")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("action")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("protocol")).WithType(SyntaxNodeHelpers.PredefinedStringType()) .WithDefault(EqualsValueClause(LiteralExpression(SyntaxKind.NullLiteralExpression)))) .WithBody( Block( ExpressionStatement( InvocationExpression( SyntaxNodeHelpers.MemberAccess("this", "InitMVCT4Result")) .WithArgumentList( IdentifierName("area"), IdentifierName("controller"), IdentifierName("action"), IdentifierName("protocol")))))) .WithAutoStringProperty("Controller", SyntaxKind.PublicKeyword) .WithAutoStringProperty("Action", SyntaxKind.PublicKeyword) .WithAutoStringProperty("Protocol", SyntaxKind.PublicKeyword) .WithAutoProperty("RouteValueDictionary", IdentifierName("RouteValueDictionary"), SyntaxKind.PublicKeyword); var jsonResultClass = SyntaxNodeHelpers.CreateClass(Constants.JsonResultClass, null, SyntaxKind.InternalKeyword, SyntaxKind.PartialKeyword) .WithBaseTypes("JsonResult", "IR4MvcActionResult") .WithMethods(ConstructorDeclaration(Constants.JsonResultClass) .WithModifiers(SyntaxKind.PublicKeyword) .AddParameterListParameters( Parameter(Identifier("area")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("controller")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("action")).WithType(SyntaxNodeHelpers.PredefinedStringType()), Parameter(Identifier("protocol")).WithType(SyntaxNodeHelpers.PredefinedStringType()) .WithDefault(EqualsValueClause(LiteralExpression(SyntaxKind.NullLiteralExpression)))) .WithInitializer(ConstructorInitializer(SyntaxKind.BaseConstructorInitializer, ArgumentList(SingletonSeparatedList(Argument(LiteralExpression(SyntaxKind.NullLiteralExpression)))))) .WithBody( Block( ExpressionStatement( InvocationExpression( SyntaxNodeHelpers.MemberAccess("this", "InitMVCT4Result")) .WithArgumentList( IdentifierName("area"), IdentifierName("controller"), IdentifierName("action"), IdentifierName("protocol")))))) .WithAutoStringProperty("Controller", SyntaxKind.PublicKeyword) .WithAutoStringProperty("Action", SyntaxKind.PublicKeyword) .WithAutoStringProperty("Protocol", SyntaxKind.PublicKeyword) .WithAutoProperty("RouteValueDictionary", IdentifierName("RouteValueDictionary"), SyntaxKind.PublicKeyword); var r4mvcNode = NewCompilationUnit() .AddMembers(generatedControllers.Cast <MemberDeclarationSyntax>().ToArray()) .AddMembers( staticFileNode, r4Namespace, mvcStaticClass, actionResultClass, jsonResultClass); CompleteAndWriteFile(r4mvcNode, Path.Combine(projectRoot, R4MvcGenerator.R4MvcFileName)); }
public IEnumerable <NamespaceDeclarationSyntax> GenerateControllers( CSharpCompilation compiler, IEnumerable <ClassDeclarationSyntax> controllerNodes) { // controllers might be in different namespaces so should group by namespace var namespaceGroups = controllerNodes.GroupBy(x => x.Ancestors().OfType <NamespaceDeclarationSyntax>().First().Name.ToFullString()); foreach (var namespaceControllers in namespaceGroups) { // create the namespace for the controllers var namespaceNode = SyntaxNodeHelpers.CreateNamespace(namespaceControllers.Key); // loop through the controllers and create a partial node for each foreach (var mvcControllerNode in namespaceControllers) { var model = compiler.GetSemanticModel(mvcControllerNode.SyntaxTree); var mvcSymbol = model.GetDeclaredSymbol(mvcControllerNode); // build controller partial class node // add a default constructor if there are some but none are zero length var genControllerClass = SyntaxNodeHelpers.CreateClass( mvcSymbol.Name, mvcControllerNode.TypeParameterList?.Parameters.ToArray(), SyntaxKind.PublicKeyword, SyntaxKind.PartialKeyword); if (!mvcSymbol.Constructors.IsEmpty || !mvcSymbol.Constructors.Any(x => x.Parameters.Length == 0)) { genControllerClass = genControllerClass.WithDefaultConstructor(true, SyntaxKind.PublicKeyword); } // add all method stubs, TODO criteria for this: only public virtual actionresults? // add subclasses, fields, properties, constants for action names genControllerClass = genControllerClass.WithMethods(mvcSymbol) .WithStringField( "Name", mvcControllerNode.Identifier.ToString(), true, SyntaxKind.PublicKeyword, SyntaxKind.ReadOnlyKeyword) .WithStringField( "NameConst", mvcControllerNode.Identifier.ToString(), true, SyntaxKind.PublicKeyword, SyntaxKind.ConstKeyword) .WithStringField( "Area", mvcControllerNode.Identifier.ToString(), true, SyntaxKind.PublicKeyword, SyntaxKind.ReadOnlyKeyword) .WithField("s_actions", "ActionNamesClass", SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword) .WithActionNameClass(mvcControllerNode) .WithActionConstantsClass(mvcControllerNode) .WithField("s_views", "ViewsClass", SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword) .WithViewsClass(_viewLocator.FindViews()); // create R4MVC_[Controller] class inheriting from partial // TODO chain base constructor call : base(Dummy.Instance) // TODO create [method]overrides(T4MVC_System_Web_Mvc_ActionResult callInfo) // TODO create method overrides that call above var r4ControllerClass = SyntaxNodeHelpers.CreateClass( GetR4MVCControllerClassName(genControllerClass), null, SyntaxKind.PublicKeyword, SyntaxKind.PartialKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()) .WithBaseTypes(mvcControllerNode.ToQualifiedName()) .WithDefaultConstructor(false, SyntaxKind.PublicKeyword); namespaceNode = namespaceNode.AddMembers(genControllerClass).AddMembers(r4ControllerClass); } yield return(namespaceNode); } }
private ClassDeclarationSyntax AddRedirectMethods(ClassDeclarationSyntax node) { var methods = new[] { MethodDeclaration(IdentifierName("RedirectToRouteResult"), Identifier("RedirectToAction")) .WithModifiers(SyntaxKind.ProtectedKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()) .AddParameterListParameters( Parameter(Identifier("result")).WithType(IdentifierName("IActionResult"))) .WithBody( Block( // var callInfo = result.GetR4MvcResult(); LocalDeclarationStatement( SyntaxNodeHelpers.VariableDeclaration("callInfo", InvocationExpression(SyntaxNodeHelpers.MemberAccess("result", "GetR4MvcResult")))), // return RedirectToRoute(callInfo.RouteValueDictionary); ReturnStatement( InvocationExpression(IdentifierName("RedirectToRoute")) .WithArgumentList( SyntaxNodeHelpers.MemberAccess("callInfo", "RouteValueDictionary"))))), MethodDeclaration(IdentifierName("RedirectToRouteResult"), Identifier("RedirectToAction")) .WithModifiers(SyntaxKind.ProtectedKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()) .AddParameterListParameters( Parameter(Identifier("taskResult")).WithGenericType("Task", "IActionResult")) .WithBody( Block( // return RedirectToAction(taskResult.Result); ReturnStatement( InvocationExpression(IdentifierName("RedirectToAction")) .WithArgumentList( SyntaxNodeHelpers.MemberAccess("taskResult", "Result"))))), MethodDeclaration(IdentifierName("RedirectToRouteResult"), Identifier("RedirectToActionPermanent")) .WithModifiers(SyntaxKind.ProtectedKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()) .AddParameterListParameters( Parameter(Identifier("result")).WithType(IdentifierName("IActionResult"))) .WithBody( Block( // var callInfo = result.GetR4MvcResult(); LocalDeclarationStatement( SyntaxNodeHelpers.VariableDeclaration("callInfo", InvocationExpression(SyntaxNodeHelpers.MemberAccess("result", "GetR4MvcResult")))), // return RedirectToRoutePermanent(callInfo.RouteValueDictionary); ReturnStatement( InvocationExpression(IdentifierName("RedirectToRoutePermanent")) .WithArgumentList( SyntaxNodeHelpers.MemberAccess("callInfo", "RouteValueDictionary"))))), MethodDeclaration(IdentifierName("RedirectToRouteResult"), Identifier("RedirectToActionPermanent")) .WithModifiers(SyntaxKind.ProtectedKeyword) .WithAttributes(SyntaxNodeHelpers.CreateGeneratedCodeAttribute(), SyntaxNodeHelpers.CreateDebugNonUserCodeAttribute()) .AddParameterListParameters( Parameter(Identifier("taskResult")).WithGenericType("Task", "IActionResult")) .WithBody( Block( // return RedirectToActionPermanent(taskResult.Result); ReturnStatement( InvocationExpression(IdentifierName("RedirectToActionPermanent")) .WithArgumentList( SyntaxNodeHelpers.MemberAccess("taskResult", "Result"))))), }; return(node.AddMembers(methods)); }