protected virtual void ValidateCompositeTypeModel(CompositeValidationResult result, CompositeModel compositeModel) { // TODO validate that none of fragments have abstract non-composite methods. if (compositeModel.PublicTypes.Any()) { Type firstType = compositeModel.PublicTypes.First(); Type[] gArgs = firstType.GetGenericArguments(); Int32 gArgsCount = gArgs.Length; foreach (Type cType in compositeModel.GetAllCompositeTypes()) { this.ValidateCompositeType(result, compositeModel, cType); } foreach (Type fType in compositeModel.GetAllFragmentTypes()) { this.ValidateFragmentType(result, compositeModel, fType); } foreach (Type type in compositeModel.PublicTypes) { this.ValidateCompositeType(result, compositeModel, type); Type[] typeGargs = type.GetGenericArguments(); Int32 typeCount = typeGargs.Length; if (typeCount > 0) { if (type.IsGenericTypeDefinition() != firstType.IsGenericTypeDefinition() || typeGargs.Take(Math.Min(gArgsCount, typeCount)).Where((tGArg, idx) => tGArg.IsGenericParameter != gArgs[idx].IsGenericParameter).Any()) { result.StructureValidationErrors.Add(ValidationErrorFactory.NewStructureError("All type interfaces must be either genericless, generic type definitions, or having all generic parameters closed.", compositeModel)); } else { // TODO generic arguments constraints } } } if (compositeModel.PublicTypes.Count(pType => !pType #if WINDOWS_PHONE_APP .GetTypeInfo() #endif .IsInterface) > 1) { result.StructureValidationErrors.Add(ValidationErrorFactory.NewStructureError("Composite types must contain at most one class, but found the following classes:\n" + String.Join(", ", compositeModel.PublicTypes.Select(pType => !pType #if WINDOWS_PHONE_APP .GetTypeInfo() #endif .IsInterface)), compositeModel)); } } else { result.StructureValidationErrors.Add(ValidationErrorFactory.NewStructureError("Composite must have at least one public type", compositeModel)); } }
protected virtual void ValidateFragmentType(CompositeValidationResult result, CompositeModel compositeModel, Type fragmentType) { if (!fragmentType #if WINDOWS_PHONE_APP .GetTypeInfo() #endif .IsClass) { result.StructureValidationErrors.Add(ValidationErrorFactory.NewStructureError("Fragments must be classes; the fragment " + fragmentType + " however is not a class.", compositeModel)); } else { var baseTypes = new HashSet <Type>(fragmentType.GetAllParentTypes()); baseTypes.Remove(fragmentType); if (fragmentType #if WINDOWS_PHONE_APP .GetTypeInfo() #endif .IsAbstract) { foreach (var fMethod in fragmentType.GetAllInstanceMethods()) { if (fMethod.IsAbstract && !compositeModel.Methods.Any(cMethod => AreSameFragmentMethods(fMethod, ReflectionHelper.FindMethodImplicitlyImplementingMethod(fragmentType, cMethod.NativeInfo)))) { result.StructureValidationErrors.Add(ValidationErrorFactory.NewStructureError("Found abstract method " + fMethod + " in " + fragmentType + ", with no corresponding composite method.", compositeModel)); } } } foreach (var baseType in baseTypes) { if (baseType.IsGenericType()) { var baseTypeGDef = baseType.GetGenericTypeDefinition(); if (compositeModel.GetAllCompositeTypes().Except(compositeModel.PublicTypes).SelectMany(cType => cType.GetAllParentTypes()).Any(pType => pType.GetGenericDefinitionIfGenericType().Equals(baseTypeGDef)) && baseType.GetGenericArguments().Any(gArg => gArg.IsArray || gArg.IsByRef || gArg.IsPointer)) { result.StructureValidationErrors.Add(ValidationErrorFactory.NewStructureError("Fragment type implements composite type with either array, by ref or pointer generic argument. This is not allowed, as fragment might not be instantiatable in cases of non-array or non-by-ref or non-pointer generic argument of composite type.", compositeModel)); } } } } }
public PublicCompositeTypeGenerationResultImpl( CompositeModel cModel, CompositeTypeModel tModel, EventHandler <AssemblyLoadingArgs> loadingEvt, IDictionary <Assembly, Assembly> assDic, CompositeCodeGenerationInfo codeGenerationInfo ) { //var orderer = new TypeLoadOrderer( cModel ); var collectionsFactory = cModel.ApplicationModel.CollectionsFactory; var publicTypes = cModel .GetAllCompositeTypes() .Concat(cModel.GetAllFragmentTypes()) //.OrderBy( t => t, orderer ) .Where(t => cModel.ApplicationModel.AffectedAssemblies.Contains(t.GetAssembly())) .OrderBy(t => t.Equals(cModel.MainCodeGenerationType) ? 0 : 1) // Populate main code generation type first .Select(t => GetGeneratedPublicType(t, cModel, codeGenerationInfo, loadingEvt, assDic)) .Distinct() .ToArray(); var mainTypes = publicTypes.Where(iResult => iResult.IsPublicTypeMainCompositeType()); if (!mainTypes.Any() || mainTypes.Skip(1).Any()) { throw new ArgumentException((mainTypes.Any() ? "Too many" : "Too little") + " generated main types (" + String.Join(", ", mainTypes) + "), exactly one allowed."); } var mainType = mainTypes.First(); this._compositeFactory = (CompositeFactory)mainType.GetAssembly().GetType(mainType.Name + codeGenerationInfo.CompositeFactorySuffix, true) #if WINDOWS_PHONE_APP .GetAllInstanceConstructors().First() #else .GetConstructors()[0] #endif .Invoke(null); var fragmentTypeGenerationResults = tModel.FragmentTypeInfos.Keys //.OrderBy( t => t, orderer ) .Select(t => Tuple.Create(t, GetParticipantType(t, cModel, codeGenerationInfo, loadingEvt, assDic, codeGenerationInfo.FragmentPrefix, true))) .Where(t => t.Item2 != null) .Select(t => (FragmentTypeGenerationResult) new FragmentTypeGenerationResultImpl(t.Item1, t.Item2)) .ToArray(); var concernInvocationGenerationResults = tModel.ConcernInvocationTypeInfos.Keys //.OrderBy( t => t, orderer ) .Select(t => Tuple.Create(t, GetParticipantType(t, cModel, codeGenerationInfo, loadingEvt, assDic, codeGenerationInfo.ConcernInvocationPrefix))) .Where(t => t.Item2 != null) .Select(t => (TypeGenerationResult) new TypeGenerationResultImpl(t.Item2, t.Item1)) .ToArray(); var sideEffectInvocationGenerationResults = tModel.SideEffectInvocationTypeInfos.Keys //.OrderBy( t => t, orderer ) .Select(t => Tuple.Create(t, GetParticipantType(t, cModel, codeGenerationInfo, loadingEvt, assDic, codeGenerationInfo.SideEffectInvocationPrefix))) .Where(t => t.Item2 != null) .Select(t => (TypeGenerationResult) new TypeGenerationResultImpl(t.Item2, t.Item1)) .ToArray(); var privateCompositeGenerationresults = tModel.PrivateCompositeTypeInfos.Keys //.OrderBy( t => t, orderer ) .Select(t => Tuple.Create(t, GetParticipantType(t, cModel, codeGenerationInfo, loadingEvt, assDic, codeGenerationInfo.PrivateCompositePrefix))) .Where(t => t.Item2 != null) .Select(t => (TypeGenerationResult) new TypeGenerationResultImpl(t.Item2, t.Item1)) .ToArray(); var pGArgs = collectionsFactory.NewDictionaryProxy( tModel.PublicCompositeGenericArguments .Select((gArg, idx) => Tuple.Create(gArg, idx)) .GroupBy(tuple => tuple.Item1.DeclaringType) .ToDictionary(grouping => grouping.Key, grouping => collectionsFactory.NewListProxy(grouping.Select(tuple => tuple.Item2).ToList()).CQ)); this._generatedPublicMainType = mainType; this._maxParamCountForCtors = mainType #if WINDOWS_PHONE_APP .GetAllInstanceConstructors().First() #else .GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0] #endif .GetParameters().Length; this._generatedPublicTypes = collectionsFactory.NewListProxy(publicTypes.Select( pt => (GeneratedTypeInfo) new GeneratedTypeInfoImpl(pt)) .ToList()).CQ; this._publicCompositeGenericArguments = pGArgs.CQ; this._privateCompositeGenerationResults = collectionsFactory.NewListProxyFromParams(privateCompositeGenerationresults).CQ; this._fragmentGenerationResults = collectionsFactory.NewListProxyFromParams(fragmentTypeGenerationResults).CQ; this._concernInvocationGenerationResults = collectionsFactory.NewListProxyFromParams(concernInvocationGenerationResults).CQ; this._sideEffectInvocationGenerationResults = collectionsFactory.NewListProxyFromParams(sideEffectInvocationGenerationResults).CQ; // Remember to remove Qi4CS assembly if present assDic.Remove(ReflectionHelper.QI4CS_ASSEMBLY); }