Beispiel #1
0
        private IDictionary <string, Binding> ProcessCompleteModule(ModuleGenerator moduleGenerator, bool ignoreCompletenessErrors)
        {
            var bindings   = new Dictionary <string, Binding>(StringComparer.Ordinal);
            var overrides  = new Dictionary <string, Binding>(StringComparer.Ordinal);
            var allModules = new Dictionary <string, ModuleGenerator>(StringComparer.Ordinal);
            var hasError   = false;

            GatherIncludedModules(moduleGenerator, allModules, new Stack <string>());

            var resolver = new Resolver(null, plugin, errors =>
            {
                if (ignoreCompletenessErrors)
                {
                    return;
                }

                hasError = true;
                foreach (var e in errors)
                {
                    errorReporter.LogError(e);
                }
            });

            foreach (var module in allModules.Values)
            {
                // Request entry-point bindings
                var addTo = module.IsOverride ? overrides : bindings;

                foreach (var entryPointType in module.EntryPoints)
                {
                    var key = entryPointType.Resolve().IsInterface
                                  ? CompilerKeys.ForType(entryPointType)
                                  : CompilerKeys.GetMemberKey(entryPointType);
                    resolver.RequestBinding(key, module.ModuleType.FullName, false, true);
                }

                foreach (var providerGenerator in module.ProviderGenerators)
                {
                    var binding = new CompilerProvidesBinding(providerGenerator);

                    if (addTo.ContainsKey(binding.ProviderKey))
                    {
                        var message  = "Duplicate bindings for {0} in {1}{2}.";
                        var addendum = module.IsOverride ? "overriding module " : string.Empty;

                        throw new ValidationException(string.Format
                                                          (message, binding.ProviderKey, addendum, module.ModuleType.FullName));
                    }

                    addTo.Add(binding.ProviderKey, binding);
                }
            }

            resolver.InstallBindings(bindings);
            resolver.InstallBindings(overrides);
            var allBindings = resolver.ResolveAllBindings();

            return(hasError ? null : allBindings);
        }
Beispiel #2
0
        private void EmitCtor(TypeDefinition runtimeModule)
        {
            /**
             * public CompiledRuntimeModule()
             *     : base(typeof(OriginalModule),
             *            new[] { "key0", ..., "keyN" },
             *            new[] { typeof(IncludedModule0), ..., typeof(IncludedModuleN) },
             *            isComplete,
             *            isLibrary)
             * {
             * }
             */

            var ctor = new MethodDefinition(".ctor",
                                            MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
                                            References.Void);

            var il = ctor.Body.GetILProcessor();

            // Push args (this, moduleType, entryPoints, includes, complete, library) and call base ctor
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldtoken, importedModuleType);
            il.Emit(OpCodes.Call, References.Type_GetTypeFromHandle);

            // make array of entry point keys
            il.Emit(OpCodes.Ldc_I4, Injects.Count);
            il.Emit(OpCodes.Newarr, References.String);
            for (var i = 0; i < Injects.Count; ++i)
            {
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Ldc_I4, i);
                il.Emit(OpCodes.Ldstr, CompilerKeys.GetMemberKey(Injects[i]));
                il.Emit(OpCodes.Stelem_Ref);
            }

            // make array of included module types
            il.Emit(OpCodes.Ldc_I4, IncludedModules.Count);
            il.Emit(OpCodes.Newarr, References.Type);
            for (var i = 0; i < IncludedModules.Count; ++i)
            {
                il.Emit(OpCodes.Dup);
                il.Emit(OpCodes.Ldc_I4, i);
                il.Emit(OpCodes.Ldtoken, Import(IncludedModules[i]));
                il.Emit(OpCodes.Call, References.Type_GetTypeFromHandle);
                il.Emit(OpCodes.Stelem_Ref);
            }

            il.EmitBoolean(IsComplete);
            il.EmitBoolean(IsLibrary);
            il.EmitBoolean(IsOverride);

            il.Emit(OpCodes.Call, References.RuntimeModule_Ctor);
            il.Emit(OpCodes.Ret);

            runtimeModule.Methods.Add(ctor);
            generatedCtor = ctor;
        }
Beispiel #3
0
        public override void Validate(IErrorReporter errorReporter)
        {
            if (injectedType.HasGenericParameters)
            {
                errorReporter.LogError("Open generic types may not be injected: " + injectedType.FullName);
                return;
            }

            switch (injectedType.Attributes & TypeAttributes.VisibilityMask)
            {
            case TypeAttributes.NestedFamily:
            case TypeAttributes.NestedFamANDAssem:
            case TypeAttributes.NestedPrivate:
            case TypeAttributes.NotPublic:
                // This type is not externally visible and can't be included in a compiled plugin.
                // It can still be loaded reflectively.
                IsVisibleToPlugin = false;
                errorReporter.LogWarning(injectedType.FullName + ": This type is private, and will be loaded reflectively.  Consider making it internal or public.");
                break;
            }

            Key         = CompilerKeys.ForType(injectedType);
            MembersKey  = CompilerKeys.GetMemberKey(injectedType);
            IsSingleton = injectedType.CustomAttributes.Any(Attributes.IsSingletonAttribute);

            var injectableCtors = injectedType
                                  .GetConstructors()
                                  .Where(ctor => ctor.CustomAttributes.Any(Attributes.IsInjectAttribute))
                                  .ToList();

            foreach (var ctor in injectableCtors)
            {
                if (InjectableCtor != null)
                {
                    errorReporter.LogError(string.Format("{0} has more than one injectable constructor.", injectedType.FullName));
                }

                if (!ctor.Attributes.IsVisible())
                {
                    errorReporter.LogError("{0} has an injectable constructor, but it is not accessible.  Consider making it public.");
                }

                InjectableCtor = ctor;
            }

            InjectableProperties = injectedType
                                   .Properties
                                   .Where(p => p.DeclaringType == injectedType)
                                   .Where(p => p.CustomAttributes.Any(Attributes.IsInjectAttribute))
                                   .Select(p => new PropertyInfo(p))
                                   .ToList();

            foreach (var p in InjectableProperties)
            {
                if (p.Setter == null)
                {
                    errorReporter.LogError(string.Format("{0} is marked [Inject] but has no setter.", p.MemberName));
                    continue;
                }

                if (!p.Setter.Attributes.IsVisible())
                {
                    const string msg = "{0}.{1} is marked [Inject], but has no visible setter.  Consider adding a public setter.";
                    errorReporter.LogError(string.Format(msg, injectedType.FullName, p.PropertyName));
                }
            }

            if (InjectableCtor == null)
            {
                if (InjectableProperties.Count == 0 && !IsEntryPoint)
                {
                    errorReporter.LogError("No injectable constructors or properties found on " + injectedType.FullName);
                }

                var defaultCtor = injectedType.GetConstructors().FirstOrDefault(ctor => !ctor.HasParameters);
                if (defaultCtor == null)
                {
                    errorReporter.LogError("Type " + injectedType.FullName + " has no [Inject] constructors and no default constructor.");
                    return;
                }

                InjectableCtor = defaultCtor;
            }

            CtorParams = InjectableCtor.Parameters.Select(p => new InjectMemberInfo(p)).ToList();

            var baseType        = injectedType.BaseType;
            var baseTypeAsmName = baseType.Maybe(type => type.Scope)
                                  .Maybe(scope => scope.Name);

            if (baseType == null ||
                baseTypeAsmName == null ||
                baseTypeAsmName.StartsWith("mscorlib") ||
                baseTypeAsmName.StartsWith("System") ||
                baseTypeAsmName.StartsWith("Microsoft") ||
                baseTypeAsmName.StartsWith("Mono"))
            {
                // We can safely skip types known not to have [Inject] bindings, i.e. types
                // from the BCL, etc.
                BaseTypeKey = null;
            }
            else
            {
                // Otherwise, base types might have [Inject] properties that we'll need
                // to account for.
                BaseTypeKey = Weaver.EnqueueBaseTypeBinding(baseType)
                    ? CompilerKeys.ForType(baseType)
                    : null;
            }
        }
Beispiel #4
0
        public override void Validate(IErrorReporter errorReporter)
        {
            if (injectedType.HasGenericParameters)
            {
                if (genericInstanceType == null ||
                    genericInstanceType.GenericArguments.Count != injectedType.GenericParameters.Count)
                {
                    errorReporter.LogError("Open generic types may not be injected: " + injectedType.FullName);
                    return;
                }
            }

            if (!injectedType.IsVisible())
            {
                // This type is not externally visible and can't be included in a compiled loader.
                // It can still be loaded reflectively.
                IsVisibleToLoader = false;
                errorReporter.LogWarning(injectedType.FullName + ": This type is private, and will be loaded reflectively.  Consider making it internal or public.");
            }

            Key         = CompilerKeys.ForType(injectedType);
            MembersKey  = CompilerKeys.GetMemberKey(injectedType);
            IsSingleton = injectedType.CustomAttributes.Any(Attributes.IsSingletonAttribute);

            var injectableCtors = injectedType
                                  .GetConstructors()
                                  .Where(ctor => ctor.CustomAttributes.Any(Attributes.IsInjectAttribute))
                                  .ToList();

            foreach (var ctor in injectableCtors)
            {
                if (InjectableCtor != null)
                {
                    errorReporter.LogError(string.Format("{0} has more than one injectable constructor.", injectedType.FullName));
                }

                if (!ctor.IsVisible())
                {
                    errorReporter.LogError(string.Format("{0} has an injectable constructor, but it is not accessible.  Consider making it public.", injectedType.FullName));
                }

                InjectableCtor = ctor;
            }

            InjectableProperties = injectedType
                                   .Properties
                                   .Where(p => p.DeclaringType == injectedType)
                                   .Where(p => p.CustomAttributes.Any(Attributes.IsInjectAttribute))
                                   .Select(p => new PropertyInfo(p))
                                   .ToList();

            foreach (var p in InjectableProperties)
            {
                if (p.Setter == null)
                {
                    errorReporter.LogError(string.Format("{0} is marked [Inject] but has no setter.", p.MemberName));
                    continue;
                }

                if (!p.Setter.IsVisible())
                {
                    const string msg = "{0}.{1} is marked [Inject], but has no visible setter.  Consider adding a public setter.";
                    errorReporter.LogError(string.Format(msg, injectedType.FullName, p.PropertyName));
                }
            }

            if (InjectableCtor == null)
            {
                if (InjectableProperties.Count == 0 && !IsModuleInjectable)
                {
                    errorReporter.LogError("No injectable constructors or properties found on " + injectedType.FullName);
                }

                // XXX ben: this is wrong, I think - entry points with no ctor will still fail.
                var defaultCtor = injectedType.GetConstructors().FirstOrDefault(ctor => !ctor.HasParameters && ctor.IsVisible());
                if (defaultCtor == null && !IsModuleInjectable)
                {
                    errorReporter.LogError("Type " + injectedType.FullName + " has no [Inject] constructors and no default constructor.");
                    return;
                }

                InjectableCtor = defaultCtor;
            }
            // InjectableCtor is null iff this is a value-type entry-point with no default ctor.
            // It's OK, such types never get constructed, only "provided".
            CtorParams = InjectableCtor == null
                ? new List <InjectMemberInfo>()
                : InjectableCtor.Parameters.Select(p => new InjectMemberInfo(p)).ToList();

            var baseType        = injectedType.BaseType;
            var baseTypeAsmName = baseType.Maybe(type => type.Scope)
                                  .Maybe(scope => scope.Name);

            if (baseType == null ||
                baseTypeAsmName == null ||
                baseTypeAsmName.StartsWith("mscorlib") ||
                baseTypeAsmName.StartsWith("System") ||
                baseTypeAsmName.StartsWith("Microsoft") ||
                baseTypeAsmName.StartsWith("Mono"))
            {
                // We can safely skip types known not to have [Inject] bindings, i.e. types
                // from the BCL, etc.
                BaseTypeKey = null;
            }
            else
            {
                // Otherwise, base types might have [Inject] properties that we'll need
                // to account for.
                BaseTypeKey = Weaver.EnqueueBaseTypeBinding(baseType)
                    ? CompilerKeys.ForType(baseType)
                    : null;
            }
        }
Beispiel #5
0
        private IDictionary <string, Binding> ProcessCompleteModule(
            ModuleGenerator moduleGenerator,
            bool ignoreCompletenessErrors)
        {
            var bindings   = new Dictionary <string, Binding>(StringComparer.Ordinal);
            var overrides  = new Dictionary <string, Binding>(StringComparer.Ordinal);
            var allModules = new Dictionary <string, ModuleGenerator>(StringComparer.Ordinal);
            var hasError   = false;

            GatherIncludedModules(moduleGenerator, allModules, new Stack <string>());

            var resolver = new Resolver(null, loader, errors =>
            {
                if (ignoreCompletenessErrors)
                {
                    return;
                }

                hasError = true;
                foreach (var e in errors)
                {
                    errorReporter.LogError(e);
                }
            });

            foreach (var module in allModules.Values)
            {
                // Request entry-point bindings
                var addTo = module.IsOverride ? overrides : bindings;

                foreach (var injectType in module.Injects)
                {
                    var key = injectType.Resolve().IsInterface
                                  ? CompilerKeys.ForType(injectType)
                                  : CompilerKeys.GetMemberKey(injectType);

                    resolver.RequestBinding(key, module.ModuleType.FullName, false, true);
                }

                foreach (var providerGenerator in module.ProviderGenerators)
                {
                    var binding = new CompilerProvidesBinding(providerGenerator);

                    if (addTo.ContainsKey(binding.ProviderKey))
                    {
                        var message  = "Duplicate bindings for {0} in {1}{2}.";
                        var addendum = module.IsOverride ? "overriding module " : string.Empty;

                        throw new ValidationException(string.Format
                                                          (message, binding.ProviderKey, addendum, module.ModuleType.FullName));
                    }

                    switch (providerGenerator.ProvidesType)
                    {
                    case ProvidesType.Default:
                        addTo.Add(binding.ProviderKey, binding);
                        break;

                    case ProvidesType.Set:
                        var setKey = CompilerKeys.GetSetKey(binding.ProviderKey);
                        CompilerSetBinding.Add(addTo, setKey, binding);
                        break;

                    default:
                        throw new ArgumentException("Unknown ProvidesType value: " + providerGenerator.ProvidesType);
                    }
                }
            }

            resolver.InstallBindings(bindings);
            resolver.InstallBindings(overrides);
            var allBindings = resolver.ResolveAllBindings();

            return(!hasError ? allBindings : null);
        }