using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; namespace Robust.Shared.Utility { internal sealed class SpecificPropertyInfo : AbstractFieldInfo { public override string Name { get; } public readonly PropertyInfo PropertyInfo; internal override MemberInfo MemberInfo => PropertyInfo; public override Type FieldType => PropertyInfo.PropertyType; public override Type? DeclaringType => PropertyInfo.DeclaringType; public SpecificPropertyInfo(PropertyInfo propertyInfo) { Name = propertyInfo.Name; PropertyInfo = propertyInfo; } public override object? GetValue(object? obj) => PropertyInfo.GetValue(obj); public override void SetValue(object? obj, object? value) => PropertyInfo.SetValue(obj, value); public override T? GetAttribute(bool includeBacking = false) where T : class { if (includeBacking && TryGetBackingField(out var backing)) { return PropertyInfo.GetCustomAttribute() ?? backing.GetAttribute(includeBacking); } return PropertyInfo.GetCustomAttribute(includeBacking); } public override IEnumerable GetAttributes(bool includeBacking = false) { foreach (var attribute in PropertyInfo.GetCustomAttributes()) { yield return attribute; } if (includeBacking && TryGetBackingField(out var backing)) { foreach (var attribute in backing.GetAttributes(includeBacking)) { yield return attribute; } } } public override bool HasAttribute(bool includeBacking = false) { if (includeBacking && TryGetBackingField(out var backing)) { return PropertyInfo.HasCustomAttribute() || backing.HasAttribute(includeBacking); } return PropertyInfo.HasCustomAttribute(); } public override bool TryGetAttribute([NotNullWhen(true)] out T? attribute, bool includeBacking = false) where T : class { return (attribute = GetAttribute(includeBacking)) != null; } public override bool IsBackingField() { return false; } public override bool HasBackingField() { return DeclaringType?.HasBackingField(Name) ?? false; } public override SpecificFieldInfo? GetBackingField() { return DeclaringType?.GetBackingField(Name); } public override bool TryGetBackingField([NotNullWhen(true)] out SpecificFieldInfo? field) { return (field = GetBackingField()) != null; } public bool IsMostOverridden(Type type) { if (DeclaringType == type) { return true; } var setBase = PropertyInfo.SetMethod?.GetBaseDefinition(); var getBase = PropertyInfo.GetMethod?.GetBaseDefinition(); var currentType = type; var relevantProperties = type.GetAllProperties().Where(p => p.Name == PropertyInfo.Name).ToList(); while (currentType != null) { foreach (var property in relevantProperties) { if(property.DeclaringType != currentType) continue; if (setBase != null && setBase == property.SetMethod?.GetBaseDefinition()) { return property == PropertyInfo; } if (getBase != null && getBase == property.GetMethod?.GetBaseDefinition()) { return property == PropertyInfo; } } currentType = currentType.BaseType; } return false; } public static implicit operator PropertyInfo(SpecificPropertyInfo f) => f.PropertyInfo; public static explicit operator SpecificPropertyInfo(PropertyInfo f) => new(f); public override string? ToString() { return PropertyInfo.ToString(); } } }