Skip to content

Commit

Permalink
SAVEPOINT
Browse files Browse the repository at this point in the history
  • Loading branch information
dennisdoomen committed Oct 20, 2024
1 parent a8e7f17 commit 94d2740
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 128 deletions.
5 changes: 4 additions & 1 deletion Build/_build.csproj.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
Expand All @@ -21,4 +23,5 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
3 changes: 3 additions & 0 deletions FluentAssertions.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@
<s:String x:Key="/Default/CodeStyle/CSharpVarKeywordUsage/ForSimpleTypes/@EntryValue">UseExplicitType</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=4a98fdf6_002D7d98_002D4f5a_002Dafeb_002Dea44ad98c70c/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;Kind Name="READONLY_FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/UserRules/=f9fce829_002De6f4_002D4cb2_002D80f1_002D5497c44f51df/@EntryIndexedValue">&lt;Policy&gt;&lt;Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static fields (private)"&gt;&lt;ElementKinds&gt;&lt;Kind Name="FIELD" /&gt;&lt;/ElementKinds&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FCONSTRUCTOR/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
Expand Down Expand Up @@ -154,6 +156,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/Environment/UnitTesting/MsTestProvider/RunConfigurationFilename/@EntryValue">D:\Workspaces\FluentAssertions\Default.testsettings</s:String>
<s:Int64 x:Key="/Default/Environment/UnitTesting/ParallelProcessesCount/@EntryValue">4</s:Int64>
<s:Boolean x:Key="/Default/Environment/UnitTesting/ShadowCopy/@EntryValue">False</s:Boolean>
Expand Down
187 changes: 63 additions & 124 deletions Src/FluentAssertions/Common/TypeMemberReflector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,149 +21,88 @@ public TypeMemberReflector(Type typeToReflect, MemberVisibility visibility)
Members = Properties.Concat<MemberInfo>(Fields).ToArray();
}

public MemberInfo[] Members { get; }

public PropertyInfo[] Properties { get; }

public FieldInfo[] Fields { get; }

private static PropertyInfo[] LoadProperties(Type typeToReflect, MemberVisibility visibility)
private PropertyInfo[] LoadProperties(Type typeToReflect, Enum visibility)
{
List<PropertyInfo> query = GetPropertiesFromHierarchy(typeToReflect, visibility);

return query.ToArray();
}

private static List<PropertyInfo> GetPropertiesFromHierarchy(Type typeToReflect, MemberVisibility memberVisibility)
public static PropertyInfo[] GetProperties2(this Type type, MemberVisibility visibility)
{
bool includeInternal = memberVisibility.HasFlag(MemberVisibility.Internal);
bool includeExplicitlyImplemented = memberVisibility.HasFlag(MemberVisibility.ExplicitlyImplemented);
var collectedProperties = new HashSet<string>();
var properties = new List<PropertyInfo>();

return GetMembersFromHierarchy(typeToReflect, type =>
// Start with the given type and iterate up the inheritance chain
while (type != null && type != typeof(object))
{
return
from p in type.GetProperties(AllInstanceMembersFlag | BindingFlags.DeclaredOnly)
where p.GetMethod is { } getMethod
&& (IsPublic(getMethod) || (includeExplicitlyImplemented && IsExplicitlyImplemented(getMethod)))
&& (includeInternal || !IsInternal(getMethod))
&& !p.IsIndexer()
orderby IsExplicitImplementation(p)
select p;
});
}

private static bool IsPublic(MethodBase getMethod) =>
!getMethod.IsPrivate && !getMethod.IsFamily && !getMethod.IsFamilyAndAssembly;

private static bool IsExplicitlyImplemented(MethodBase getMethod) =>
getMethod.IsPrivate && getMethod.IsFinal;

private static bool IsInternal(MethodBase getMethod) =>
getMethod.IsAssembly || getMethod.IsFamilyOrAssembly;

private static bool IsExplicitImplementation(PropertyInfo property)
{
return property.GetMethod!.IsPrivate &&
property.SetMethod?.IsPrivate != false &&
property.Name.Contains('.', StringComparison.Ordinal);
}
// Add all properties declared in the current type (including new ones)
PropertyInfo[] allProperties = type.GetProperties(
BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic);

private static FieldInfo[] LoadFields(Type typeToReflect, MemberVisibility visibility)
{
List<FieldInfo> query = GetFieldsFromHierarchy(typeToReflect, visibility);

return query.ToArray();
}

private static List<FieldInfo> GetFieldsFromHierarchy(Type typeToReflect, MemberVisibility memberVisibility)
{
bool includeInternal = memberVisibility.HasFlag(MemberVisibility.Internal);

return GetMembersFromHierarchy(typeToReflect, type =>
{
return type
.GetFields(AllInstanceMembersFlag)
.Where(field => IsPublic(field))
.Where(field => includeInternal || !IsInternal(field));
});
}

private static bool IsPublic(FieldInfo field) =>
!field.IsPrivate && !field.IsFamily && !field.IsFamilyAndAssembly;

private static bool IsInternal(FieldInfo field)
{
return field.IsAssembly || field.IsFamilyOrAssembly;
}

private static List<TMemberInfo> GetMembersFromHierarchy<TMemberInfo>(
Type typeToReflect,
Func<Type, IEnumerable<TMemberInfo>> getMembers)
where TMemberInfo : MemberInfo
{
if (typeToReflect.IsInterface)
{
return GetInterfaceMembers(typeToReflect, getMembers);
}

return GetClassMembers(typeToReflect, getMembers);
}

private static List<TMemberInfo> GetInterfaceMembers<TMemberInfo>(Type typeToReflect,
Func<Type, IEnumerable<TMemberInfo>> getMembers)
where TMemberInfo : MemberInfo
{
List<TMemberInfo> members = new();

var considered = new List<Type>();
var queue = new Queue<Type>();
considered.Add(typeToReflect);
queue.Enqueue(typeToReflect);

while (queue.Count > 0)
{
Type subType = queue.Dequeue();

foreach (Type subInterface in subType.GetInterfaces())
if (visibility.HasFlag(MemberVisibility.Public) || visibility.HasFlag(MemberVisibility.Internal) ||
visibility.HasFlag(MemberVisibility.ExplicitlyImplemented))
{
if (considered.Contains(subInterface))
foreach (var prop in allProperties)
{
continue;
if (!collectedProperties.Contains(prop.Name) && !IsExplicitlyImplemented(prop) && HasVisibility(visibility, prop))
{
properties.Add(prop);
collectedProperties.Add(prop.Name);
}
}
}

considered.Add(subInterface);
queue.Enqueue(subInterface);
if (visibility.HasFlag(MemberVisibility.ExplicitlyImplemented))
{
foreach (var prop in allProperties)
{
if (IsExplicitlyImplemented(prop))
{
var name = prop.Name.Split('.').Last();
if (!collectedProperties.Contains(name))
{
properties.Add(prop);
collectedProperties.Add(name);
}
}
}
}

IEnumerable<TMemberInfo> typeMembers = getMembers(subType);
if (visibility.HasFlag(MemberVisibility.DefaultInterfaceProperties))
{
// Add explicitly implemented interface properties (not included above)
var interfaces = type.GetInterfaces();

IEnumerable<TMemberInfo> newPropertyInfos = typeMembers.Where(x => !members.Contains(x));
foreach (var iface in interfaces)
{
foreach (var prop in iface.GetProperties())
{
if (!collectedProperties.Contains(prop.Name) && !prop.GetMethod!.IsAbstract)
{
properties.Add(prop);
collectedProperties.Add(prop.Name);
}
}
}
}

members.InsertRange(0, newPropertyInfos);
// Move to the base type
type = type.BaseType;
}

return members;
return properties.ToArray();
}

private static List<TMemberInfo> GetClassMembers<TMemberInfo>(Type typeToReflect,
Func<Type, IEnumerable<TMemberInfo>> getMembers)
where TMemberInfo : MemberInfo
private static bool IsExplicitlyImplemented(PropertyInfo prop)
{
List<TMemberInfo> members = new();
return prop.Name.Contains('.', StringComparison.InvariantCultureIgnoreCase);
}

while (typeToReflect != null)
{
foreach (var memberInfo in getMembers(typeToReflect))
{
if (members.TrueForAll(mi => mi.Name != memberInfo.Name))
{
members.Add(memberInfo);
}
}
private static bool HasVisibility(MemberVisibility visibility, PropertyInfo prop) =>
(visibility.HasFlag(MemberVisibility.Public) && prop.GetMethod?.IsPublic is true) ||
(visibility.HasFlag(MemberVisibility.Internal) && prop.GetMethod?.IsAssembly is true);
throw new NotImplementedException();
}

typeToReflect = typeToReflect.BaseType;
}
public MemberInfo[] Members { get; }

return members;
}
public PropertyInfo[] Properties { get; }

public FieldInfo[] Fields { get; }
}
3 changes: 2 additions & 1 deletion Src/FluentAssertions/Equivalency/MemberVisibility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public enum MemberVisibility
None = 0,
Internal = 1,
Public = 2,
ExplicitlyImplemented = 4
ExplicitlyImplemented = 4,
DefaultInterfaceProperties = 8
}
Loading

0 comments on commit 94d2740

Please sign in to comment.