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;
            }
Esempio n. 4
0
        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));
        }
Esempio n. 6
0
        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);
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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);
                }
            }
        }