Skip to content

Commit

Permalink
Fix a crash when trying to get an ImmediateType on a type with redefi…
Browse files Browse the repository at this point in the history
…ned properties (new) with a property type different from initial property type.

Fix #2.
  • Loading branch information
KeRNeLith committed Sep 2, 2020
1 parent 042a738 commit 5be1660
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 8 deletions.
42 changes: 37 additions & 5 deletions src/ImmediateReflection/ImmediateProperties.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,28 @@ private void Init([NotNull, ItemNotNull] IEnumerable<PropertyInfo> properties)
foreach (PropertyInfo property in Where(properties, IsNotIndexed))
#endif
{
_properties.Add(
property.Name,
var currentImmediateProperty =
#if SUPPORTS_CACHING
CachesHandler.Instance.GetProperty(property));
CachesHandler.Instance.GetProperty(property);
#else
new ImmediateProperty(property));
new ImmediateProperty(property);
#endif

if (_properties.TryGetValue(property.Name, out ImmediateProperty immediateProperty))
{
// Keep the property from the most derived type
if (ShouldReplacePropertyWith(immediateProperty, currentImmediateProperty))
{
_properties[property.Name] = currentImmediateProperty;
}
}
else
{
_properties.Add(property.Name, currentImmediateProperty);
}
}

#region Local function
#region Local functions

bool IsNotIndexed(PropertyInfo property)
{
Expand All @@ -78,6 +90,26 @@ bool IsNotIndexed(PropertyInfo property)
return !IsIndexed(property);
}

bool ShouldReplacePropertyWith(ImmediateProperty property1, ImmediateProperty property2)
{
Debug.Assert(property1 != null);
Debug.Assert(property2 != null);

Type initialType = property1.DeclaringType;
Type currentType = property2.DeclaringType;
while (currentType != null)
{
// If property2 is a property of a derived object of property1 declaring type
// => Prefer derived property
if (initialType == currentType)
return true;

currentType = currentType.BaseType;
}

return false;
}

#endregion
}

Expand Down
27 changes: 27 additions & 0 deletions tests/ImmediateReflection.Tests/ImmediatePropertiesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ public void ImmediatePropertiesInfo()
immediateProperties3);
}

[Test]
public void ImmediatePropertiesInfoWithNew()
{
var immediateProperties = new ImmediateProperties(new[] { ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo, BaseClassPublicGetPropertyPropertyInfo });
CollectionAssert.AreEquivalent(
new[] { new ImmediateProperty(ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo) },
immediateProperties);

immediateProperties = new ImmediateProperties(new[] { BaseClassPublicGetPropertyPropertyInfo, ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo });
CollectionAssert.AreEquivalent(
new[] { new ImmediateProperty(ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo) },
immediateProperties);
}

[Test]
public void GetProperty()
{
Expand All @@ -50,6 +64,19 @@ public void GetProperty()
// ReSharper restore InconsistentNaming
}

[Test]
public void GetPropertyWithNew()
{
var immediateProperties = new ImmediateProperties(new[] { ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo, BaseClassPublicGetPropertyPropertyInfo });
var expectedProperty = new ImmediateProperty(ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo);
Assert.AreEqual(expectedProperty, immediateProperties[nameof(ChildTypeRedefinitionTestClass.Property)]);
Assert.AreEqual(expectedProperty, immediateProperties.GetProperty(nameof(ChildTypeRedefinitionTestClass.Property)));

immediateProperties = new ImmediateProperties(new[] { BaseClassPublicGetPropertyPropertyInfo, ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo });
Assert.AreEqual(expectedProperty, immediateProperties[nameof(ChildTypeRedefinitionTestClass.Property)]);
Assert.AreEqual(expectedProperty, immediateProperties.GetProperty(nameof(ChildTypeRedefinitionTestClass.Property)));
}

#region Equals/HashCode/ToString

[Test]
Expand Down
10 changes: 7 additions & 3 deletions tests/ImmediateReflection.Tests/ImmediatePropertyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,9 +416,13 @@ private static IEnumerable<TestCaseData> CreateImmediatePropertyGetValueTestCase
var baseObject = new BaseTestClass();
yield return new TestCaseData(baseObject, BaseClassPublicGetPropertyPropertyInfo, "Parent");

var childObject = new ChildTestClass();
yield return new TestCaseData(childObject, ChildClassPublicGetPropertyPropertyInfo, "Child");
yield return new TestCaseData(childObject, BaseClassPublicGetPropertyPropertyInfo, "Parent");
var childObject1 = new ChildTestClass();
yield return new TestCaseData(childObject1, ChildClassPublicGetPropertyPropertyInfo, "Child");
yield return new TestCaseData(childObject1, BaseClassPublicGetPropertyPropertyInfo, "Parent");

var childObject2 = new ChildTypeRedefinitionTestClass();
yield return new TestCaseData(childObject2, ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo, 12);
yield return new TestCaseData(childObject2, BaseClassPublicGetPropertyPropertyInfo, "Parent");

#endregion

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,13 @@ public static TypeClassifiedMembers GetForInternalObjectTypeTestObject()
protected static readonly PropertyInfo ChildClassPublicGetPropertyPropertyInfo =
typeof(ChildTestClass).GetProperty(nameof(ChildTestClass.Property)) ?? throw new AssertionException("Cannot find property.");

[NotNull]
protected static readonly PropertyInfo ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo =
typeof(ChildTypeRedefinitionTestClass).GetProperty(
nameof(ChildTypeRedefinitionTestClass.Property),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
?? throw new AssertionException("Cannot find property.");

#endregion

#region Item & indexed property
Expand Down
19 changes: 19 additions & 0 deletions tests/ImmediateReflection.Tests/ImmediateTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ public void ImmediateTypeNewKeyword()
},
immediateType.Properties.Select(property => property.PropertyInfo));

// Case same type redefinition
immediateType = new ImmediateType(typeof(ChildTestClass));
Assert.AreEqual(typeof(ChildTestClass), immediateType.Type);
Assert.AreEqual(nameof(ChildTestClass), immediateType.Name);
Expand All @@ -534,6 +535,24 @@ public void ImmediateTypeNewKeyword()
ChildClassPublicGetPropertyPropertyInfo
},
immediateType.Properties.Select(property => property.PropertyInfo));

// Case different type definition
immediateType = new ImmediateType(typeof(ChildTypeRedefinitionTestClass));
Assert.AreEqual(typeof(ChildTypeRedefinitionTestClass), immediateType.Type);
Assert.AreEqual(nameof(ChildTypeRedefinitionTestClass), immediateType.Name);
Assert.AreEqual(
$"{nameof(ImmediateReflection)}.{nameof(Tests)}.{nameof(ChildTypeRedefinitionTestClass)}",
immediateType.FullName);
CollectionAssert.AreEquivalent(
Enumerable.Empty<FieldInfo>(),
immediateType.Fields.Select(field => field.FieldInfo));
CollectionAssert.AreEquivalent(
new[]
{
ChildTypeRedefinitionClassPublicGetPropertyPropertyInfo
},
immediateType.Properties.Select(property => property.PropertyInfo));

}

[Test]
Expand Down
5 changes: 5 additions & 0 deletions tests/ImmediateReflection.Tests/TestTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,11 @@ public class ChildTestClass : BaseTestClass
public new string Property { get; } = "Child";
}

public class ChildTypeRedefinitionTestClass : BaseTestClass
{
public new int Property { get; set; } = 12;
}

public class BaseItemTestClass
{
public string Item { get; }
Expand Down

0 comments on commit 5be1660

Please sign in to comment.