diff --git a/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs b/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs new file mode 100644 index 000000000000..bcd6a0747d1f --- /dev/null +++ b/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs @@ -0,0 +1,298 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Mono.Cecil; + +namespace Mono.Linker +{ + internal static class DynamicallyAccessedMembersBinder + { + // Returns the members of the type bound by memberTypes. For MemberTypes.All, this returns a single null result. + // This sentinel value allows callers to handle the case where MemberTypes.All conceptually binds to the entire type + // including all recursive nested members. + public static IEnumerable GetDynamicallyAccessedMembers (this TypeDefinition typeDefinition, DynamicallyAccessedMemberTypes memberTypes) + { + if (memberTypes == DynamicallyAccessedMemberTypes.All) { + yield return null; + yield break; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicConstructors)) { + foreach (var c in typeDefinition.GetConstructorsOnType (filter: null, bindingFlags: BindingFlags.NonPublic)) + yield return c; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors)) { + foreach (var c in typeDefinition.GetConstructorsOnType (filter: null, bindingFlags: BindingFlags.Public)) + yield return c; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.DefaultConstructor)) { + foreach (var c in typeDefinition.GetConstructorsOnType (filter: m => m.IsPublic && m.Parameters.Count == 0)) + yield return c; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicMethods)) { + foreach (var m in typeDefinition.GetMethodsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.NonPublic)) + yield return m; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicMethods)) { + foreach (var m in typeDefinition.GetMethodsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.Public)) + yield return m; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicFields)) { + foreach (var f in typeDefinition.GetFieldsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.NonPublic)) + yield return f; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicFields)) { + foreach (var f in typeDefinition.GetFieldsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.Public)) + yield return f; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicNestedTypes)) { + foreach (var t in typeDefinition.GetNestedTypesOnType (filter: null, bindingFlags: BindingFlags.NonPublic)) + yield return t; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicNestedTypes)) { + foreach (var t in typeDefinition.GetNestedTypesOnType (filter: null, bindingFlags: BindingFlags.Public)) + yield return t; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicProperties)) { + foreach (var p in typeDefinition.GetPropertiesOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.NonPublic)) + yield return p; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicProperties)) { + foreach (var p in typeDefinition.GetPropertiesOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.Public)) + yield return p; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicEvents)) { + foreach (var e in typeDefinition.GetEventsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.NonPublic)) + yield return e; + } + + if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicEvents)) { + foreach (var e in typeDefinition.GetEventsOnTypeHierarchy (filter: null, bindingFlags: BindingFlags.Public)) + yield return e; + } + } + + public static IEnumerable GetConstructorsOnType (this TypeDefinition type, Func filter, BindingFlags? bindingFlags = null) + { + foreach (var method in type.Methods) { + if (!method.IsConstructor) + continue; + + if (filter != null && !filter (method)) + continue; + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static && !method.IsStatic) + continue; + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance && method.IsStatic) + continue; + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public && !method.IsPublic) + continue; + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic && method.IsPublic) + continue; + + yield return method; + } + } + + public static IEnumerable GetMethodsOnTypeHierarchy (this TypeDefinition type, Func filter, BindingFlags? bindingFlags = null) + { + bool onBaseType = false; + while (type != null) { + foreach (var method in type.Methods) { + // Ignore constructors as those are not considered methods from a reflection's point of view + if (method.IsConstructor) + continue; + + // Ignore private methods on a base type - those are completely ignored by reflection + // (anything private on the base type is not visible via the derived type) + if (onBaseType && method.IsPrivate) + continue; + + // Note that special methods like property getter/setter, event adder/remover will still get through and will be marked. + // This is intentional as reflection treats these as methods as well. + + if (filter != null && !filter (method)) + continue; + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static && !method.IsStatic) + continue; + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance && method.IsStatic) + continue; + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public && !method.IsPublic) + continue; + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic && method.IsPublic) + continue; + + yield return method; + } + + type = type.BaseType?.Resolve (); + onBaseType = true; + } + } + + public static IEnumerable GetFieldsOnTypeHierarchy (this TypeDefinition type, Func filter, BindingFlags bindingFlags = BindingFlags.Default) + { + bool onBaseType = false; + while (type != null) { + foreach (var field in type.Fields) { + // Ignore private fields on a base type - those are completely ignored by reflection + // (anything private on the base type is not visible via the derived type) + if (onBaseType && field.IsPrivate) + continue; + + // Note that compiler generated fields backing some properties and events will get through here. + // This is intentional as reflection treats these as fields as well. + + if (filter != null && !filter (field)) + continue; + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static && !field.IsStatic) + continue; + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance && field.IsStatic) + continue; + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public && !field.IsPublic) + continue; + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic && field.IsPublic) + continue; + + yield return field; + } + + type = type.BaseType?.Resolve (); + onBaseType = true; + } + } + + public static IEnumerable GetNestedTypesOnType (this TypeDefinition type, Func filter, BindingFlags bindingFlags = BindingFlags.Default) + { + foreach (var nestedType in type.NestedTypes) { + if (filter != null && !filter (nestedType)) + continue; + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public) { + if (!nestedType.IsNestedPublic) + continue; + } + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic) { + if (nestedType.IsNestedPublic) + continue; + } + + yield return nestedType; + } + } + + public static IEnumerable GetPropertiesOnTypeHierarchy (this TypeDefinition type, Func filter, BindingFlags bindingFlags = BindingFlags.Default) + { + bool onBaseType = false; + while (type != null) { + foreach (var property in type.Properties) { + // Ignore private properties on a base type - those are completely ignored by reflection + // (anything private on the base type is not visible via the derived type) + // Note that properties themselves are not actually private, their accessors are + if (onBaseType && + (property.GetMethod == null || property.GetMethod.IsPrivate) && + (property.SetMethod == null || property.SetMethod.IsPrivate)) + continue; + + if (filter != null && !filter (property)) + continue; + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static) { + if ((property.GetMethod != null) && !property.GetMethod.IsStatic) continue; + if ((property.SetMethod != null) && !property.SetMethod.IsStatic) continue; + } + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance) { + if ((property.GetMethod != null) && property.GetMethod.IsStatic) continue; + if ((property.SetMethod != null) && property.SetMethod.IsStatic) continue; + } + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public) { + if ((property.GetMethod == null || !property.GetMethod.IsPublic) + && (property.SetMethod == null || !property.SetMethod.IsPublic)) + continue; + } + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic) { + if ((property.GetMethod != null) && property.GetMethod.IsPublic) continue; + if ((property.SetMethod != null) && property.SetMethod.IsPublic) continue; + } + + yield return property; + } + + type = type.BaseType?.Resolve (); + onBaseType = true; + } + } + + public static IEnumerable GetEventsOnTypeHierarchy (this TypeDefinition type, Func filter, BindingFlags bindingFlags = BindingFlags.Default) + { + bool onBaseType = false; + while (type != null) { + foreach (var @event in type.Events) { + // Ignore private properties on a base type - those are completely ignored by reflection + // (anything private on the base type is not visible via the derived type) + // Note that properties themselves are not actually private, their accessors are + if (onBaseType && + (@event.AddMethod == null || @event.AddMethod.IsPrivate) && + (@event.RemoveMethod == null || @event.RemoveMethod.IsPrivate)) + continue; + + if (filter != null && !filter (@event)) + continue; + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static) { + if ((@event.AddMethod != null) && !@event.AddMethod.IsStatic) continue; + if ((@event.RemoveMethod != null) && !@event.RemoveMethod.IsStatic) continue; + } + + if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance) { + if ((@event.AddMethod != null) && @event.AddMethod.IsStatic) continue; + if ((@event.RemoveMethod != null) && @event.RemoveMethod.IsStatic) continue; + } + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public) { + if ((@event.AddMethod == null || !@event.AddMethod.IsPublic) + && (@event.RemoveMethod == null || !@event.RemoveMethod.IsPublic)) + continue; + } + + if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic) { + if ((@event.AddMethod != null) && @event.AddMethod.IsPublic) continue; + if ((@event.RemoveMethod != null) && @event.RemoveMethod.IsPublic) continue; + } + + yield return @event; + } + + type = type.BaseType?.Resolve (); + onBaseType = true; + } + } + } +} \ No newline at end of file diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index 7f3cbd508b54..7c0695ccc573 100644 --- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -1237,178 +1237,100 @@ void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionC void MarkTypeForDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, DynamicallyAccessedMemberTypes requiredMemberKinds) { - if (requiredMemberKinds == DynamicallyAccessedMemberTypes.All) { - var source = reflectionContext.Source; - reflectionContext.RecordRecognizedPattern (typeDefinition, () => _markStep.MarkEntireType (typeDefinition, includeBaseTypes: true, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); - return; + foreach (var member in typeDefinition.GetDynamicallyAccessedMembers (requiredMemberKinds)) { + switch (member) { + case MethodDefinition method: + MarkMethod (ref reflectionContext, typeDefinition, method); + break; + case FieldDefinition field: + MarkField (ref reflectionContext, typeDefinition, field); + break; + case TypeDefinition nestedType: + MarkNestedType (ref reflectionContext, typeDefinition, nestedType); + break; + case PropertyDefinition property: + MarkProperty (ref reflectionContext, typeDefinition, property); + break; + case EventDefinition @event: + MarkEvent (ref reflectionContext, typeDefinition, @event); + break; + case null: + var source = reflectionContext.Source; + reflectionContext.RecordRecognizedPattern (typeDefinition, () => _markStep.MarkEntireType (typeDefinition, includeBaseTypes: true, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); + break; + } } + } - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.NonPublicConstructors)) - MarkConstructorsOnType (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.NonPublic); - - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors)) - MarkConstructorsOnType (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.Public); - - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.DefaultConstructor)) - MarkConstructorsOnType (ref reflectionContext, typeDefinition, filter: m => m.IsPublic && m.Parameters.Count == 0); - - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.NonPublicMethods)) - MarkMethodsOnTypeHierarchy (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.NonPublic); - - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.PublicMethods)) - MarkMethodsOnTypeHierarchy (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.Public); - - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.NonPublicFields)) - MarkFieldsOnTypeHierarchy (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.NonPublic); - - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.PublicFields)) - MarkFieldsOnTypeHierarchy (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.Public); - - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.NonPublicNestedTypes)) - MarkNestedTypesOnType (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.NonPublic); - - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.PublicNestedTypes)) - MarkNestedTypesOnType (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.Public); + void MarkMethod (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, MethodDefinition method) + { + var source = reflectionContext.Source; + reflectionContext.RecordRecognizedPattern (method, () => _markStep.MarkIndirectlyCalledMethod (method, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); + } - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.NonPublicProperties)) - MarkPropertiesOnTypeHierarchy (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.NonPublic); + void MarkNestedType (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, TypeDefinition nestedType) + { + var source = reflectionContext.Source; + reflectionContext.RecordRecognizedPattern (nestedType, () => _markStep.MarkType (nestedType, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); + } - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.PublicProperties)) - MarkPropertiesOnTypeHierarchy (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.Public); + void MarkField (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, FieldDefinition field) + { + var source = reflectionContext.Source; + reflectionContext.RecordRecognizedPattern (field, () => _markStep.MarkField (field, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); + } - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.NonPublicEvents)) - MarkEventsOnTypeHierarchy (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.NonPublic); + void MarkProperty (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, PropertyDefinition property) + { + var source = reflectionContext.Source; + var dependencyInfo = new DependencyInfo (DependencyKind.AccessedViaReflection, source); + reflectionContext.RecordRecognizedPattern (property, () => { + // Marking the property itself actually doesn't keep it (it only marks its attributes and records the dependency), we have to mark the methods on it + _markStep.MarkProperty (property, dependencyInfo); + // TODO - this is sort of questionable - when somebody asks for a property they probably want to call either get or set + // but linker tracks those separately, and so accessing the getter/setter will raise a warning as it's potentially trimmed. + // So including them here doesn't actually remove the warning even if the code is written correctly. + _markStep.MarkMethodIfNotNull (property.GetMethod, dependencyInfo); + _markStep.MarkMethodIfNotNull (property.SetMethod, dependencyInfo); + _markStep.MarkMethodsIf (property.OtherMethods, m => true, dependencyInfo); + }); + } - if (requiredMemberKinds.HasFlag (DynamicallyAccessedMemberTypes.PublicEvents)) - MarkEventsOnTypeHierarchy (ref reflectionContext, typeDefinition, filter: null, bindingFlags: BindingFlags.Public); + void MarkEvent (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, EventDefinition @event) + { + var dependencyInfo = new DependencyInfo (DependencyKind.AccessedViaReflection, reflectionContext.Source); + reflectionContext.RecordRecognizedPattern (@event, () => { + // MarkEvent actually marks the add/remove/invoke methods as well, so no need to mark those explicitly + _markStep.MarkEvent (@event, dependencyInfo); + _markStep.MarkMethodsIf (@event.OtherMethods, m => true, dependencyInfo); + }); } void MarkConstructorsOnType (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func filter, BindingFlags? bindingFlags = null) { - foreach (var method in type.Methods) { - if (!method.IsConstructor) - continue; - - if (filter != null && !filter (method)) - continue; - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static && !method.IsStatic) - continue; - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance && method.IsStatic) - continue; - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public && !method.IsPublic) - continue; - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic && method.IsPublic) - continue; - - var source = reflectionContext.Source; - reflectionContext.RecordRecognizedPattern (method, () => _markStep.MarkIndirectlyCalledMethod (method, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); - } + foreach (var ctor in type.GetConstructorsOnType (filter, bindingFlags)) + MarkMethod (ref reflectionContext, type, ctor); } void MarkMethodsOnTypeHierarchy (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func filter, BindingFlags? bindingFlags = null) { - bool onBaseType = false; - while (type != null) { - foreach (var method in type.Methods) { - // Ignore constructors as those are not considered methods from a reflection's point of view - if (method.IsConstructor) - continue; - - // Ignore private methods on a base type - those are completely ignored by reflection - // (anything private on the base type is not visible via the derived type) - if (onBaseType && method.IsPrivate) - continue; - - // Note that special methods like property getter/setter, event adder/remover will still get through and will be marked. - // This is intentional as reflection treats these as methods as well. - - if (filter != null && !filter (method)) - continue; - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static && !method.IsStatic) - continue; - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance && method.IsStatic) - continue; - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public && !method.IsPublic) - continue; - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic && method.IsPublic) - continue; - - var source = reflectionContext.Source; - reflectionContext.RecordRecognizedPattern (method, () => _markStep.MarkIndirectlyCalledMethod (method, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); - } - - type = type.BaseType?.Resolve (); - onBaseType = true; - } + foreach (var method in type.GetMethodsOnTypeHierarchy (filter, bindingFlags)) + MarkMethod (ref reflectionContext, type, method); } void MarkFieldsOnTypeHierarchy (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func filter, BindingFlags bindingFlags = BindingFlags.Default) { - bool onBaseType = false; - while (type != null) { - foreach (var field in type.Fields) { - // Ignore private fields on a base type - those are completely ignored by reflection - // (anything private on the base type is not visible via the derived type) - if (onBaseType && field.IsPrivate) - continue; - - // Note that compiler generated fields backing some properties and events will get through here. - // This is intentional as reflection treats these as fields as well. - - if (filter != null && !filter (field)) - continue; - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static && !field.IsStatic) - continue; - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance && field.IsStatic) - continue; - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public && !field.IsPublic) - continue; - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic && field.IsPublic) - continue; - - var source = reflectionContext.Source; - reflectionContext.RecordRecognizedPattern (field, () => _markStep.MarkField (field, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); - } - - type = type.BaseType?.Resolve (); - onBaseType = true; - } + foreach (var field in type.GetFieldsOnTypeHierarchy (filter, bindingFlags)) + MarkField (ref reflectionContext, type, field); } TypeDefinition[] MarkNestedTypesOnType (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func filter, BindingFlags bindingFlags = BindingFlags.Default) { var result = new ArrayBuilder (); - foreach (var nestedType in type.NestedTypes) { - if (filter != null && !filter (nestedType)) - continue; - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public) { - if (!nestedType.IsNestedPublic) - continue; - } - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic) { - if (nestedType.IsNestedPublic) - continue; - } - + foreach (var nestedType in type.GetNestedTypesOnType (filter, bindingFlags)) { result.Add (nestedType); - - var source = reflectionContext.Source; - reflectionContext.RecordRecognizedPattern (nestedType, () => _markStep.MarkType (nestedType, new DependencyInfo (DependencyKind.AccessedViaReflection, source))); + MarkNestedType (ref reflectionContext, type, nestedType); } return result.ToArray (); @@ -1416,107 +1338,14 @@ TypeDefinition[] MarkNestedTypesOnType (ref ReflectionPatternContext reflectionC void MarkPropertiesOnTypeHierarchy (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func filter, BindingFlags bindingFlags = BindingFlags.Default) { - bool onBaseType = false; - while (type != null) { - foreach (var property in type.Properties) { - // Ignore private properties on a base type - those are completely ignored by reflection - // (anything private on the base type is not visible via the derived type) - // Note that properties themselves are not actually private, their accessors are - if (onBaseType && - (property.GetMethod == null || property.GetMethod.IsPrivate) && - (property.SetMethod == null || property.SetMethod.IsPrivate)) - continue; - - if (filter != null && !filter (property)) - continue; - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static) { - if ((property.GetMethod != null) && !property.GetMethod.IsStatic) continue; - if ((property.SetMethod != null) && !property.SetMethod.IsStatic) continue; - } - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance) { - if ((property.GetMethod != null) && property.GetMethod.IsStatic) continue; - if ((property.SetMethod != null) && property.SetMethod.IsStatic) continue; - } - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public) { - if ((property.GetMethod == null || !property.GetMethod.IsPublic) - && (property.SetMethod == null || !property.SetMethod.IsPublic)) - continue; - } - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic) { - if ((property.GetMethod != null) && property.GetMethod.IsPublic) continue; - if ((property.SetMethod != null) && property.SetMethod.IsPublic) continue; - } - - var source = reflectionContext.Source; - reflectionContext.RecordRecognizedPattern (property, () => { - // Marking the property itself actually doesn't keep it (it only marks its attributes and records the dependency), we have to mark the methods on it - _markStep.MarkProperty (property, new DependencyInfo (DependencyKind.AccessedViaReflection, source)); - // TODO - this is sort of questionable - when somebody asks for a property they probably want to call either get or set - // but linker tracks those separately, and so accessing the getter/setter will raise a warning as it's potentially trimmed. - // So including them here doesn't actually remove the warning even if the code is written correctly. - _markStep.MarkMethodIfNotNull (property.GetMethod, new DependencyInfo (DependencyKind.AccessedViaReflection, source)); - _markStep.MarkMethodIfNotNull (property.SetMethod, new DependencyInfo (DependencyKind.AccessedViaReflection, source)); - _markStep.MarkMethodsIf (property.OtherMethods, m => true, new DependencyInfo (DependencyKind.AccessedViaReflection, source)); - }); - } - - type = type.BaseType?.Resolve (); - onBaseType = true; - } + foreach (var property in type.GetPropertiesOnTypeHierarchy (filter, bindingFlags)) + MarkProperty (ref reflectionContext, type, property); } void MarkEventsOnTypeHierarchy (ref ReflectionPatternContext reflectionContext, TypeDefinition type, Func filter, BindingFlags bindingFlags = BindingFlags.Default) { - bool onBaseType = false; - while (type != null) { - foreach (var @event in type.Events) { - // Ignore private properties on a base type - those are completely ignored by reflection - // (anything private on the base type is not visible via the derived type) - // Note that properties themselves are not actually private, their accessors are - if (onBaseType && - (@event.AddMethod == null || @event.AddMethod.IsPrivate) && - (@event.RemoveMethod == null || @event.RemoveMethod.IsPrivate)) - continue; - - if (filter != null && !filter (@event)) - continue; - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Static) { - if ((@event.AddMethod != null) && !@event.AddMethod.IsStatic) continue; - if ((@event.RemoveMethod != null) && !@event.RemoveMethod.IsStatic) continue; - } - - if ((bindingFlags & (BindingFlags.Instance | BindingFlags.Static)) == BindingFlags.Instance) { - if ((@event.AddMethod != null) && @event.AddMethod.IsStatic) continue; - if ((@event.RemoveMethod != null) && @event.RemoveMethod.IsStatic) continue; - } - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.Public) { - if ((@event.AddMethod == null || !@event.AddMethod.IsPublic) - && (@event.RemoveMethod == null || !@event.RemoveMethod.IsPublic)) - continue; - } - - if ((bindingFlags & (BindingFlags.Public | BindingFlags.NonPublic)) == BindingFlags.NonPublic) { - if ((@event.AddMethod != null) && @event.AddMethod.IsPublic) continue; - if ((@event.RemoveMethod != null) && @event.RemoveMethod.IsPublic) continue; - } - - var source = reflectionContext.Source; - reflectionContext.RecordRecognizedPattern (@event, () => { - // MarkEvent actually marks the add/remove/invoke methods as well, so no need to mark those explicitly - _markStep.MarkEvent (@event, new DependencyInfo (DependencyKind.AccessedViaReflection, source)); - _markStep.MarkMethodsIf (@event.OtherMethods, m => true, new DependencyInfo (DependencyKind.AccessedViaReflection, source)); - }); - } - - type = type.BaseType?.Resolve (); - onBaseType = true; - } + foreach (var @event in type.GetEventsOnTypeHierarchy (filter, bindingFlags)) + MarkEvent (ref reflectionContext, type, @event); } string GetValueDescriptionForErrorMessage (ValueNode value)