public ReactAssembly AnalyzeAndConstructAssemblyModel()
        {
            Contract.Assert(m_compilation != null, "Expected to have a compilation. Must call CompileAndCheckForErrors first");

            var assembly       = new ReactAssembly();
            var proceseedTypes = new HashSet <ITypeSymbol>();

            foreach (var type in GetAllTypes())
            {
                if (TryExtractModule(type, out var module))
                {
                    assembly.Modules.Add(module);
                }

                if (IsViewManager(type))
                {
                    assembly.ViewManagers.Add(type);
                }

                // Proactively register serializable types.
                switch (type.TypeKind)
                {
                case TypeKind.Enum:
                    assembly.SerializableTypes.Add(type, type.TypeKind);
                    break;
                }

                // Register extension methods
                if (type.MightContainExtensionMethods)
                {
                    foreach (var member in type.GetMembers())
                    {
                        if (member is IMethodSymbol method)
                        {
                            if (method.IsExtensionMethod &&
                                method.Parameters.Length == 2 &&
                                !(method.Parameters[1].Type is ITypeParameterSymbol))
                            {
                                if (method.Parameters[0].Type.Equals(ReactTypes.JSValueReader, SymbolEqualityComparer.Default) &&
                                    method.Parameters[1].RefKind == RefKind.Out)
                                {
                                    assembly.JSReaderFunctions.Add(method.Parameters[1].Type, method);
                                }
                                else if (method.Parameters[0].Type.Equals(ReactTypes.JSValueWriter, SymbolEqualityComparer.Default))
                                {
                                    assembly.JSWriterFunctions.Add(method.Parameters[1].Type, method);
                                }
                            }
                        }
                    }
                }
            }

            foreach (var module in assembly.Modules)
            {
                foreach (var method in module.Methods)
                {
                    AddSerializableMethod(method.Method);
                }

                foreach (var constant in module.Constants)
                {
                    if (constant.Symbol is IFieldSymbol field)
                    {
                        AddSerializableType(field.Type);
                    }
                    else if (constant.Symbol is IPropertySymbol property)
                    {
                        AddSerializableType(property.Type);
                    }
                }

                foreach (var callback in module.Events.Union <ReactCallback>(module.Functions))
                {
                    foreach (var param in callback.CallbackParameters)
                    {
                        AddSerializableType(param.Type);
                    }
                }
            }

            void AddSerializableMethod(IMethodSymbol method)
            {
                AddSerializableType(method.ReturnType);
                foreach (var param in method.Parameters)
                {
                    AddSerializableType(param.Type);
                }
            }

            void AddSerializableType(ITypeSymbol type)
            {
                if (proceseedTypes.Contains(type))
                {
                    return;
                }

                proceseedTypes.Add(type);

                if (type is INamedTypeSymbol namedType)
                {
                    if (type.TypeKind == TypeKind.Delegate)
                    {
                        Contract.Assert(namedType.DelegateInvokeMethod != null);

                        AddSerializableMethod(namedType.DelegateInvokeMethod);
                    }
                    else if (type.ContainingAssembly.Equals(m_compilation.Assembly, SymbolEqualityComparer.Default))
                    {
                        if (namedType.TypeKind == TypeKind.Class)
                        {
                            // Check that classes have a default constructor.
                            if (!namedType
                                .GetMembers()
                                .Any(member =>
                                     member is IMethodSymbol method &&
                                     method.MethodKind == MethodKind.Constructor &&
                                     method.Parameters.Length == 0))
                            {
                            }
                        }

                        assembly.SerializableTypes.Add(namedType, namedType.TypeKind);
                    }
                }
            }

            return(assembly);
        }
        public CSharpSyntaxNode Generate(ReactAssembly assembly)
        {
            var registrationInvocations = new List <StatementSyntax>();
            var providerMembers         = new List <MemberDeclarationSyntax>();

            if (assembly.ViewManagers.Any())
            {
                registrationInvocations.Add(InvocationStatement(ReactNativeNames.CreateViewManagers, IdentifierName(ReactNativeNames.PackageBuilderId)));
                providerMembers.Add(CreateViewManagers(assembly.ViewManagers));
            }

            if (assembly.Modules.Any())
            {
                registrationInvocations.Add(InvocationStatement(ReactNativeNames.CreateModules, IdentifierName((ReactNativeNames.PackageBuilderId))));
                providerMembers.Add(CreateModules(assembly.Modules));
            }

            if (assembly.SerializableTypes.Any())
            {
                registrationInvocations.Add(InvocationStatement(ReactNativeNames.CreateSerializers));
                providerMembers.AddRange(CreateSerializers(assembly.SerializableTypes.Keys));
            }

            if (assembly.JSReaderFunctions.Any())
            {
                registrationInvocations.Add(InvocationStatement(ReactNativeNames.RegisterExtensionReaders));
                providerMembers.Add(RegisterExtensionReaders(assembly.JSReaderFunctions));
            }

            if (assembly.JSWriterFunctions.Any())
            {
                registrationInvocations.Add(InvocationStatement(ReactNativeNames.RegisterExtensionWriter));
                providerMembers.Add(RegisterExtensionWriter(assembly.JSWriterFunctions));
            }

            // Generates:
            //  public void CreatePackage(IPackageBuilder packageBuilder)
            //  {
            //    ... registrationInvocations
            //  }
            var createPackageMethod = MethodDeclaration(
                PredefinedType(Token(SyntaxKind.VoidKeyword)),
                ReactNativeNames.CreatePackage)
                                      .AddModifiers(
                Token(SyntaxKind.PublicKeyword))
                                      .AddParameterListParameters(
                GetPackageBuilderArgument())
                                      .WithBody(
                Block(
                    registrationInvocations
                    ));

            // Ensure the main package registration implementation is at the top of the file.
            providerMembers.Insert(0, createPackageMethod);

            // Generates:
            //    namespace "MyNS"
            //    {
            //      public sealed partial ReactPackageProvider : IReactPackageProvider
            //      {
            //        ... providerMembers
            //      }
            //    }
            var ns =
                NamespaceDeclaration(ParseName(m_rootNamespace))
                .AddMembers(
                    ClassDeclaration("ReactPackageProvider")
                    .AddModifiers(
                        Token(SyntaxKind.PublicKeyword),
                        Token(SyntaxKind.SealedKeyword),
                        Token(SyntaxKind.PartialKeyword))
                    .AddBaseListTypes(
                        SimpleBaseType(
                            m_reactTypes.IReactPackageProvider.ToTypeSyntax()))
                    .WithMembers(
                        new SyntaxList <MemberDeclarationSyntax>(providerMembers))
                    );

            return(ns);
        }