static FactoryTypeInfoWeaver()
        {
            cauldronInterceptionHelper = Builder.Current.GetType("CauldronInterceptionHelper", SearchContext.Module);

            unknownConstructorText = cauldronInterceptionHelper.CreateField(Modifiers.PublicStatic, (BuilderType)BuilderTypes.String, "UnknownConstructorText");
            unknownConstructorText.CustomAttributes.AddCompilerGeneratedAttribute();
            unknownConstructorText.CustomAttributes.AddEditorBrowsableAttribute(EditorBrowsableState.Never);

            cauldronInterceptionHelper
            .CreateStaticConstructor()
            .NewCoder()
            .SetValue(unknownConstructorText, UnknownConstructor)
            .Insert(InsertionPosition.Beginning);
        }
        private void CreateComponentCache(Builder builder, BuilderType cauldron)
        {
            var componentAttribute            = __ComponentAttribute.Instance;
            var componentConstructorAttribute = __ComponentConstructorAttribute.Type;
            var factory = __Factory.Instance;

            // Before we start let us find all factoryextensions and add a component attribute to them
            var factoryResolverInterface = __IFactoryResolver.Type;

            this.AddComponentAttribute(builder, builder.FindTypesByInterface(factoryResolverInterface), x => factoryResolverInterface.Fullname);
            // Also the same to all types that inherits from Factory<>
            var factoryGeneric = __Factory_1.Type;

            this.AddComponentAttribute(builder, builder.FindTypesByBaseClass(factoryGeneric), type =>
            {
                var factoryBase = type.BaseClasses.FirstOrDefault(x => x.Fullname.StartsWith("Cauldron.Activator.Factory"));
                if (factoryBase == null)
                {
                    return(type.Fullname);
                }

                return(factoryBase.GetGenericArgument(0).Fullname);
            });

            int counter     = 0;
            var arrayAvatar = builder.GetType("System.Array").New(x => new
            {
                Length = x.GetMethod("get_Length")
            });
            var extensionAvatar = builder.GetType("Cauldron.ExtensionsReflection").New(x => new
            {
                CreateInstance = x.GetMethod("CreateInstance", 2)
            });
            var factoryCacheInterface         = builder.GetType("Cauldron.Activator.IFactoryCache");
            var factoryTypeInfoInterface      = builder.GetType("Cauldron.Activator.IFactoryTypeInfo");
            var createInstanceInterfaceMethod = factoryTypeInfoInterface.GetMethod("CreateInstance", 1);

            // Get all Components
            var components     = builder.FindTypesByAttribute(componentAttribute.ToBuilderType);
            var componentTypes = new List <BuilderType>();

            // Create types with the components properties
            foreach (var component in components)
            {
                this.Log("Hardcoding component factory .ctor: " + component.Type.Fullname);

                var componentType           = builder.CreateType("", TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, $"<>f__IFactoryTypeInfo_{component.Type.Name}_{counter++}");
                var componentAttributeField = componentType.CreateField(Modifiers.Private, componentAttribute.ToBuilderType, "componentAttribute");
                componentType.AddInterface(factoryTypeInfoInterface);
                componentTypes.Add(componentType);

                // Create ctor
                componentType
                .CreateConstructor()
                .NewCode()
                .Context(x =>
                {
                    x.Load(Crumb.This).Call(builder.GetType(typeof(object)).Import().ParameterlessContructor.Import());
                    x.Assign(componentAttributeField).NewObj(component);
                })
                .Return()
                .Replace();

                // Implement the methods
                componentType.CreateMethod(Modifiers.Public | Modifiers.Overrrides, createInstanceInterfaceMethod.ReturnType, createInstanceInterfaceMethod.Name, createInstanceInterfaceMethod.Parameters)
                .NewCode()
                .Context(x =>
                {
                    var localVariable = x.GetReturnVariable();
                    // Find any method with a componentcontructor attribute
                    var ctors = component.Type.GetMethods(y =>
                    {
                        if (y.Name == ".cctor")
                        {
                            return(true);
                        }

                        if (!y.Resolve().IsPublic || !y.Resolve().IsAssembly)
                        {
                            return(false);
                        }

                        if (y.Name == ".ctor" && y.DeclaringType.FullName.GetHashCode() != component.Type.Fullname.GetHashCode() && y.DeclaringType.FullName != component.Type.Fullname)
                        {
                            return(false);
                        }

                        if (y.Name.StartsWith("set_"))
                        {
                            return(false);
                        }

                        return(true);
                    })
                                .Where(y => y.CustomAttributes.HasAttribute(componentConstructorAttribute))
                                .Concat(
                        component.Type.GetAllProperties().Where(y => y.CustomAttributes.HasAttribute(componentConstructorAttribute))
                        .Select(y =>
                    {
                        y.CustomAttributes.Remove(componentConstructorAttribute);
                        y.CustomAttributes.AddEditorBrowsableAttribute(EditorBrowsableState.Never);

                        return(y.Getter);
                    })
                        )
                                .OrderBy(y => y.Parameters.Length)
                                .ToArray();

                    if (ctors.Length > 0)
                    {
                        bool parameterlessCtorAlreadyHandled = false;

                        for (int index = 0; index < ctors.Length; index++)
                        {
                            this.Log("- " + ctors[index].Fullname);

                            var ctor = ctors[index];
                            // add a EditorBrowsable attribute
                            ctor.CustomAttributes.AddEditorBrowsableAttribute(EditorBrowsableState.Never);
                            var ctorParameters = ctor.Parameters;

                            if (ctorParameters.Length > 0)
                            {
                                // In this case we have to find a parameterless constructor first
                                if (component.Type.ParameterlessContructor != null && !parameterlessCtorAlreadyHandled && component.Type.ParameterlessContructor.IsPublicOrInternal)
                                {
                                    x.Load(Crumb.GetParameter(0)).IsNull().Then(y => y.NewObj(component.Type.ParameterlessContructor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                    x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(0).Then(y => y.NewObj(component.Type.ParameterlessContructor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                    parameterlessCtorAlreadyHandled = true;
                                }

                                var code = x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(ctorParameters.Length);

                                for (int i = 0; i < ctorParameters.Length; i++)
                                {
                                    code.And.Load(Crumb.GetParameter(0).UnPacked(i)).Is(ctorParameters[i]);
                                }

                                if (ctor.Name == ".ctor")
                                {
                                    code.Then(y => y.NewObj(ctor, Crumb.GetParameter(0).UnPacked()).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                }
                                else
                                {
                                    code.Then(y => y.Call(ctor, Crumb.GetParameter(0).UnPacked()).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                }
                            }
                            else
                            {
                                if (ctor.Name == ".ctor")
                                {
                                    x.Load(Crumb.GetParameter(0)).IsNull().Then(y => y.NewObj(ctor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                    x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(0).Then(y => y.NewObj(ctor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                }
                                else
                                {
                                    x.Load(Crumb.GetParameter(0)).IsNull().Then(y => y.Call(ctor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                    x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(0).Then(y => y.Call(ctor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                                }

                                parameterlessCtorAlreadyHandled = true;
                            }
                        }
                    }
                    else
                    {
                        // In case we don't have constructor with ComponentConstructor Attribute,
                        // then we should look for a parameterless Ctor
                        if (component.Type.ParameterlessContructor == null)
                        {
                            this.Log(LogTypes.Error, component.Type, $"The component '{component.Type.Fullname}' has no ComponentConstructor attribute or the constructor is not public");
                        }
                        else if (component.Type.ParameterlessContructor.IsPublicOrInternal)
                        {
                            x.Load(Crumb.GetParameter(0)).IsNull().Then(y => y.NewObj(component.Type.ParameterlessContructor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());
                            x.Load(Crumb.GetParameter(0)).Call(arrayAvatar.Length).EqualTo(0).Then(y => y.NewObj(component.Type.ParameterlessContructor).Dup().Call(factory.OnObjectCreation, Crumb.This).Return());

                            this.Log($"The component '{component.Type.Fullname}' has no ComponentConstructor attribute. A parameterless ctor was found and will be used.");
                        }
                    }
                })
                .Context(x => x.Call(extensionAvatar.CreateInstance, component.Type, Crumb.GetParameter(0)).Dup().Call(factory.OnObjectCreation, Crumb.This).Return())
                .Return()
                .Replace();

                // Implement the properties
                foreach (var property in factoryTypeInfoInterface.Properties)
                {
                    var propertyResult = componentType.CreateProperty(Modifiers.Public | Modifiers.Overrrides, property.ReturnType, property.Name, true);
                    propertyResult.BackingField.Remove();

                    switch (property.Name)
                    {
                    case "ContractName":
                        propertyResult.Getter.NewCode().Call(componentAttributeField, componentAttribute.ContractName).Return().Replace();
                        break;

                    case "CreationPolicy":
                        propertyResult.Getter.NewCode().Call(componentAttributeField, componentAttribute.Policy).Return().Replace();
                        break;

                    case "Priority":
                        propertyResult.Getter.NewCode().Call(componentAttributeField, componentAttribute.Priority).Return().Replace();
                        break;

                    case "Type":
                        propertyResult.Getter.NewCode().Load(component.Type).Return().Replace();
                        break;
                    }
                }

                componentType.CustomAttributes.AddEditorBrowsableAttribute(EditorBrowsableState.Never);
                // Also remove the component attribute
                component.Attribute.Remove();
            }

            this.Log("Adding component IFactoryCache Interface");
            cauldron.AddInterface(factoryCacheInterface);
            var factoryCacheInterfaceAvatar = factoryCacheInterface.New(x => new
            {
                Components = x.GetMethod("GetComponents")
            });
            var ctorCoder = cauldron.ParameterlessContructor.NewCode();

            cauldron.CreateMethod(Modifiers.Public | Modifiers.Overrrides, factoryCacheInterfaceAvatar.Components.ReturnType, factoryCacheInterfaceAvatar.Components.Name)
            .NewCode()
            .Context(x =>
            {
                var resultValue = x.GetReturnVariable();
                x.Newarr(factoryTypeInfoInterface, componentTypes.Count).StoreLocal(resultValue);

                for (int i = 0; i < componentTypes.Count; i++)
                {
                    var field = cauldron.CreateField(Modifiers.Private, factoryTypeInfoInterface, "<FactoryType>f__" + i);
                    x.Load(resultValue);
                    x.StoreElement(factoryTypeInfoInterface, field, i);
                    // x.StoreElement(factoryTypeInfoInterface,
                    // x.NewCode().NewObj(componentTypes[i].ParameterlessContructor), i);
                    ctorCoder.Assign(field).NewObj(componentTypes[i].ParameterlessContructor);
                }
            })
            .Return()
            .Replace();

            ctorCoder.Insert(InsertionPosition.End);
        }