public ProviderMethodBindingGenerator( ModuleDefinition moduleDefinition, References references, TypeReference moduleType, MethodDefinition providerMethod, bool isLibrary) : base(moduleDefinition, references) { this.providerMethod = providerMethod; this.moduleType = moduleType; this.isLibrary = isLibrary; var name = ProviderMethod.GetNamedAttributeName(); key = CompilerKeys.ForType(ProviderMethod.ReturnType, name); var attr = providerMethod.CustomAttributes.First(Attributes.IsProvidesAttribute); if (attr.HasConstructorArguments) { var providesTypeArg = attr.ConstructorArguments.Single(); ProvidesType = (ProvidesType)providesTypeArg.Value; } else { ProvidesType = ProvidesType.Default; } }
private InjectMemberInfo(string key, TypeReference type) { this.key = key; this.type = type; lazyKey = CompilerKeys.GetLazyKey(key); providerKey = CompilerKeys.GetProviderKey(key); }
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 ProviderMethodBindingGenerator( ModuleDefinition moduleDefinition, References references, TypeDefinition moduleType, MethodDefinition providerMethod, bool isLibrary) : base(moduleDefinition, references) { this.providerMethod = Conditions.CheckNotNull(providerMethod, "providerMethod"); this.moduleType = Conditions.CheckNotNull(moduleType, "moduleType"); this.isLibrary = isLibrary; var name = ProviderMethod.GetNamedAttributeName(); key = CompilerKeys.ForType(ProviderMethod.ReturnType, name); }
public override void Validate(IErrorReporter errorReporter) { ParamKeys = new List <string>(); foreach (var param in ProviderMethod.Parameters) { ParamKeys.Add(CompilerKeys.ForParam(param)); } if (ProviderMethod.HasGenericParameters) { errorReporter.LogError("Provider methods cannot be generic: " + ProviderMethod.FullName); } if (ProviderMethod.IsStatic) { errorReporter.LogError("Provider methods cannot be static: " + ProviderMethod.FullName); } if (ProviderMethod.MethodReturnType.ReturnType.Name == "Lazy`1") { errorReporter.LogError("Provider methods cannot return System.Lazy<T> directly: " + ProviderMethod.FullName); } if (ProviderMethod.ReturnType.Name == "IProvider`1") { errorReporter.LogError("Provider methods cannot return IProvider<T> directly: " + ProviderMethod.FullName); } if (ProviderMethod.IsPrivate) { errorReporter.LogError("Provider methods cannot be private: " + ProviderMethod.FullName); } if (ProviderMethod.IsAbstract) { errorReporter.LogError("Provider methods cannot be abstract: " + ProviderMethod.FullName); } }
public override TypeDefinition Generate(IErrorReporter errorReporter) { Conditions.CheckNotNull(RuntimeModuleType, "RuntimeModuleType"); var providerType = new TypeDefinition( RuntimeModuleType.Namespace, "ProviderBinding_" + RuntimeModuleType.NestedTypes.Count, TypeAttributes.NestedPublic, References.Binding); providerType.CustomAttributes.Add(new CustomAttribute(References.CompilerGeneratedAttribute)); providerType.DeclaringType = RuntimeModuleType; IsSingleton = ProviderMethod.CustomAttributes.Any(Attributes.IsSingletonAttribute); var moduleField = new FieldDefinition("module", FieldAttributes.Private, ModuleType); providerType.Fields.Add(moduleField); var parameters = new List <ParameterDefinition>(); var fields = new List <FieldDefinition>(); foreach (var param in ProviderMethod.Parameters) { var field = new FieldDefinition(param.Name, FieldAttributes.Private, References.Binding); providerType.Fields.Add(field); parameters.Add(param); fields.Add(field); ParamKeys.Add(CompilerKeys.ForParam(param)); } EmitCtor(providerType, moduleField); EmitResolve(providerType, parameters, fields); EmitGetDependencies(providerType, fields); EmitGet(providerType, moduleField, parameters, fields); RuntimeModuleType.NestedTypes.Add(providerType); return(providerType); }
public void ValidateCompleteness(ISet <string> injectableKeys, IErrorReporter errorReporter) { if (!IsComplete) { return; } foreach (var method in baseProvidesMethods) { foreach (var param in method.Parameters) { var name = param.Name; var key = CompilerKeys.ForParam(param); if (!injectableKeys.Contains(key)) { const string msg = "{0}: Module is a complete module but has an unsatisfied dependency on {1}{2}"; var nameDescr = name == null ? string.Empty : "[Named(\"" + name + "\")] "; errorReporter.LogError(string.Format(msg, moduleType.FullName, nameDescr, param.ParameterType.FullName)); } } } }
public InjectMemberInfo(PropertyDefinition property) : this(CompilerKeys.ForProperty(property), property.PropertyType) { memberName = property.FullName; }
public InjectMemberInfo(ParameterDefinition param) : this(CompilerKeys.ForParam(param), param.ParameterType) { memberName = param.Name; }
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); }
public override void Validate(IErrorReporter errorReporter) { if (moduleType.BaseType != null && moduleType.BaseType.FullName != References.Object.FullName) { errorReporter.LogError(moduleType.FullName + ": Modules must inherit from System.Object only."); } if (moduleType.IsAbstract) { errorReporter.LogError(moduleType.FullName + ": Modules cannot be abstract."); } moduleCtor = moduleType.GetConstructors().FirstOrDefault(m => m.Parameters.Count == 0); if (moduleCtor == null) { errorReporter.LogError(moduleType.FullName + " is marked as a [Module], but no default constructor is visible."); } ProvidedKeys = new HashSet <string>(StringComparer.Ordinal); foreach (var method in baseProvidesMethods) { var name = method.GetNamedAttributeName(); var key = CompilerKeys.ForType(method.ReturnType, name); if (!ProvidedKeys.Add(key)) { errorReporter.LogError(moduleType.FullName + ": Duplicate provider key for method " + moduleType.FullName + "." + method.Name); } } if (IsComplete) { foreach (var method in baseProvidesMethods) { foreach (var param in method.Parameters) { var name = param.GetNamedAttributeName(); var key = CompilerKeys.ForType(param.ParameterType, name); if (!ProvidedKeys.Contains(key)) { const string msg = "{0}: Module is a complete module but has an unsatisfied dependency on {1}{2}"; var nameDescr = name == null ? string.Empty : "[Named(\"" + name + "\")] "; errorReporter.LogError(string.Format(msg, moduleType.FullName, nameDescr, param.ParameterType.FullName)); } } } } switch (moduleType.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(moduleType.FullName + ": This type is private, and will be loaded reflectively. Consider making it internal or public."); break; } foreach (var gen in ProviderGenerators) { gen.Validate(errorReporter); } }
private void EmitGetBindings(TypeDefinition runtimeModule) { /** * public override void GetBindings(Dictionary<string, Binding> bindings) * { * var module = this.Module; * bindings.Add("keyof binding0", new ProviderBinding0(module)); * ... * bindings.Add("keyof bindingN", new ProviderBindingN(module)); * } */ var getBindings = new MethodDefinition( "GetBindings", MethodAttributes.Public | MethodAttributes.Virtual, References.Void); var vModule = new VariableDefinition("module", importedModuleType); getBindings.Body.Variables.Add(vModule); getBindings.Body.InitLocals = true; getBindings.Parameters.Add(new ParameterDefinition(References.DictionaryOfStringToBinding)); var il = getBindings.Body.GetILProcessor(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Callvirt, References.RuntimeModule_ModuleGetter); il.Emit(OpCodes.Castclass, importedModuleType); il.Emit(OpCodes.Stloc, vModule); foreach (var binding in ProviderGenerators) { switch (binding.ProvidesType) { case ProvidesType.Default: il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldstr, binding.Key); il.Emit(OpCodes.Ldloc, vModule); il.Emit(OpCodes.Newobj, binding.GeneratedCtor); il.Emit(OpCodes.Callvirt, References.DictionaryOfStringToBinding_Add); break; case ProvidesType.Set: var addMethodRef = new GenericInstanceMethod(References.SetBindings_AddOfT); addMethodRef.GenericArguments.Add(binding.ProviderMethod.ReturnType); il.Emit(OpCodes.Ldarg_1); il.Emit(OpCodes.Ldstr, CompilerKeys.GetSetKey(binding.Key)); il.Emit(OpCodes.Ldloc, vModule); il.Emit(OpCodes.Newobj, binding.GeneratedCtor); il.Emit(OpCodes.Call, addMethodRef); break; default: throw new InvalidOperationException("Unknown ProvidesType value: " + binding.ProvidesType); } } il.Emit(OpCodes.Ret); runtimeModule.Methods.Add(getBindings); }