public bool CheckFieldForUnityImplicits([NotNull] IField field, [NotNull] IPsiModule module) { ITypeElement containingType = field.GetContainingType(); if (containingType == null) { return(false); } bool serializable = containingType.HasAttributeInstance(new ClrTypeName("System.SerializableAttribute"), true); bool unityObject = containingType.GetSuperTypes().Any(t => IsUnityImplicitType(t, module)); if (!serializable && !unityObject) { return(false); } if (field.GetAccessRights() == AccessRights.PUBLIC) { return(true); } foreach (KeyValuePair <string, string> pair in m_unitySettings.UnityUsageAttributes.EnumIndexedValues()) { bool hasAtttribute = field.HasAttributeInstance(new ClrTypeName(pair.Value), true); if (hasAtttribute) { return(true); } } return(false); }
// NOTE: This method assumes that the type is not a descendant of UnityEngine.Object! private bool IsSerializableType([CanBeNull] ITypeElement type, [NotNull] IProject project, bool isTypeUsage, bool hasSerializeReference = false) { if (!(type is IStruct || type is IClass)) { return(false); } if (isTypeUsage) { // Type usage (e.g. field declaration) is stricter. Means it must be a concrete type with no type // parameters, unless the type usage is for [SerializeReference], which allows abstract types if (type is IModifiersOwner modifiersOwner && modifiersOwner.IsAbstract && !hasSerializeReference) { return(false); } // Unity 2020.1 allows fields to have generic types. It's currently undocumented, but there are no // limitations on the number of type parameters, or even nested type parameters. The base type needs to // be serializable, but type parameters don't (if a non-serializable type parameter is used as a field, // it just isn't serialised). // https://blogs.unity3d.com/2020/03/17/unity-2020-1-beta-is-now-available-for-feedback/ var unityVersion = myUnityVersion.GetActualVersion(project); if (unityVersion < new Version(2020, 1) && type is ITypeParametersOwner typeParametersOwner && typeParametersOwner.TypeParameters.Count > 0) { return(false); } } if (type is IClass @class && @class.IsStaticClass()) { return(false); } // System.Dictionary is special cased and excluded. We can see this in UnitySerializationLogic.cs in the // reference source repo. It also excludes anything with a full name beginning "System.", which includes // "System.Version" (which is marked [Serializable]). However, it doesn't exclude string, int, etc. // TODO: Rewrite this whole section to properly mimic UnitySerializationLogic.cs var name = type.GetClrName(); if (Equals(name, KnownTypes.SystemVersion) || Equals(name, PredefinedType.GENERIC_DICTIONARY_FQN)) { return(false); } using (CompilationContextCookie.GetExplicitUniversalContextIfNotSet()) return(type.HasAttributeInstance(PredefinedType.SERIALIZABLE_ATTRIBUTE_CLASS, true)); }
// NOTE: This method assumes that the type is not a descendant of UnityEngine.Object! private bool IsSerializableType([CanBeNull] ITypeElement type, [NotNull] IProject project, bool isTypeUsage) { if (!(type is IStruct || type is IClass)) { return(false); } if (isTypeUsage) { // Type usage (e.g. field declaration) is stricter. Means it must be a concrete type with no type // parameters if (type is IModifiersOwner modifiersOwner && modifiersOwner.IsAbstract) { return(false); } // Unity 2020.1 allows fields to have generic types. It's currently undocumented, but there are no // limitations on the number of type parameters, or even nested type parameters. The base type needs to // be serializable, but type parameters don't (if a non-serializable type parameter is used as a field, // it just isn't serialised). // https://blogs.unity3d.com/2020/03/17/unity-2020-1-beta-is-now-available-for-feedback/ var unityVersion = myUnityVersion.GetActualVersion(project); if (unityVersion < new Version(2020, 1) && type is ITypeParametersOwner typeParametersOwner && typeParametersOwner.TypeParameters.Count > 0) { return(false); } } if (type is IClass @class && @class.IsStaticClass()) { return(false); } // System.Version seems to be special cased. In Mono, it's marked as [Serializable], but in netstandard, // it's not. Which means that depending on what runtime you're using, you could potentially get different // fields serialised. However, it never shows up in Inspector, so it's a good indication that it's handled // specially. if (Equals(type.GetClrName(), KnownTypes.SystemVersion)) { return(false); } return(type.HasAttributeInstance(PredefinedType.SERIALIZABLE_ATTRIBUTE_CLASS, true)); }
private static bool IsTestFixture(ITypeElement typeElement) { if (!(typeElement is IClass) && !(typeElement is IStruct)) { return(false); } if (typeElement.AllTypeParameters.Any()) { return(false); // type should be concrete } var modifiersOwner = (IModifiersOwner)typeElement; if (modifiersOwner.IsAbstract || modifiersOwner.GetAccessRights() == AccessRights.INTERNAL) { return(false); } if (typeElement.HasAttributeInstance(TestFixtureAttribute, false)) { return(true); } var @class = typeElement as IClass; if (@class != null) { var visited = new HashSet <IClass>(); while ((@class = @class.GetSuperClass()) != null) { if (visited.Contains(@class)) { break; } visited.Add(@class); if (@class.HasAttributeInstance(TestFixtureAttribute, false)) { return(true); } } } return(false); }
public bool IsSerializableType([CanBeNull] ITypeElement type) { // A class or struct with the `[System.Serializable]` attribute // Should not be abstract, static or generic // We'll ignore abstract or generic because it might be being used as a base class // TODO: Add a warning if the serializable class isn't inherited var clazz = type as IClass; if (clazz?.IsStaticClass() == true) { return(false); } if (type?.IsClassLike() == true) { return(type.HasAttributeInstance(PredefinedType.SERIALIZABLE_ATTRIBUTE_CLASS, true)); } return(false); }
public static bool IsZoneClass(ITypeElement typeElement) { return(typeElement.HasAttributeInstance(new ClrTypeName(ZoneAttributeNameFull), false)); }