예제 #1
0
        private static void ValidateInternal(object obj, object contextObject, bool recursive, ref List <IValidationError> validationErrors, HashSet <object> validatedObjects = null)
        {
            if (obj == null)
            {
                return;
            }

            if (validatedObjects != null)
            {
                if (validatedObjects.Contains(obj))
                {
                    return;
                }

                validatedObjects.Add(obj);
            }

            Type objectType = obj.GetType();

            var whitelistedNamespaces = ValidatorWhitelistedNamespaceProvider.GetWhitelistedNamespaces();

            // if whitelisted asset exists - use whitelisting instead of blacklisting
            if (whitelistedNamespaces.Count > 0)
            {
                int ignoredNamespacesCount = ValidatorIgnoredNamespaceProvider.GetIgnoredNamespaces().Count;
                if (ignoredNamespacesCount > 0)
                {
                    Debug.LogWarning("Both ValidatorIgnoredNamespace + ValidatorWhitelistedNamespace exist in project (mutually exclusive) - will only use whitelisted!");
                }

                if (string.IsNullOrEmpty(objectType.Namespace))
                {
                    // No namespace means no validation in whitelist format
                    return;
                }

                foreach (var whitelistedNamespace in whitelistedNamespaces)
                {
                    if (!objectType.Namespace.Contains(whitelistedNamespace.Namespace))
                    {
                        return;
                    }
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(objectType.Namespace))
                {
                    // allow user defined ignores for namespaces
                    foreach (var validatorIgnoredNamespace in ValidatorIgnoredNamespaceProvider.GetIgnoredNamespaces())
                    {
                        if (validatorIgnoredNamespace == null)
                        {
                            Debug.LogWarning("Bad state - validatorIgnoredNamespace is null!");
                            continue;
                        }

                        if (objectType.Namespace.Contains(validatorIgnoredNamespace.Namespace))
                        {
                            return;
                        }
                    }
                }
            }

            foreach (FieldInfo fieldInfo in TypeUtil.GetInspectorFields(objectType)
                     .Where(f => typeof(UnityEventBase).IsAssignableFrom(f.FieldType))
                     .Where(f => !Attribute.IsDefined(f, typeof(OptionalAttribute)) && !Attribute.IsDefined(f, typeof(HideInInspector))))
            {
                // NOTE (darren): check UnityEvents for all classes
                UnityEventBase unityEvent = (UnityEventBase)fieldInfo.GetValue(obj);
                if (unityEvent == null)
                {
                    Debug.LogError("Unexpected null UnityEvent in GameObjectValidator!");
                    continue;
                }

                for (int i = 0; i < unityEvent.GetPersistentEventCount(); i++)
                {
                    MethodInfo methodInfo = unityEvent.GetMethodInfoForIndex(i);
                    if (methodInfo == null)
                    {
                        validationErrors = validationErrors ?? new List <IValidationError>();
                        validationErrors.Add(ValidationErrorFactory.Create(obj, objectType, fieldInfo, contextObject));
                        break;
                    }
                }
            }

            bool whitelisted = ValidatorUnityWhitelist.IsTypeWhitelisted(objectType);

            if (kUnityAssemblies.Contains(objectType.Assembly) && !whitelisted)
            {
                return;
            }

            IEnumerable <MemberInfo> membersToCheck = null;

            if (whitelisted)
            {
                membersToCheck = ValidatorUnityWhitelist.GetWhitelistedMembersFor(objectType);
            }
            else
            {
                membersToCheck = TypeUtil.GetInspectorFields(objectType)
                                 .Where(f => !ValidatorBlacklistedClassProvider.GetBlacklistedClasses().Any(b => b.Class == f.DeclaringType.Name))
                                 .Where(f => !Attribute.IsDefined(f, typeof(OptionalAttribute)) && !Attribute.IsDefined(f, typeof(HideInInspector)))
                                 .Where(f => !kUnityAssemblies.Contains(f.DeclaringType.Assembly)).Cast <MemberInfo>();                               // NOTE (darren): this is to ignore fields that declared in super-classes out of our control (Unity)
            }

            foreach (MemberInfo memberInfo in membersToCheck)
            {
                IEnumerable <Predicate <object> > predicates = ValidatorPredicates.GetOptionalPredicatesFor(memberInfo);
                if (predicates != null)
                {
                    bool shouldValidate = predicates.All(p => p.Invoke(obj));
                    if (!shouldValidate)
                    {
                        continue;
                    }
                }

                IList <UnityEngine.Object> unityEngineObjects = GetUnityEngineObjects(memberInfo, obj);
                // TODO (darren): don't alloc memory for List<> if not necessary
                if (unityEngineObjects == null || unityEngineObjects.Count <= 0)
                {
                    // NOTE (darren): if this is not a UnityEngine.Object
                    // we might still have to recursively look through its fields
                    // which might contain UnityEngine.Objects
                    if (recursive)
                    {
                        IList <object> memberObjects = GetMemberObjects(memberInfo, obj);
                        foreach (object memberObj in memberObjects)
                        {
                            // NOTE (darren): the LocalId is broken here because we lost
                            // a reference to the original GameObject being validated
                            // (as contextObject may be the scene for example).
                            // Leaving this as-is as it's an edge case and nice-to-have.
                            ValidateInternal(memberObj, contextObject, recursive, ref validationErrors, validatedObjects);
                        }
                    }
                    continue;
                }

                int index = 0;
                foreach (UnityEngine.Object memberObject in unityEngineObjects)
                {
                    if (memberObject == null)
                    {
                        validationErrors = validationErrors ?? new List <IValidationError>();
                        if (unityEngineObjects.Count > 1)
                        {
                            validationErrors.Add(ValidationErrorFactory.Create(obj, objectType, memberInfo, contextObject, index));
                        }
                        else
                        {
                            validationErrors.Add(ValidationErrorFactory.Create(obj, objectType, memberInfo, contextObject));
                        }
                        index++;
                        continue;
                    }

                    if (recursive)
                    {
                        GameObject memberObjectAsGameObject = memberObject as GameObject;
                        if (memberObjectAsGameObject != null)
                        {
                            PrefabType prefabType = PrefabUtility.GetPrefabType(memberObjectAsGameObject);
                            if (prefabType == PrefabType.Prefab)
                            {
                                // switch context to the prefab we just recursed to
                                object newContextObject = memberObjectAsGameObject;

                                validatedObjects = validatedObjects ?? new HashSet <object>()
                                {
                                    obj
                                };
                                ValidateGameObjectInternal(memberObjectAsGameObject, newContextObject, recursive, ref validationErrors, validatedObjects);
                            }
                        }

                        ScriptableObject memberObjectAsScriptableObject = memberObject as ScriptableObject;
                        if (memberObjectAsScriptableObject != null)
                        {
                            // switch context to the scriptable object we just recursed to
                            object newContextObject = memberObjectAsScriptableObject;

                            validatedObjects = validatedObjects ?? new HashSet <object>()
                            {
                                obj
                            };
                            ValidateInternal(memberObjectAsScriptableObject, newContextObject, recursive, ref validationErrors, validatedObjects);
                        }
                    }
                    index++;
                }
            }
        }
예제 #2
0
        private static bool IsIgnored(object obj, object contextObject)
        {
            if (obj == null)
            {
                return(true);
            }

            // Skip user defined ignored asset paths:
            var ignoredAssetPaths = ValidatorIgnoredAssetPathProvider.GetIgnoredAssetPaths();

            if (ignoredAssetPaths.Count > 0)
            {
                UnityEngine.Object unityContextObject = contextObject as UnityEngine.Object;
                if (unityContextObject != null)
                {
                    string assetPath = AssetDatabase.GetAssetPath(unityContextObject);
                    if (!string.IsNullOrEmpty(assetPath))
                    {
                        if (ignoredAssetPaths.Any(ignoredAssetPath => assetPath.StartsWith(ignoredAssetPath.Path)))
                        {
                            return(true);
                        }
                    }
                }
            }

            Type objectType = obj.GetType();

            var whitelistedNamespaces = ValidatorWhitelistedNamespaceProvider.GetWhitelistedNamespaces();

            // if whitelisted asset exists - use whitelisting instead of blacklisting
            if (whitelistedNamespaces.Count > 0)
            {
                int ignoredNamespacesCount = ValidatorIgnoredNamespaceProvider.GetIgnoredNamespaces().Count;
                if (ignoredNamespacesCount > 0)
                {
                    Debug.LogWarning("Both ValidatorIgnoredNamespace + ValidatorWhitelistedNamespace exist in project (mutually exclusive) - will only use whitelisted!");
                }

                if (string.IsNullOrEmpty(objectType.Namespace))
                {
                    // No namespace means no validation in whitelist format
                    return(true);
                }

                if (!whitelistedNamespaces.Any(whitelistedNamespace => objectType.Namespace.Contains(whitelistedNamespace.Namespace)))
                {
                    // It is not allowed to skip basic UnityEngine objects, such as GameObject, because the validation
                    // always starts with one of those.
                    if (objectType.Namespace != typeof(GameObject).Namespace)
                    {
                        return(true);
                    }
                }
            }
            else
            {
                if (!string.IsNullOrEmpty(objectType.Namespace))
                {
                    // allow user defined ignores for namespaces
                    foreach (var validatorIgnoredNamespace in ValidatorIgnoredNamespaceProvider.GetIgnoredNamespaces())
                    {
                        if (validatorIgnoredNamespace == null)
                        {
                            Debug.LogWarning("Bad state - validatorIgnoredNamespace is null!");
                            continue;
                        }

                        if (objectType.Namespace.Contains(validatorIgnoredNamespace.Namespace))
                        {
                            // It is not allowed to skip basic UnityEngine objects, such as GameObject, because the
                            // validation always starts with one of those.
                            if (objectType.Namespace == typeof(GameObject).Namespace)
                            {
                                Debug.LogWarning($"Bad state - Cannot ignore namespace '{typeof(GameObject).Namespace}'");
                                continue;
                            }
                            else
                            {
                                return(true);
                            }
                        }
                    }
                }
            }

            return(false);
        }