private static ClassDeclarationSyntax GenerateApiControllerForInterface(InterfaceDeclarationSyntax interfaceNode, SemanticModel semanticModel) { if (!RoslynUtils.IsPublic(interfaceNode)) { return(null); } AttributeSyntax apiControllerAttribute = AttributeUtils.SelectAttributeOfType(interfaceNode.AttributeLists, typeof(ApiControllerAttribute), semanticModel); // if the interface is not annotated with the ApiController attribute, do nothing if (apiControllerAttribute == null) { return(null); } var namespaceNode = interfaceNode.Parent as NamespaceDeclarationSyntax; if (namespaceNode == null) { throw new Exception("A grain interface must be declared inside a namespace"); } // copy all attributes except the ApiController attribute SyntaxList <AttributeListSyntax> attributesLists = AttributeUtils.RemoveAttributeOfType(interfaceNode.AttributeLists, typeof(ApiControllerAttribute), semanticModel); // add the RoutePrefix attribute (if any) var attributeInspector = new AttributeInspector(apiControllerAttribute, semanticModel); if (attributeInspector.NamedArguments.ContainsKey(RoutePrefix)) { AttributeSyntax routePrefixAttribute = AttributeUtils.AttributeWithArgument(RoutePrefix, attributeInspector.NamedArguments[RoutePrefix]); attributesLists = attributesLists.Add(AttributeUtils.AttributeList(routePrefixAttribute)); } string grainName = interfaceNode.Identifier.Text; string apiControllerName = GetApiControllerName(grainName); // create the Api controller class, add the attributes to it and make it a subclass of ApiController ClassDeclarationSyntax classDclr = SF.ClassDeclaration(SF.Identifier(apiControllerName)).AddModifiers(SF.Token(SyntaxKind.PublicKeyword), SF.Token(SyntaxKind.PartialKeyword)).WithAttributeLists(SF.List(attributesLists)).WithBaseList(SF.BaseList(SF.SeparatedList <BaseTypeSyntax>().Add(SF.SimpleBaseType(SF.IdentifierName(ApicontrollerClassName))))); // Add the IGrainFactory field and to the constructor classDclr = RoslynUtils.AddField(classDclr, "IGrainFactory", "_grainFactory"); MethodDeclarationSyntax constructor = RoslynUtils.ParseMethod(string.Format(@" public {0}(IGrainFactory grainFactory) {{ _grainFactory = grainFactory; }}", apiControllerName)).WithTrailingTrivia(SF.EndOfLine("")); classDclr = classDclr.AddMembers(constructor); // generate the api controller methods and add them to the class IEnumerable <MethodDeclarationSyntax> apiControllerMethods = GenerateApiControllerMethods(RoslynUtils.GetMethodDeclarations(interfaceNode), grainName); // ReSharper disable once LoopCanBeConvertedToQuery foreach (var method in apiControllerMethods) { classDclr = classDclr.AddMembers(method); } return(classDclr); }
public async Task <CodeGenResult> CodeGen(Workspace workspace, Project project) { CompilationUnitSyntax cu = SF.CompilationUnit(); var usings = new HashSet <string>(); bool copyUsings = false; foreach (Document document in project.Documents) { SyntaxTree syntaxTree = await document.GetSyntaxTreeAsync(); _semanticModel = await document.GetSemanticModelAsync(); IEnumerable <ClassDeclarationSyntax> classes = syntaxTree.GetRoot().DescendantNodes().OfType <ClassDeclarationSyntax>(); foreach (var classNode in classes) { if (!RoslynUtils.IsPublic(classNode)) { continue; } ITypeSymbol swmrInterface = FindSwmrInterface(classNode); if (swmrInterface == null) { continue; } var namespaceNode = classNode.Parent as NamespaceDeclarationSyntax; if (namespaceNode == null) { throw new Exception("A grain must be declared inside a namespace"); } usings.UnionWith(syntaxTree.GetRoot().DescendantNodes().OfType <UsingDirectiveSyntax>().Select(usingDirective => usingDirective.Name.ToString())); int replicaCount = GetReadReplicaCount(swmrInterface); NamespaceDeclarationSyntax namespaceDclr = SF.NamespaceDeclaration(SF.IdentifierName(namespaceNode.Name.ToString())).WithUsings(namespaceNode.Usings); namespaceDclr = namespaceDclr.AddMembers( GenerateWriteGrain(classNode, swmrInterface, replicaCount), GenerateReadGrain(classNode, swmrInterface, replicaCount), GenerateReadReplicaGrain(classNode, swmrInterface) ); usings.UnionWith(namespaceNode.Usings.Select(@using => @using.Name.ToString())); cu = cu.AddMembers(namespaceDclr); // only copy the usings if at least one class was generated copyUsings = true; } } if (copyUsings) { usings.UnionWith(GetCommonUsings()); } return(new CodeGenResult(Formatter.Format(cu, workspace).ToString(), usings)); }
public async Task <CodeGenResult> CodeGen(Workspace workspace, Project project) { CompilationUnitSyntax cu = SF.CompilationUnit(); var usings = new HashSet <string>(); foreach (Document document in project.Documents) { SyntaxTree syntaxTree = await document.GetSyntaxTreeAsync(); _semanticModel = await document.GetSemanticModelAsync(); IEnumerable <InterfaceDeclarationSyntax> interfaces = syntaxTree.GetRoot().DescendantNodes().OfType <InterfaceDeclarationSyntax>(); foreach (var interfaceNode in interfaces) { if (!RoslynUtils.IsPublic(interfaceNode)) { continue; } AttributeSyntax swmrAttribute = AttributeUtils.SelectAttributeOfType(interfaceNode.AttributeLists, typeof(SingleWriterMultipleReadersAttribute), _semanticModel); if (swmrAttribute == null) { continue; } var namespaceNode = interfaceNode.Parent as NamespaceDeclarationSyntax; if (namespaceNode == null) { throw new Exception("A grain interface must be declared inside a namespace"); } usings.UnionWith(syntaxTree.GetRoot().DescendantNodes().OfType <UsingDirectiveSyntax>().Select(usingDirective => usingDirective.Name.ToString())); var methods = RoslynUtils.GetMethodDeclarations(interfaceNode); var readMethods = SwmrUtils.GetReadOnlyMethods(methods, _semanticModel); var writeMethods = methods.Except(readMethods).Where(method => new MethodInspector(method).MethodName != "GetState"); readMethods = SwmrUtils.RemoveReadOnlyAttribute(readMethods, _semanticModel); string grainInterfaceName = interfaceNode.Identifier.Text; var readReplicaMethods = new List <MethodDeclarationSyntax>(readMethods) { GenerateSetStateMethod() }; InterfaceDeclarationSyntax readReplicaInterface = GenerateInterface(SwmrUtils.GetReadReplicaInterfaceName(grainInterfaceName), readReplicaMethods, interfaceNode.BaseList); readMethods = SwmrUtils.AddSessionIdParameter(readMethods); writeMethods = SwmrUtils.AddSessionIdParameter(writeMethods); string readerInterfaceName = SwmrUtils.GetReadInterfaceName(grainInterfaceName); string writerInterfaceName = SwmrUtils.GetWriteInterfaceName(grainInterfaceName); InterfaceDeclarationSyntax readerInterface = GenerateInterface(readerInterfaceName, readMethods, interfaceNode.BaseList); InterfaceDeclarationSyntax writerInterface = GenerateInterface(writerInterfaceName, writeMethods, interfaceNode.BaseList); string fullNameSpace = _semanticModel.GetDeclaredSymbol(namespaceNode).ToString(); NamespaceDeclarationSyntax namespaceDclr = SF.NamespaceDeclaration(SF.IdentifierName(fullNameSpace)).WithUsings(namespaceNode.Usings); namespaceDclr = namespaceDclr.AddMembers(readerInterface, writerInterface, readReplicaInterface); usings.UnionWith(namespaceNode.Usings.Select(@using => @using.Name.ToString())); usings.Remove("ETG.Orleans.Attributes"); cu = cu.AddMembers(namespaceDclr); } } return(new CodeGenResult(Formatter.Format(cu, workspace).ToString(), usings)); }