public async Task <CodeGenResult> CodeGen(Workspace workspace, Project project)
        {
            var usings = new HashSet <string>();

            usings.UnionWith(GetCommonUsings());
            CompilationUnitSyntax cu = SF.CompilationUnit();

            foreach (Document document in project.Documents)
            {
                SyntaxTree syntaxTree = await document.GetSyntaxTreeAsync();

                SemanticModel semanticModel = await document.GetSemanticModelAsync();

                IEnumerable <InterfaceDeclarationSyntax> interfaces = syntaxTree.GetRoot().DescendantNodes().OfType <InterfaceDeclarationSyntax>();

                bool copyDocumentUsings = false;

                foreach (var interfaceNode in interfaces)
                {
                    ClassDeclarationSyntax classDclr = GenerateApiControllerForInterface(interfaceNode, semanticModel);
                    if (classDclr == null)
                    {
                        continue;
                    }

                    // only copy the usings in the document if at least one ApiController is generated
                    copyDocumentUsings = true;
                    var namespaceNode = interfaceNode.Parent as NamespaceDeclarationSyntax;
                    // ReSharper disable once PossibleNullReferenceException
                    usings.UnionWith(namespaceNode.Usings.Select(@using => @using.Name.ToString()));

                    // use the same namespace in the generated class
                    string fullNameSpace = semanticModel.GetDeclaredSymbol(namespaceNode).ToString();
                    NamespaceDeclarationSyntax namespaceDclr = SF.NamespaceDeclaration(SF.IdentifierName(fullNameSpace)).WithUsings(namespaceNode.Usings);
                    namespaceDclr = namespaceDclr.AddMembers(classDclr);
                    cu            = cu.AddMembers(namespaceDclr);
                }
                if (copyDocumentUsings)
                {
                    usings.UnionWith(syntaxTree.GetRoot().DescendantNodes().OfType <UsingDirectiveSyntax>().Select(@using => @using.Name.ToString()));
                }
            }

            return(new CodeGenResult(Formatter.Format(cu, workspace).ToString(), usings));
        }
示例#2
0
        public SyntaxTree Generate(TransducerCompilation source)
        {
            var stb = source.Transducer;

            var sourceNamespace = source.DeclarationType.ContainingNamespace.DeclaringSyntaxReferences[0].GetSyntax() as NamespaceDeclarationSyntax;

            if (sourceNamespace == null)
            {
                throw new CodeGenerationException("Containing namespace declaration not found for " + source.DeclarationType);
            }

            // Follow the declaration of the original (partial) class
            var classDecl = source.DeclarationType.DeclaringSyntaxReferences.Select(r => r.GetSyntax()).OfType <ClassDeclarationSyntax>().FirstOrDefault()
                            .WithLeadingTrivia().WithTrailingTrivia() // Strip any trivia
                            .WithMembers(SF.List <MemberDeclarationSyntax>())
                            .WithAttributeLists(SF.List <AttributeListSyntax>());

            if (classDecl == null)
            {
                throw new Exception("Class declaration for " + source.DeclarationType + " not found");
            }

            classDecl = _concreteCG.Generate(source, stb, classDecl);

            var automataNamespace = SF.IdentifierName("Microsoft").Qualified(SF.IdentifierName("Automata")).Qualified(SF.IdentifierName("CSharpFrontend"));
            var root = SF.CompilationUnit()
                       .WithUsings(SF.List(new[]
            {
                SF.UsingDirective(SF.IdentifierName("System")),
                SF.UsingDirective(SF.IdentifierName("System").Qualified(SF.IdentifierName("Text"))),
                SF.UsingDirective(SF.IdentifierName("System").Qualified(SF.IdentifierName("IO"))),
                SF.UsingDirective(SF.IdentifierName("System").Qualified(SF.IdentifierName("Collections")).Qualified(SF.IdentifierName("Generic"))),
                SF.UsingDirective(automataNamespace),
            }))
                       .WithMembers(SF.SingletonList((MemberDeclarationSyntax)SF.NamespaceDeclaration(sourceNamespace.Name)
                                                     .WithMembers(SF.SingletonList((MemberDeclarationSyntax)classDecl))));
            var normalized = root.NormalizeWhitespace();

            return(SF.SyntaxTree(normalized));
        }
示例#3
0
        /// <summary>
        /// Generates a syntax tree for the provided assemblies.
        /// </summary>
        /// <param name="assemblies">The assemblies to generate code for.</param>
        /// <param name="runtime">Whether or not runtime code generation is being performed.</param>
        /// <returns>The generated syntax tree.</returns>
        private GeneratedSyntax GenerateForAssemblies(List <Assembly> assemblies, bool runtime)
        {
            if (Logger.IsVerbose)
            {
                Logger.Verbose(
                    "Generating code for assemblies: {0}",
                    string.Join(", ", assemblies.Select(_ => _.FullName)));
            }

            Assembly       targetAssembly;
            HashSet <Type> ignoredTypes;

            if (runtime)
            {
                // Ignore types which have already been accounted for.
                ignoredTypes   = GetTypesWithGeneratedSupportClasses();
                targetAssembly = null;
            }
            else
            {
                ignoredTypes   = new HashSet <Type>();
                targetAssembly = assemblies.FirstOrDefault();
            }

            var members = new List <MemberDeclarationSyntax>();

            // Include assemblies which are marked as included.
            var knownAssemblyAttributes = new Dictionary <Assembly, KnownAssemblyAttribute>();
            var knownAssemblies         = new HashSet <Assembly>();

            foreach (var attribute in assemblies.SelectMany(asm => asm.GetCustomAttributes <KnownAssemblyAttribute>()))
            {
                knownAssemblyAttributes[attribute.Assembly] = attribute;
                knownAssemblies.Add(attribute.Assembly);
            }

            if (knownAssemblies.Count > 0)
            {
                knownAssemblies.UnionWith(assemblies);
                assemblies = knownAssemblies.ToList();
            }

            // Get types from assemblies which reference Orleans and are not generated assemblies.
            var includedTypes = new HashSet <Type>();

            for (var i = 0; i < assemblies.Count; i++)
            {
                var assembly = assemblies[i];
                foreach (var attribute in assembly.GetCustomAttributes <ConsiderForCodeGenerationAttribute>())
                {
                    ConsiderType(attribute.Type, runtime, targetAssembly, includedTypes, considerForSerialization: true);
                    if (attribute.ThrowOnFailure && !serializerGenerationManager.IsTypeRecorded(attribute.Type))
                    {
                        throw new CodeGenerationException(
                                  $"Found {attribute.GetType().Name} for type {attribute.Type.GetParseableName()}, but code"
                                  + " could not be generated. Ensure that the type is accessible.");
                    }
                }

                KnownAssemblyAttribute knownAssemblyAttribute;
                var considerAllTypesForSerialization = knownAssemblyAttributes.TryGetValue(assembly, out knownAssemblyAttribute) &&
                                                       knownAssemblyAttribute.TreatTypesAsSerializable;
                foreach (var type in TypeUtils.GetDefinedTypes(assembly, Logger))
                {
                    var considerForSerialization = considerAllTypesForSerialization || type.IsSerializable;
                    ConsiderType(type.AsType(), runtime, targetAssembly, includedTypes, considerForSerialization);
                }
            }

            includedTypes.RemoveWhere(_ => ignoredTypes.Contains(_));

            // Group the types by namespace and generate the required code in each namespace.
            foreach (var group in includedTypes.GroupBy(_ => CodeGeneratorCommon.GetGeneratedNamespace(_)))
            {
                var namespaceMembers = new List <MemberDeclarationSyntax>();
                foreach (var type in group)
                {
                    // The module containing the serializer.
                    var module = runtime ? null : type.GetTypeInfo().Module;

                    // Every type which is encountered must be considered for serialization.
                    Action <Type> onEncounteredType = encounteredType =>
                    {
                        // If a type was encountered which can be accessed, process it for serialization.
                        serializerGenerationManager.RecordTypeToGenerate(encounteredType, module, targetAssembly);
                    };

                    if (Logger.IsVerbose2)
                    {
                        Logger.Verbose2("Generating code for: {0}", type.GetParseableName());
                    }

                    if (GrainInterfaceUtils.IsGrainInterface(type))
                    {
                        if (Logger.IsVerbose2)
                        {
                            Logger.Verbose2(
                                "Generating GrainReference and MethodInvoker for {0}",
                                type.GetParseableName());
                        }

                        GrainInterfaceUtils.ValidateInterfaceRules(type);

                        namespaceMembers.Add(GrainReferenceGenerator.GenerateClass(type, onEncounteredType));
                        namespaceMembers.Add(GrainMethodInvokerGenerator.GenerateClass(type));
                    }

                    // Generate serializers.
                    var  first = true;
                    Type toGen;
                    while (serializerGenerationManager.GetNextTypeToProcess(out toGen))
                    {
                        if (!runtime)
                        {
                            if (first)
                            {
                                ConsoleText.WriteStatus("ClientGenerator - Generating serializer classes for types:");
                                first = false;
                            }

                            ConsoleText.WriteStatus(
                                "\ttype " + toGen.FullName + " in namespace " + toGen.Namespace
                                + " defined in Assembly " + toGen.GetTypeInfo().Assembly.GetName());
                        }

                        if (Logger.IsVerbose2)
                        {
                            Logger.Verbose2(
                                "Generating & Registering Serializer for Type {0}",
                                toGen.GetParseableName());
                        }

                        namespaceMembers.Add(SerializerGenerator.GenerateClass(toGen, onEncounteredType));
                    }
                }

                if (namespaceMembers.Count == 0)
                {
                    if (Logger.IsVerbose)
                    {
                        Logger.Verbose2("Skipping namespace: {0}", group.Key);
                    }

                    continue;
                }

                members.Add(
                    SF.NamespaceDeclaration(SF.ParseName(group.Key))
                    .AddUsings(
                        TypeUtils.GetNamespaces(typeof(TaskUtility), typeof(GrainExtensions), typeof(IntrospectionExtensions))
                        .Select(_ => SF.UsingDirective(SF.ParseName(_)))
                        .ToArray())
                    .AddMembers(namespaceMembers.ToArray()));
            }

            return(new GeneratedSyntax
            {
                SourceAssemblies = assemblies,
                Syntax = members.Count > 0 ? SF.CompilationUnit().AddMembers(members.ToArray()) : null
            });
        }
        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));
        }
示例#5
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));
        }