[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:
Родитель
b8f15a0656
Коммит
e3f549fc7e
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче