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));
        }
Пример #3
0
        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));
        }