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); }
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; }
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; } }
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; } }
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); }