[tests] Improve cecil-tests's member filtering API. (#17001)

* Improve these methods to find members inside nested types as well.
* Simplify their implementation somewhat.
* Make the filter method optional to allow enumerating everything.
* Rename these methods to Enumerate* to better express what they do.
* Make them extension methods on AssemblyDefinition to make them more
  discoverable and easier to use.
This commit is contained in:
Rolf Bjarne Kvinge 2022-12-13 17:09:45 +01:00 коммит произвёл GitHub
Родитель b8f15a0656
Коммит e3f549fc7e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 74 добавлений и 81 удалений

Просмотреть файл

@ -44,13 +44,13 @@ namespace Cecil.Tests {
var assembly = info.Assembly;
HashSet<string> found = new HashSet<string> ();
foreach (var prop in Helper.FilterProperties (assembly, a => HasAnyAvailabilityAttribute (a))) {
foreach (var prop in assembly.EnumerateProperties (a => HasAnyAvailabilityAttribute (a))) {
CheckAllPlatformsOnParent (prop, prop.FullName, prop.DeclaringType, found);
}
foreach (var meth in Helper.FilterMethods (assembly, a => HasAnyAvailabilityAttribute (a))) {
foreach (var meth in assembly.EnumerateMethods (a => HasAnyAvailabilityAttribute (a))) {
CheckAllPlatformsOnParent (meth, meth.FullName, meth.DeclaringType, found);
}
foreach (var field in Helper.FilterFields (assembly, a => HasAnyAvailabilityAttribute (a))) {
foreach (var field in assembly.EnumerateFields (a => HasAnyAvailabilityAttribute (a))) {
CheckAllPlatformsOnParent (field, field.FullName, field.DeclaringType, found);
}
Assert.That (found, Is.Empty, $"{found.Count} issues found");
@ -87,7 +87,7 @@ namespace Cecil.Tests {
{
var assembly = info.Assembly;
var doubleAttributed = new List<string> ();
foreach (var type in Helper.FilterTypes (assembly, a => HasAnyAvailabilityAttribute (a))) {
foreach (var type in assembly.EnumerateTypes (a => HasAnyAvailabilityAttribute (a))) {
var platformCount = new Dictionary<string, int> ();
foreach (var attribute in type.CustomAttributes.Where (a => IsAvailabilityAttribute (a))) {
var kind = FindAvailabilityKind (attribute);
@ -511,16 +511,16 @@ namespace Cecil.Tests {
string platformName = AssemblyToAttributeName (assembly);
HashSet<string> found = new HashSet<string> ();
foreach (var type in Helper.FilterTypes (assembly, a => HasAnyAvailabilityAttribute (a))) {
foreach (var type in assembly.EnumerateTypes (a => HasAnyAvailabilityAttribute (a))) {
CheckCurrentPlatformIncludedIfAny (type, platformName, type.FullName, type.DeclaringType, found);
}
foreach (var prop in Helper.FilterProperties (assembly, a => HasAnyAvailabilityAttribute (a))) {
foreach (var prop in assembly.EnumerateProperties (a => HasAnyAvailabilityAttribute (a))) {
CheckCurrentPlatformIncludedIfAny (prop, platformName, prop.FullName, prop.DeclaringType, found);
}
foreach (var meth in Helper.FilterMethods (assembly, a => HasAnyAvailabilityAttribute (a))) {
foreach (var meth in assembly.EnumerateMethods (a => HasAnyAvailabilityAttribute (a))) {
CheckCurrentPlatformIncludedIfAny (meth, platformName, meth.FullName, meth.DeclaringType, found);
}
foreach (var field in Helper.FilterFields (assembly, a => HasAnyAvailabilityAttribute (a))) {
foreach (var field in assembly.EnumerateFields (a => HasAnyAvailabilityAttribute (a))) {
CheckCurrentPlatformIncludedIfAny (field, platformName, field.FullName, field.DeclaringType, found);
}
Assert.That (found, Is.Empty, $"{found.Count} issues found");

Просмотреть файл

@ -197,7 +197,7 @@ namespace Cecil.Tests {
IEnumerable<MethodDefinition> AllPInvokes (AssemblyDefinition assembly)
{
return Helper.FilterMethods (assembly, method =>
return assembly.EnumerateMethods (method =>
(method.Attributes & MethodAttributes.PInvokeImpl) != 0);
}

Просмотреть файл

@ -133,7 +133,7 @@ namespace Cecil.Tests {
IEnumerable<MethodDefinition> AllPInvokes (AssemblyDefinition assembly)
{
return Helper.FilterMethods (assembly, method =>
return assembly.EnumerateMethods (method =>
(method.Attributes & MethodAttributes.PInvokeImpl) != 0);
}
@ -148,7 +148,7 @@ namespace Cecil.Tests {
IEnumerable<MethodDefinition> AllSetupBlocks (AssemblyDefinition assembly)
{
return Helper.FilterMethods (assembly, method => {
return assembly.EnumerateMethods (method => {
if (!method.HasBody)
return false;
return method.Body.Instructions.Any (IsCallToSetupBlockUnsafe);

Просмотреть файл

@ -15,7 +15,7 @@ using Xamarin.Utils;
namespace Cecil.Tests {
public class Helper {
public static class Helper {
static Dictionary<string, AssemblyDefinition> cache = new Dictionary<string, AssemblyDefinition> ();
@ -39,99 +39,92 @@ namespace Cecil.Tests {
return ad;
}
public static IEnumerable<MethodDefinition> FilterMethods (AssemblyDefinition assembly, Func<MethodDefinition, bool>? filter)
// Enumerates all the methods in the assembly, for all types (including nested types), potentially providing a custom filter function.
public static IEnumerable<MethodDefinition> EnumerateMethods (this AssemblyDefinition assembly, Func<MethodDefinition, bool>? filter = null)
{
foreach (var module in assembly.Modules) {
foreach (var type in module.Types) {
foreach (var method in FilterMethods (type, filter))
yield return method;
}
}
yield break;
}
foreach (var type in EnumerateTypes (assembly)) {
if (!type.HasMethods)
continue;
static IEnumerable<MethodDefinition> FilterMethods (TypeDefinition type, Func<MethodDefinition, bool>? filter)
{
if (type.HasMethods) {
foreach (var method in type.Methods) {
if ((filter == null) || filter (method))
if (filter is null || filter (method))
yield return method;
}
}
if (type.HasNestedTypes) {
foreach (var nested in type.NestedTypes) {
foreach (var method in FilterMethods (nested, filter))
yield return method;
}
}
yield break;
}
public static IEnumerable<PropertyDefinition> FilterProperties (AssemblyDefinition assembly, Func<PropertyDefinition, bool>? filter)
// Enumerates all the properties in the assembly, for all types (including nested types), potentially providing a custom filter function.
public static IEnumerable<PropertyDefinition> EnumerateProperties (this AssemblyDefinition assembly, Func<PropertyDefinition, bool>? filter = null)
{
foreach (var module in assembly.Modules) {
foreach (var type in module.Types) {
foreach (var property in FilterProperties (type, filter))
yield return property;
}
}
yield break;
}
foreach (var type in EnumerateTypes (assembly)) {
if (!type.HasProperties)
continue;
static IEnumerable<PropertyDefinition> FilterProperties (TypeDefinition type, Func<PropertyDefinition, bool>? filter)
{
if (type.HasProperties) {
foreach (var property in type.Properties) {
if ((filter is null) || filter (property))
if (filter is null || filter (property))
yield return property;
}
}
if (type.HasNestedTypes) {
foreach (var nested in type.NestedTypes) {
foreach (var property in FilterProperties (nested, filter))
yield return property;
}
}
yield break;
}
public static IEnumerable<TypeDefinition> FilterTypes (AssemblyDefinition assembly, Func<TypeDefinition, bool>? filter)
// Enumerates all the events in the assembly, for all types (including nested types), potentially providing a custom filter function.
public static IEnumerable<EventDefinition> EnumerateEvents (this AssemblyDefinition assembly, Func<EventDefinition, bool>? filter = null)
{
foreach (var type in EnumerateTypes (assembly)) {
if (!type.HasEvents)
continue;
foreach (var @event in type.Events) {
if (filter is null || filter (@event))
yield return @event;
}
}
}
// Recursively enumerates all the nested types for the given type, potentially providing a custom filter function.
static IEnumerable<TypeDefinition> EnumerateNestedTypes (TypeDefinition type, Func<TypeDefinition, bool>? filter)
{
if (!type.HasNestedTypes)
yield break;
foreach (var nestedType in type.NestedTypes) {
foreach (var nn in EnumerateNestedTypes (nestedType, filter))
yield return nn;
if (filter is null || filter (nestedType))
yield return nestedType;
}
}
// Enumerates all the types in the assembly, including nested types, potentially providing a custom filter function.
public static IEnumerable<TypeDefinition> EnumerateTypes (this AssemblyDefinition assembly, Func<TypeDefinition, bool>? filter = null)
{
foreach (var module in assembly.Modules) {
if (!module.HasTypes)
continue;
foreach (var type in module.Types) {
if ((filter is null) || filter (type))
if (filter is null || filter (type))
yield return type;
foreach (var nestedType in EnumerateNestedTypes (type, filter))
yield return nestedType;
}
}
yield break;
}
public static IEnumerable<FieldDefinition> FilterFields (AssemblyDefinition assembly, Func<FieldDefinition, bool>? filter)
// Enumerates all the fields in the assembly, for all types (including nested types), potentially providing a custom filter function.
public static IEnumerable<FieldDefinition> EnumerateFields (this AssemblyDefinition assembly, Func<FieldDefinition, bool>? filter = null)
{
foreach (var module in assembly.Modules) {
foreach (var type in module.Types) {
foreach (var field in FilterFields (type, filter))
yield return field;
}
}
yield break;
}
foreach (var type in EnumerateTypes (assembly)) {
if (!type.HasFields)
continue;
static IEnumerable<FieldDefinition> FilterFields (TypeDefinition type, Func<FieldDefinition, bool>? filter)
{
if (type.HasFields) {
foreach (var field in type.Fields) {
if ((filter is null) || filter (field))
if (filter is null || filter (field))
yield return field;
}
}
if (type.HasNestedTypes) {
foreach (var nested in type.NestedTypes) {
foreach (var field in FilterFields (nested, filter))
yield return field;
}
}
yield break;
}
public static string GetBCLDirectory (string assembly)

Просмотреть файл

@ -23,7 +23,7 @@ namespace Cecil.Tests {
var failedMethods = new List<string> ();
List<string>? failures = null;
var checkedTypes = new List<TypeReference> ();
foreach (var m in Helper.FilterMethods (assembly!, (m) => m.HasPInvokeInfo)) {
foreach (var m in assembly.EnumerateMethods ((m) => m.HasPInvokeInfo)) {
failures = null;
checkedTypes.Clear ();
if (!CheckMarshalAs (checkedTypes, m, ref failures)) {

Просмотреть файл

@ -24,21 +24,21 @@ namespace Cecil.Tests {
// Make a list of Obsolete things
var found = new HashSet<string> ();
foreach (var prop in Helper.FilterProperties (assembly, a => FilterMember (a))) {
foreach (var prop in assembly.EnumerateProperties (a => FilterMember (a))) {
if (Skip (prop))
continue;
Console.WriteLine ($"{GetLocation (prop.GetMethod ?? prop.SetMethod)} {prop.FullName}");
found.Add (prop.FullName);
}
foreach (var meth in Helper.FilterMethods (assembly, a => FilterMember (a))) {
foreach (var meth in assembly.EnumerateMethods (a => FilterMember (a))) {
if (Skip (meth))
continue;
Console.WriteLine ($"{GetLocation (meth)} {meth.FullName}");
found.Add (meth.FullName);
}
foreach (var type in Helper.FilterTypes (assembly, a => FilterMember (a))) {
foreach (var type in assembly.EnumerateTypes (a => FilterMember (a))) {
if (Skip (type))
continue;
Console.WriteLine ($"{GetLocation (type.Methods.FirstOrDefault ())} {type.FullName}");

Просмотреть файл

@ -21,7 +21,7 @@ namespace Cecil.Tests {
{
var assembly = info.Assembly;
// look inside all .cctor (static constructor) inside `assemblyName`
foreach (var m in Helper.FilterMethods (assembly!, (m) => m.IsStatic && m.IsConstructor)) {
foreach (var m in assembly.EnumerateMethods ((m) => m.IsStatic && m.IsConstructor)) {
foreach (var ins in m.Body.Instructions) {
if (ins.OpCode != OpCodes.Stsfld)
continue;
@ -134,7 +134,7 @@ namespace Cecil.Tests {
{
var assembly = info.Assembly;
List<string> found = new List<string> ();
foreach (var m in Helper.FilterMethods (assembly!, (m) => m.IsPInvokeImpl)) {
foreach (var m in assembly.EnumerateMethods ((m) => m.IsPInvokeImpl)) {
var symbol = m.PInvokeInfo.EntryPoint;
if (BannedCApi.Contains (symbol))
found.Add (symbol);