Пример #1
0
        public void GetFullName_ClassInterfaces(Type classType, params string[] expected)
        {
            var actual = classType
                         .GetInterfaces()
                         .Where(p => GrainInterfaceUtils.IsGrainInterface(p))
                         .Select(p => GrainInterfaceUtils.GetFullName(p))
                         .ToArray();

            _testOutputHelper.WriteLine("Expected: " + string.Join(";", expected));
            _testOutputHelper.WriteLine("Actual: " + string.Join(";", actual));

            Assert.Equal(expected, actual);
        }
Пример #2
0
        private void ConsiderType(
            Type type,
            bool runtime,
            Assembly targetAssembly,
            ISet <Type> includedTypes,
            bool considerForSerialization = false)
        {
            // The module containing the serializer.
            var typeInfo = type.GetTypeInfo();
            var module   = runtime || !Equals(typeInfo.Assembly, targetAssembly) ? null : typeInfo.Module;

            // If a type was encountered which can be accessed and is marked as [Serializable], process it for serialization.
            if (considerForSerialization)
            {
                RecordType(type, module, targetAssembly, includedTypes);
            }

            // Consider generic arguments to base types and implemented interfaces for code generation.
            ConsiderGenericBaseTypeArguments(typeInfo, module, targetAssembly, includedTypes);
            ConsiderGenericInterfacesArguments(typeInfo, module, targetAssembly, includedTypes);

            // Include grain interface types.
            if (GrainInterfaceUtils.IsGrainInterface(type))
            {
                // If code generation is being performed at runtime, the interface must be accessible to the generated code.
                if (!runtime || TypeUtilities.IsAccessibleFromAssembly(type, targetAssembly))
                {
                    if (Logger.IsVerbose2)
                    {
                        Logger.Verbose2("Will generate code for: {0}", type.GetParseableName());
                    }

                    includedTypes.Add(type);
                }
            }
        }
Пример #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
            });
        }