static bool ShouldProcess(ICompiledAssembly compiledAssembly) { if (!compiledAssembly.RequiresCodegen()) { return(false); } var assemblyName = compiledAssembly.Name; if (assemblyName == CodeGenUtils.ExternalPropertyBagAssemblyName) { return(false); } // TODO: Debug type load exception and other assembly-specific issues if (k_IgnoredAssemblies.Contains(assemblyName)) { return(false); } if (RuntimeSerializationSettingsUtils.GetAssemblyExceptions().Contains(assemblyName)) { return(false); } if (CodeGenUtils.IsTestAssembly(compiledAssembly)) { return(false); } return(true); }
public override void OnActivate(string searchContext, VisualElement rootElement) { base.OnActivate(searchContext, rootElement); RuntimeSerializationSettingsUtils.ClearExceptionCache(); m_AssemblyRows.Clear(); ReflectionUtils.ForEachAssembly(assembly => { if (CodeGenUtils.IsTestAssembly(assembly)) { return; } if (k_IgnoredAssemblies.Contains(assembly.GetName().Name)) { return; } var assemblyRow = new AssemblyRow(assembly); if (assemblyRow.GetTypeCount() > 0) { m_AssemblyRows.Add(assemblyRow); } }); m_AssemblyRows.Sort((a, b) => a.DisplayName.CompareTo(b.DisplayName)); }
public AssemblyRow(Assembly assembly) { FullName = assembly.FullName; DisplayName = $"Assembly: {assembly.GetName().Name}"; foreach (var type in assembly.GetTypes()) { if (type.IsAbstract || type.IsInterface) { continue; } if (type.IsGenericType) { continue; } if (!typeof(Component).IsAssignableFrom(type)) { #if INCLUDE_ALL_SERIALIZABLE_CONTAINERS if (!CodeGenUtils.IsSerializableContainer(type)) #endif continue; } var typeName = type.FullName; if (string.IsNullOrEmpty(typeName)) { continue; } var typeNamespace = type.Namespace; var group = m_RootNamespaceGroup; if (!string.IsNullOrEmpty(typeNamespace)) { var namespaceParts = typeNamespace.Split('.'); foreach (var part in namespaceParts) { var lastGroup = group; if (!group.Children.TryGetValue(part, out group)) { group = new NamespaceGroup(); lastGroup.Children.Add(part, group); } } } var typeRow = new TypeRow(type); var types = group.Types; types.Add(typeRow); } m_RootNamespaceGroup.PostProcessRecursively(); m_GetAllNamespaces = GetAllNamespaces; m_GetAllTypes = GetAllTypes; m_RemoveAllNamespaces = RemoveAllNamespaces; m_RemoveAllTypes = RemoveAllTypes; }
static ILPostProcessResult GeneratePropertyBags(AssemblyDefinition compiledAssembly, string[] defines) { var context = new Context(compiledAssembly.MainModule, defines); // TODO: collection pools var fields = new List <FieldInfo>(); var properties = new List <PropertyInfo>(); #if UNITY_2020_2_OR_NEWER var editorAssemblyPath = Assembly.GetAssembly(typeof(EditorApplication)).Location; var editorPath = editorAssemblyPath.Substring(0, editorAssemblyPath.Length - k_EditorAssemblyPathSuffix); #else var editorPath = EditorApplication.applicationContentsPath; #endif var serializableContainerTypes = new HashSet <Type>(); var assemblyExceptions = RuntimeSerializationSettingsUtils.GetAssemblyExceptions(); var namespaceExceptions = RuntimeSerializationSettingsUtils.GetNamespaceExceptions(); var typeExceptions = RuntimeSerializationSettingsUtils.GetTypeExceptions(); ReflectionUtils.ForEachAssembly(assembly => { Console.WriteLine($"Process assembly {assembly.FullName}"); if (assembly.IsDynamic) { return; } if (!CodeGenUtils.IsBuiltInAssembly(assembly, editorPath)) { return; } if (assemblyExceptions.Contains(assembly.FullName)) { return; } PostProcessAssembly(namespaceExceptions, typeExceptions, assembly, fields, properties, serializableContainerTypes); }); serializableContainerTypes.ExceptWith(k_IgnoredTypes); if (serializableContainerTypes.Count == 0) { return(null); } GeneratePropertyBagsForSerializableTypes(context, serializableContainerTypes); return(CreatePostProcessResult(compiledAssembly)); }
static ILPostProcessResult ProcessAssembly(AssemblyDefinition compiledAssembly) { var module = compiledAssembly.MainModule; var componentTypes = new List <TypeContainer>(); #if UNITY_2020_2_OR_NEWER var editorAssemblyPath = Assembly.GetAssembly(typeof(EditorApplication)).Location; var editorPath = editorAssemblyPath.Substring(0, editorAssemblyPath.Length - k_EditorAssemblyPathSuffix); #else var editorPath = EditorApplication.applicationContentsPath; #endif var assemblyExceptions = RuntimeSerializationSettingsUtils.GetAssemblyExceptions(); var namespaceExceptions = RuntimeSerializationSettingsUtils.GetNamespaceExceptions(); var typeExceptions = RuntimeSerializationSettingsUtils.GetTypeExceptions(); ReflectionUtils.ForEachAssembly(assembly => { if (assembly.IsDynamic) { return; } if (!CodeGenUtils.IsBuiltInAssembly(assembly, editorPath) && !k_PlayerAssemblies.Contains(assembly.GetName().Name)) { return; } if (assemblyExceptions.Contains(assembly.FullName)) { return; } PostProcessAssembly(namespaceExceptions, typeExceptions, module, assembly, componentTypes); }); PostProcessGenericMethodWrapper(componentTypes, module); return(CreatePostProcessResult(compiledAssembly)); }
static void PostProcessProperty(PropertyInfo property, HashSet <string> includedProperties, HashSet <string> ignoredProperties, HashSet <Type> serializableContainerTypes) { var propertyType = property.PropertyType; if (serializableContainerTypes.Contains(propertyType)) { return; } var propertyName = property.Name; var includeField = includedProperties != null && includedProperties.Contains(propertyName); if (!includeField) { if (ignoredProperties != null && ignoredProperties.Contains(propertyName)) { return; } if (property.GetGetMethod(true) == null) { return; } var setMethod = property.GetSetMethod(true); if (setMethod == null) { return; } var isValidProperty = false; foreach (var attribute in property.CustomAttributes) { var attributeType = attribute.AttributeType; if (attributeType == k_NativePropertyAttributeType) { isValidProperty = true; break; } if (attributeType == k_NativeNameAttributeType) { isValidProperty = true; break; } } // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags if ((setMethod.MethodImplementationFlags & MethodImplAttributes.InternalCall) != 0) { isValidProperty = true; } if (!isValidProperty) { return; } } if (propertyType.IsArray) { propertyType = propertyType.GetElementType(); } else if (ReflectedPropertyBagUtils.IsListType(propertyType)) { propertyType = propertyType.GenericTypeArguments[0]; } if (!CodeGenUtils.IsSerializableContainer(propertyType)) { return; } serializableContainerTypes.Add(propertyType); }
static void PostProcessField(FieldInfo field, HashSet <string> includedProperties, HashSet <string> ignoredProperties, HashSet <Type> serializableContainerTypes) { var fieldType = field.FieldType; if (serializableContainerTypes.Contains(fieldType)) { return; } var fieldName = field.Name; var includeField = includedProperties != null && includedProperties.Contains(fieldName); if (!includeField) { if (ignoredProperties != null && ignoredProperties.Contains(fieldName)) { return; } if (!field.IsPublic) { var isValidField = false; foreach (var attribute in field.GetCustomAttributes()) { var attributeType = attribute.GetType(); if (attributeType == k_NativeNameAttributeType || attributeType == typeof(SerializableAttribute)) { isValidField = true; } if (attributeType == k_IgnoreAttributeType) { isValidField = false; break; } } if (!isValidField) { return; } } } if (fieldType.IsArray) { fieldType = fieldType.GetElementType(); } else if (ReflectedPropertyBagUtils.IsListType(fieldType)) { fieldType = fieldType.GenericTypeArguments[0]; } if (fieldType == null || fieldType.IsGenericParameter || fieldType.IsGenericType) { return; } if (!CodeGenUtils.IsSerializableContainer(fieldType)) { return; } serializableContainerTypes.Add(fieldType); }
static TypeDefinition GeneratePropertyBag(Context context, TypeReference containerType, MethodReference createValueMethod, MethodReference createArrayMethod, MethodReference createListMethod, TypeReference unityObjectReference, TypeReference unityObjectListReference) { var propertyBagType = PropertyBag.GeneratePropertyBagHeader(context, containerType, out var ctorMethod, out var addPropertyMethod); var ctorMethodBody = ctorMethod.Body; var il = ctorMethodBody.GetILProcessor(); var baseCtorCall = ctorMethodBody.Instructions.Last(); foreach (var(member, nameOverride) in CodeGenUtils.GetPropertyMembers(containerType.Resolve())) { if (CodeGenUtils.TryGenerateUnityObjectProperty(context, containerType, null, member, il, addPropertyMethod, createValueMethod, createArrayMethod, createListMethod, unityObjectReference, unityObjectListReference)) { continue; } var memberType = context.ImportReference(Utility.GetMemberType(member).ResolveGenericParameter(containerType)); if (memberType.IsGenericInstance || memberType.IsArray) { PropertyBag.RegisterCollectionTypes(context, containerType, memberType, il); } TypeDefinition propertyType; // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (member.IsPublic()) { propertyType = Property.Generate(context, containerType, member, nameOverride); } else { #if !NET_DOTS propertyType = ReflectedProperty.Generate(context, containerType, member, nameOverride); #else throw new Exception("Private properties require reflection which is not supported in NET_DOTS."); #endif } propertyBagType.NestedTypes.Add(propertyType); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Newobj, propertyType.GetConstructors().First()); il.Emit(OpCodes.Call, context.Module.ImportReference(addPropertyMethod.MakeGenericInstanceMethod(memberType))); } il.Emit(OpCodes.Ret); var nop = il.Create(OpCodes.Nop); var ret = il.Create(OpCodes.Ret); var leave = il.Create(OpCodes.Leave, ret); il.InsertAfter(ctorMethodBody.Instructions.Last(), nop); il.InsertAfter(nop, leave); il.InsertAfter(leave, ret); var handler = new ExceptionHandler(ExceptionHandlerType.Catch) { TryStart = baseCtorCall.Next, TryEnd = nop, HandlerStart = nop, HandlerEnd = ret, CatchType = context.Module.ImportReference(typeof(Exception)) }; ctorMethodBody.ExceptionHandlers.Add(handler); return(propertyBagType); }
static TypeDefinition GeneratePropertyBag(Context context, TypeReference containerType, TypeDefinition externalContainer, Dictionary <string, TypeDefinition> externalContainerTypes, MethodReference getTypeMethod, MethodReference createValueMethod, MethodReference createArrayMethod, MethodReference createListMethod, TypeReference unityObjectReference, TypeReference unityObjectListReference, TypeReference listType) { var effectiveContainerType = externalContainer ?? containerType; var propertyBagType = PropertyBag.GeneratePropertyBagHeader(context, effectiveContainerType, out var ctorMethod, out var addPropertyMethod); var il = ctorMethod.Body.GetILProcessor(); foreach (var(member, nameOverride) in CodeGenUtils.GetPropertyMembers(containerType.Resolve())) { if (CodeGenUtils.TryGenerateUnityObjectProperty(context, containerType, externalContainer, member, il, addPropertyMethod, createValueMethod, createArrayMethod, createListMethod, unityObjectReference, unityObjectListReference)) { continue; } var memberType = context.ImportReference(Utility.GetMemberType(member).ResolveGenericParameter(containerType)); TypeReference externalMember; if (memberType.IsArray) { externalContainerTypes.TryGetValue(memberType.GetElementType().FullName, out var externalMemberDefinition); externalMember = externalMemberDefinition?.MakeArrayType(); } else if (CodeGenUtils.IsListType(memberType, out var genericInstance)) { externalContainerTypes.TryGetValue(genericInstance.GenericArguments[0].FullName, out var externalMemberDefinition); externalMember = externalMemberDefinition == null ? null : listType.MakeGenericInstanceType(externalMemberDefinition); } else { externalContainerTypes.TryGetValue(memberType.FullName, out var externalMemberDefinition); externalMember = externalMemberDefinition; } var effectiveMemberType = externalMember ?? memberType; if (memberType.IsGenericInstance || memberType.IsArray) { PropertyBag.RegisterCollectionTypes(context, effectiveContainerType, effectiveMemberType, il); } TypeDefinition propertyType; if (externalMember != null || externalContainer != null) { propertyType = ReflectedExternalProperty.Generate(context, containerType, externalContainer, member, externalMember, getTypeMethod, nameOverride); } else if (member.IsPublicOrAssembly()) { propertyType = Property.Generate(context, containerType, member, nameOverride); } else { #if !NET_DOTS propertyType = ReflectedProperty.Generate(context, containerType, member, nameOverride); #else throw new Exception("Private properties require reflection which is not supported in NET_DOTS."); #endif } propertyBagType.NestedTypes.Add(propertyType); il.Emit(OpCodes.Ldarg_0); // this il.Emit(OpCodes.Newobj, propertyType.GetConstructors().First()); il.Emit(OpCodes.Call, context.Module.ImportReference(addPropertyMethod.MakeGenericInstanceMethod(effectiveMemberType))); } il.Emit(OpCodes.Ret); return(propertyBagType); }
static void PostProcessType(TypeDefinition type, HashSet <TypeDefinition> serializableTypes) { if (type.HasGenericParameters && !type.IsGenericInstance) { return; } foreach (var(member, _) in CodeGenUtils.GetPropertyMembers(type)) { var memberType = Utility.GetMemberType(member).ResolveGenericParameter(type); var resolvedMemberType = memberType.Resolve(); if (resolvedMemberType == null) { Console.Error.WriteLine($"Couldn't resolve {memberType}"); continue; } if (memberType.IsArray) { resolvedMemberType = resolvedMemberType.GetElementType().Resolve(); } else if (CodeGenUtils.IsListType(memberType, out var genericInstance)) { resolvedMemberType = genericInstance.GenericArguments[0].Resolve(); } else { resolvedMemberType = resolvedMemberType.Resolve(); } if (resolvedMemberType.HasGenericParameters && !resolvedMemberType.IsGenericInstance) { continue; } var(hasSkipGenerationAttribute, hasCompilerGeneratedAttribute) = CodeGenUtils.GetSerializationAttributes(resolvedMemberType); if (hasSkipGenerationAttribute || hasCompilerGeneratedAttribute) { continue; } // Skip UnityObjectTypes because we will be using UnityObjectReferenceProperty if (CodeGenUtils.IsAssignableToUnityObject(resolvedMemberType)) { continue; } if (!CodeGenUtils.IsSerializableContainer(resolvedMemberType)) { if (!resolvedMemberType.IsValueType || CodeGenUtils.TypeIsPrimitive(resolvedMemberType, resolvedMemberType.FullName)) { continue; } } if (serializableTypes.Add(resolvedMemberType)) { PostProcessType(resolvedMemberType, serializableTypes); } } }
static void PostProcessAssembly(AssemblyDefinition assembly, HashSet <TypeDefinition> serializableTypes) { var namespaceExceptions = RuntimeSerializationSettingsUtils.GetNamespaceExceptions(); var typeExceptions = RuntimeSerializationSettingsUtils.GetTypeExceptions(); foreach (var module in assembly.Modules) { foreach (var type in module.GetTypes()) { if (type.IsAbstract || type.IsInterface) { continue; } if (type.HasGenericParameters && !type.IsGenericInstance) { continue; } var(hasSkipGenerationAttribute, hasCompilerGeneratedAttribute) = CodeGenUtils.GetSerializationAttributes(type); if (hasSkipGenerationAttribute || hasCompilerGeneratedAttribute) { continue; } if (!CodeGenUtils.IsAssignableToComponent(type)) { #if INCLUDE_ALL_SERIALIZABLE_CONTAINERS if (!CodeGenUtils.IsSerializableContainer(type)) #endif continue; } var typeName = type.FullName; if (string.IsNullOrEmpty(typeName)) { continue; } if (typeExceptions.Contains(typeName)) { continue; } var partOfNamespaceException = false; var typeNamespace = type.Namespace; if (!string.IsNullOrEmpty(typeNamespace)) { foreach (var exception in namespaceExceptions) { if (typeNamespace.Contains(exception)) { partOfNamespaceException = true; break; } } } if (partOfNamespaceException) { continue; } serializableTypes.Add(type); PostProcessType(type, serializableTypes); } } }