Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven Boemer <sbomer@gmail.com>2021-08-14 02:25:25 +0300
committerGitHub <noreply@github.com>2021-08-14 02:25:25 +0300
commitc321df28835445093009af394ddf3c31e9b1fc91 (patch)
tree0a53f29ab3d2d028e5dd375f55e1f377737cc298
parent4dd506a685d7d81a0e7782ca56d6c0db0064d7d4 (diff)
Fix warnings for DAMT on interfaces (#2210)
* Fix warnings for DAMT on interfaces https://github.com/mono/linker/pull/2191 addressed issues with redundant warnings from base types, but interfaces need to be handled specially. There were a few issues with the interface handling in that change: - The binding logic didn't include interfaces for DAM.All when declaredOnly was specified, as @vitek-karas pointed out in https://github.com/mono/linker/pull/2206#discussion_r687573854. This could have led to us not marking interfaces for types derived from a DAMT.All-annotated type. Either way, the binding logic should not select interface _members_ when declaredOnly is specified. - The DAMT-on-type logic had special handling for base types, but didn't separately mark interface members, which is needed when applying annotations DAMT.All or DAMT.Interfaces. This could have led to missing interface impls or interface members for types which have (explicit or inherited) DAMT.All or DAMT.Interfaces annotations. Separately, the bit operations on DAMT also didn't correctly handle cases where there are bits shared by different enum members. * Remove debug output * Apply suggestions from code review Co-authored-by: Vitek Karas <vitek.karas@microsoft.com> Co-authored-by: Vitek Karas <vitek.karas@microsoft.com>
-rw-r--r--src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs37
-rw-r--r--src/linker/Linker.Dataflow/DynamicallyAccessedMembersTypeHierarchy.cs53
-rw-r--r--src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs94
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs19
-rw-r--r--test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs84
5 files changed, 217 insertions, 70 deletions
diff --git a/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs b/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs
index 85b597fe1..d8b08b858 100644
--- a/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs
+++ b/src/linker/Linker.Dataflow/DynamicallyAccessedMembersBinder.cs
@@ -24,7 +24,8 @@ namespace Mono.Linker
// DynamicallyAccessedMemberTypes.PublicNestedTypes and NonPublicNestedTypes do the same for members of the selected nested types.
public static IEnumerable<IMetadataTokenProvider> GetDynamicallyAccessedMembers (this TypeDefinition typeDefinition, LinkContext context, DynamicallyAccessedMemberTypes memberTypes, bool declaredOnly = false)
{
- var declaredOnlyFlags = declaredOnly ? BindingFlags.DeclaredOnly : BindingFlags.Default;
+ if (memberTypes == DynamicallyAccessedMemberTypes.None)
+ yield break;
if (memberTypes == DynamicallyAccessedMemberTypes.All) {
var members = new List<IMetadataTokenProvider> ();
@@ -34,6 +35,8 @@ namespace Mono.Linker
yield break;
}
+ var declaredOnlyFlags = declaredOnly ? BindingFlags.DeclaredOnly : BindingFlags.Default;
+
if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.NonPublicConstructors)) {
foreach (var c in typeDefinition.GetConstructorsOnType (filter: null, bindingFlags: BindingFlags.NonPublic))
yield return c;
@@ -338,18 +341,19 @@ namespace Mono.Linker
}
}
+ // declaredOnly will cause this to retrieve interfaces recursively required by the type, but doesn't necessarily
+ // include interfaces required by any base types.
public static IEnumerable<InterfaceImplementation> GetAllInterfaceImplementations (this TypeDefinition type, LinkContext context, bool declaredOnly)
{
while (type != null) {
foreach (var i in type.Interfaces) {
yield return i;
- if (!declaredOnly) {
- TypeDefinition interfaceType = context.TryResolve (i.InterfaceType);
- if (interfaceType != null) {
- foreach (var innerInterface in interfaceType.GetAllInterfaceImplementations (context, declaredOnly: false))
- yield return innerInterface;
- }
+ TypeDefinition interfaceType = context.TryResolve (i.InterfaceType);
+ if (interfaceType != null) {
+ // declaredOnly here doesn't matter since interfaces don't have base types
+ foreach (var innerInterface in interfaceType.GetAllInterfaceImplementations (context, declaredOnly: true))
+ yield return innerInterface;
}
}
@@ -360,6 +364,8 @@ namespace Mono.Linker
}
}
+ // declaredOnly will cause this to retrieve only members of the type, not of its base types. This includes interfaces recursively
+ // required by this type (but not members of these interfaces, or interfaces required only by base types).
public static void GetAllOnType (this TypeDefinition type, LinkContext context, bool declaredOnly, List<IMetadataTokenProvider> members) => GetAllOnType (type, context, declaredOnly, members, new HashSet<TypeDefinition> ());
static void GetAllOnType (TypeDefinition type, LinkContext context, bool declaredOnly, List<IMetadataTokenProvider> members, HashSet<TypeDefinition> types)
@@ -381,11 +387,18 @@ namespace Mono.Linker
GetAllOnType (baseType, context, declaredOnly: false, members, types);
}
- if (!declaredOnly && type.HasInterfaces) {
- foreach (var iface in type.Interfaces) {
- members.Add (iface);
- var interfaceType = context.TryResolve (iface.InterfaceType);
- GetAllOnType (interfaceType, context, declaredOnly: false, members, types);
+ if (type.HasInterfaces) {
+ if (declaredOnly) {
+ foreach (var iface in type.GetAllInterfaceImplementations (context, declaredOnly: true))
+ members.Add (iface);
+ } else {
+ foreach (var iface in type.Interfaces) {
+ members.Add (iface);
+ var interfaceType = context.TryResolve (iface.InterfaceType);
+ if (interfaceType == null)
+ continue;
+ GetAllOnType (interfaceType, context, declaredOnly: false, members, types);
+ }
}
}
diff --git a/src/linker/Linker.Dataflow/DynamicallyAccessedMembersTypeHierarchy.cs b/src/linker/Linker.Dataflow/DynamicallyAccessedMembersTypeHierarchy.cs
index e3e871510..e4bbadfbe 100644
--- a/src/linker/Linker.Dataflow/DynamicallyAccessedMembersTypeHierarchy.cs
+++ b/src/linker/Linker.Dataflow/DynamicallyAccessedMembersTypeHierarchy.cs
@@ -120,7 +120,7 @@ namespace Mono.Linker.Dataflow
var reflectionMethodBodyScanner = new ReflectionMethodBodyScanner (_context, _markStep, _scopeStack);
// Set up a context to report warnings on access to annotated members, with the annotated type as the origin.
var reflectionPatternContext = new ReflectionPatternContext (_context, reportingEnabled: true, _scopeStack.CurrentScope.Origin, type);
- reflectionMethodBodyScanner.ApplyDynamicallyAccessedMembersToType (ref reflectionPatternContext, type, annotation);
+ ApplyDynamicallyAccessedMembersToType (ref reflectionMethodBodyScanner, ref reflectionPatternContext, type, annotation);
reflectionPatternContext.Dispose ();
}
@@ -145,7 +145,7 @@ namespace Mono.Linker.Dataflow
using var _ = _scopeStack.PushScope (new MessageOrigin (type));
// Set up a context to report warnings on access to annotated members, with the annotated type as the origin.
var reflectionPatternContext = new ReflectionPatternContext (_context, reportingEnabled: true, _scopeStack.CurrentScope.Origin, type);
- reflectionMethodBodyScanner.ApplyDynamicallyAccessedMembersToType (ref reflectionPatternContext, type, annotation);
+ ApplyDynamicallyAccessedMembersToType (ref reflectionMethodBodyScanner, ref reflectionPatternContext, type, annotation);
// Mark it as applied in the cache
_typesInDynamicallyAccessedMembersHierarchy[type] = (annotation, true);
@@ -216,13 +216,60 @@ namespace Mono.Linker.Dataflow
using var _ = _scopeStack.PushScope (new MessageOrigin (type));
// Set up a context to report warnings on access to annotated members, with the annotated type as the origin.
var reflectionPatternContext = new ReflectionPatternContext (_context, reportingEnabled: true, _scopeStack.CurrentScope.Origin, type);
- reflectionMethodBodyScanner.ApplyDynamicallyAccessedMembersToType (ref reflectionPatternContext, type, annotation);
+ ApplyDynamicallyAccessedMembersToType (ref reflectionMethodBodyScanner, ref reflectionPatternContext, type, annotation);
_typesInDynamicallyAccessedMembersHierarchy[type] = (annotation, true);
}
return applied;
}
+ public void ApplyDynamicallyAccessedMembersToType (ref ReflectionMethodBodyScanner reflectionMethodBodyScanner, ref ReflectionPatternContext reflectionPatternContext, TypeDefinition type, DynamicallyAccessedMemberTypes annotation)
+ {
+ Debug.Assert (annotation != DynamicallyAccessedMemberTypes.None);
+
+ reflectionPatternContext.AnalyzingPattern ();
+ // There are no cases where we don't handle the pattern - the method will always "deal with it"
+ reflectionPatternContext.RecordHandledPattern ();
+
+ // We need to apply annotations to this type, and its base/interface types (recursively)
+ // But the annotations on base/interfaces are already applied so we don't need to apply those
+ // again (and should avoid doing so as it would produce extra warnings).
+ var baseType = _context.TryResolve (type.BaseType);
+ if (baseType != null) {
+ var baseAnnotation = GetCachedInfoForTypeInHierarchy (baseType);
+ var annotationToApplyToBase = ReflectionMethodBodyScanner.GetMissingMemberTypes (annotation, baseAnnotation.annotation);
+
+ // Apply any annotations that didn't exist on the base type to the base type.
+ // This may produce redundant warnings when the annotation is DAMT.All or DAMT.PublicConstructors and the base already has a
+ // subset of those annotations.
+ reflectionMethodBodyScanner.MarkTypeForDynamicallyAccessedMembers (ref reflectionPatternContext, baseType, annotationToApplyToBase, DependencyKind.DynamicallyAccessedMemberOnType, declaredOnly: false);
+ }
+
+ // Most of the DynamicallyAccessedMemberTypes don't select members on interfaces. We only need to apply
+ // annotations to interfaces separately if dealing with DAMT.All or DAMT.Interfaces.
+ if (annotation.HasFlag (DynamicallyAccessedMemberTypesOverlay.Interfaces) && type.HasInterfaces) {
+ var annotationToApplyToInterfaces = annotation == DynamicallyAccessedMemberTypes.All ? annotation : DynamicallyAccessedMemberTypesOverlay.Interfaces;
+ foreach (var iface in type.Interfaces) {
+ var interfaceType = _context.TryResolve (iface.InterfaceType);
+ if (interfaceType == null)
+ continue;
+
+ var interfaceAnnotation = GetCachedInfoForTypeInHierarchy (interfaceType);
+ if (interfaceAnnotation.annotation.HasFlag (annotationToApplyToInterfaces))
+ continue;
+
+ // Apply All or Interfaces to the interface type.
+ // DAMT.All may produce redundant warnings from implementing types, when the interface type already had some annotations.
+ reflectionMethodBodyScanner.MarkTypeForDynamicallyAccessedMembers (ref reflectionPatternContext, interfaceType, annotationToApplyToInterfaces, DependencyKind.DynamicallyAccessedMemberOnType, declaredOnly: false);
+ }
+ }
+
+ // The annotations this type inherited from its base types or interfaces should not produce
+ // warnings on the respective base/interface members, since those are already covered by applying
+ // the annotations to those types. So we only need to handle the members directly declared on this type.
+ reflectionMethodBodyScanner.MarkTypeForDynamicallyAccessedMembers (ref reflectionPatternContext, type, annotation, DependencyKind.DynamicallyAccessedMemberOnType, declaredOnly: true);
+ }
+
(DynamicallyAccessedMemberTypes annotation, bool applied) GetCachedInfoForTypeInHierarchy (TypeDefinition type)
{
Debug.Assert (type.IsInterface || _context.Annotations.IsMarked (type));
diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index f367a3f4c..5d08160da 100644
--- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -119,27 +119,6 @@ namespace Mono.Linker.Dataflow
reflectionContext.Dispose ();
}
- public void ApplyDynamicallyAccessedMembersToType (ref ReflectionPatternContext reflectionPatternContext, TypeDefinition type, DynamicallyAccessedMemberTypes annotation)
- {
- Debug.Assert (annotation != DynamicallyAccessedMemberTypes.None);
-
- reflectionPatternContext.AnalyzingPattern ();
- // Handle cases where a type has no members but annotations are to be applied to derived type members
- reflectionPatternContext.RecordHandledPattern ();
-
- // The annotations this type inherited from its base types should not produce
- // warnings on the base members, since those are covered by warnings in the base type.
- // For now, annotations that are inherited from base types but also declared explicitly on this type
- // still warn about base members since the cache doesn't track enough information to tell the difference.
- var declaredAnnotation = _context.Annotations.FlowAnnotations.GetTypeAnnotation (type);
- var inheritedOnlyAnnotation = annotation & ~declaredAnnotation;
-
- // Warn about all members accessed by the annotation on this type (including members of base types/interfaces)
- MarkTypeForDynamicallyAccessedMembers (ref reflectionPatternContext, type, declaredAnnotation, DependencyKind.DynamicallyAccessedMemberOnType, declaredOnly: false);
- // Warn about members accessed by inherited annotations (not including members of base types/interfaces)
- MarkTypeForDynamicallyAccessedMembers (ref reflectionPatternContext, type, inheritedOnlyAnnotation, DependencyKind.DynamicallyAccessedMemberOnType, declaredOnly: true);
- }
-
ValueNode GetValueNodeForCustomAttributeArgument (CustomAttributeArgument argument)
{
ValueNode valueNode;
@@ -2008,6 +1987,48 @@ namespace Mono.Linker.Dataflow
methodReturnValue = MergePointValue.MergeValues (methodReturnValue, NullValue.Instance);
}
+ public static DynamicallyAccessedMemberTypes GetMissingMemberTypes (DynamicallyAccessedMemberTypes requiredMemberTypes, DynamicallyAccessedMemberTypes availableMemberTypes)
+ {
+ if (availableMemberTypes.HasFlag (requiredMemberTypes))
+ return DynamicallyAccessedMemberTypes.None;
+
+ if (requiredMemberTypes == DynamicallyAccessedMemberTypes.All)
+ return DynamicallyAccessedMemberTypes.All;
+
+ var missingMemberTypes = requiredMemberTypes & ~availableMemberTypes;
+
+ // PublicConstructors is a special case since its value is 3 - so PublicParameterlessConstructor (1) | _PublicConstructor_WithMoreThanOneParameter_ (2)
+ // The above bit logic only works for value with single bit set.
+ if (requiredMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors) &&
+ !availableMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors))
+ missingMemberTypes |= DynamicallyAccessedMemberTypes.PublicConstructors;
+
+ return missingMemberTypes;
+ }
+
+ string GetMemberTypesString (DynamicallyAccessedMemberTypes memberTypes)
+ {
+ Debug.Assert (memberTypes != DynamicallyAccessedMemberTypes.None);
+
+ if (memberTypes == DynamicallyAccessedMemberTypes.All)
+ return $"'{nameof (DynamicallyAccessedMemberTypes)}.{nameof (DynamicallyAccessedMemberTypes.All)}'";
+
+ var memberTypesList = AllDynamicallyAccessedMemberTypes
+ .Where (damt => (memberTypes & damt) == damt && damt != DynamicallyAccessedMemberTypes.None)
+ .ToList ();
+
+ if (memberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors))
+ memberTypesList.Remove (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
+
+ return string.Join (", ", memberTypesList.Select (mt => {
+ string mtName = mt == DynamicallyAccessedMemberTypesOverlay.Interfaces
+ ? nameof (DynamicallyAccessedMemberTypesOverlay.Interfaces)
+ : mt.ToString ();
+
+ return $"'{nameof (DynamicallyAccessedMemberTypes)}.{mtName}'";
+ }));
+ }
+
void RequireDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionContext, DynamicallyAccessedMemberTypes requiredMemberTypes, ValueNode value, IMetadataTokenProvider targetContext)
{
foreach (var uniqueValue in value.UniqueValues ()) {
@@ -2018,32 +2039,9 @@ namespace Mono.Linker.Dataflow
reflectionContext.RecordHandledPattern ();
} else if (uniqueValue is LeafValueWithDynamicallyAccessedMemberNode valueWithDynamicallyAccessedMember) {
var availableMemberTypes = valueWithDynamicallyAccessedMember.DynamicallyAccessedMemberTypes;
- if (!availableMemberTypes.HasFlag (requiredMemberTypes)) {
- string missingMemberTypes = $"'{nameof (DynamicallyAccessedMemberTypes)}.{nameof (DynamicallyAccessedMemberTypes.All)}'";
- if (requiredMemberTypes != DynamicallyAccessedMemberTypes.All) {
- var missingMemberTypesList = AllDynamicallyAccessedMemberTypes
- .Where (damt => (requiredMemberTypes & ~availableMemberTypes & damt) == damt && damt != DynamicallyAccessedMemberTypes.None)
- .ToList ();
-
- // PublicConstructors is a special case since its value is 3 - so PublicParameterlessConstructor (1) | _PublicConstructor_WithMoreThanOneParameter_ (2)
- // The above bit logic only works for value with single bit set.
- if (requiredMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors) &&
- availableMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor) &&
- !availableMemberTypes.HasFlag (DynamicallyAccessedMemberTypes.PublicConstructors))
- missingMemberTypesList.Add (DynamicallyAccessedMemberTypes.PublicConstructors);
-
- if (missingMemberTypesList.Contains (DynamicallyAccessedMemberTypes.PublicConstructors) &&
- missingMemberTypesList.Contains (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor))
- missingMemberTypesList.Remove (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor);
-
- missingMemberTypes = string.Join (", ", missingMemberTypesList.Select (mmt => {
- string mmtName = mmt == DynamicallyAccessedMemberTypesOverlay.Interfaces
- ? nameof (DynamicallyAccessedMemberTypesOverlay.Interfaces)
- : mmt.ToString ();
-
- return $"'{nameof (DynamicallyAccessedMemberTypes)}.{mmtName}'";
- }));
- }
+ var missingMemberTypesValue = GetMissingMemberTypes (requiredMemberTypes, availableMemberTypes);
+ if (missingMemberTypesValue != DynamicallyAccessedMemberTypes.None) {
+ var missingMemberTypes = GetMemberTypesString (missingMemberTypesValue);
switch ((valueWithDynamicallyAccessedMember.SourceContext, targetContext)) {
case (ParameterDefinition sourceParameter, ParameterDefinition targetParameter):
@@ -2295,7 +2293,7 @@ namespace Mono.Linker.Dataflow
static bool HasBindingFlag (BindingFlags? bindingFlags, BindingFlags? search) => bindingFlags != null && (bindingFlags & search) == search;
- void MarkTypeForDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, DependencyKind dependencyKind, bool declaredOnly = false)
+ public void MarkTypeForDynamicallyAccessedMembers (ref ReflectionPatternContext reflectionContext, TypeDefinition typeDefinition, DynamicallyAccessedMemberTypes requiredMemberTypes, DependencyKind dependencyKind, bool declaredOnly = false)
{
foreach (var member in typeDefinition.GetDynamicallyAccessedMembers (_context, requiredMemberTypes, declaredOnly)) {
switch (member) {
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs b/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs
index 05125df0f..a683287ff 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
@@ -1347,6 +1347,22 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[Kept]
+ interface InterfaceImplementedByDerived
+ {
+ [Kept]
+ void Method ();
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (AnnotatedBase))]
+ [KeptInterface (typeof (InterfaceImplementedByDerived))]
+ class DerivedWithInterface : AnnotatedBase, InterfaceImplementedByDerived
+ {
+ [Kept]
+ public void Method () { }
+ }
+
+ [Kept]
static AnnotatedBase GetInstance () => new Derived ();
[Kept]
@@ -1354,6 +1370,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
{
Type t = GetInstance ().GetType ();
t.RequiresAll ();
+ var t2 = typeof (DerivedWithInterface);
}
}
diff --git a/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs b/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs
index 5bd06a7e7..9ca2ff3ae 100644
--- a/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs
+++ b/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs
@@ -25,6 +25,7 @@ namespace Mono.Linker.Tests.Cases.Reflection
// Reference to the derived type should apply base annotations
var t1 = typeof (DerivedFromAnnotatedBase);
var t2 = typeof (AnnotatedDerivedFromAnnotatedBase);
+ var t3 = typeof (AnnotatedAllDerivedFromAnnotatedBase);
annotatedDerivedFromBase.GetType ().RequiresPublicMethods ();
annotatedPublicNestedTypes.GetType ().RequiresPublicNestedTypes ();
derivedFromAnnotatedDerivedFromBase.GetType ().RequiresPublicFields ();
@@ -34,9 +35,12 @@ namespace Mono.Linker.Tests.Cases.Reflection
annotatedPublicEvents.GetType ().RequiresPublicEvents ();
annotatedPublicNestedTypes.GetType ().RequiresPublicNestedTypes ();
annotatedInterfaces.GetType ().RequiresInterfaces ();
+ annotatedPublicParameterlessConstructor.GetType ().RequiresPublicParameterlessConstructor ();
annotatedAll.GetType ().RequiresAll ();
- var t3 = typeof (DerivedFromAnnotatedAll1);
- var t4 = typeof (DerivedFromAnnotatedAll2);
+ var t4 = typeof (DerivedFromAnnotatedAll1);
+ var t5 = typeof (DerivedFromAnnotatedAll2);
+ var t6 = typeof (DerivedFromAnnotatedAllWithInterface);
+ var t7 = typeof (DerivedFromAnnotatedPublicParameterlessConstructor);
annotatedRUCPublicMethods.GetType ().RequiresPublicMethods ();
// Instantiate this type just so its property getters are considered reachable
@@ -60,6 +64,8 @@ namespace Mono.Linker.Tests.Cases.Reflection
[Kept]
static AnnotatedInterfaces annotatedInterfaces;
[Kept]
+ static AnnotatedPublicParameterlessConstructor annotatedPublicParameterlessConstructor;
+ [Kept]
static AnnotatedBase annotatedBase;
[Kept]
static AnnotatedBaseSharedByNestedTypes annotatedBaseSharedByNestedTypes;
@@ -114,6 +120,22 @@ namespace Mono.Linker.Tests.Cases.Reflection
{
}
+ interface InterfaceImplementedByDerived
+ {
+ [Kept]
+ [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]
+ [RequiresUnreferencedCode ("--RUC on InterfaceImplementedByDerived.RUCMethod--")]
+ void RUCInterfaceMethod () { }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (AnnotatedAll))]
+ [KeptInterface (typeof (InterfaceImplementedByDerived))]
+ [ExpectedWarning ("IL2113", "--RUC on InterfaceImplementedByDerived.RUCMethod--")]
+ class DerivedFromAnnotatedAllWithInterface : AnnotatedAll, InterfaceImplementedByDerived
+ {
+ }
+
[Kept]
[KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))]
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
@@ -251,6 +273,46 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))]
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
+ class AnnotatedPublicParameterlessConstructor
+ {
+ [Kept]
+ [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]
+ [ExpectedWarning ("IL2112", "--RUC on AnnotatedPublicParameterlessConstructor()--")]
+ [RequiresUnreferencedCode ("--RUC on AnnotatedPublicParameterlessConstructor()--")]
+ public AnnotatedPublicParameterlessConstructor () { }
+
+ [Kept]
+ [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]
+ [RequiresUnreferencedCode ("--RUC on AnnotatedPublicParameterlessConstructor(int)--")]
+ public AnnotatedPublicParameterlessConstructor (int i) { }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptBaseType (typeof (AnnotatedPublicParameterlessConstructor))]
+ [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))]
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicConstructors)]
+ [ExpectedWarning ("IL2113", "--RUC on AnnotatedPublicParameterlessConstructor(int)--")]
+ // This warning is redundant because the base type already has DAMT.PublicParameterlessConstructors,
+ // but we produce it anyway due to implementation difficulties in the case of DAMT.PublicConstructors.
+ [ExpectedWarning ("IL2113", "--RUC on AnnotatedPublicParameterlessConstructor()--")]
+ class DerivedFromAnnotatedPublicParameterlessConstructor : AnnotatedPublicParameterlessConstructor
+ {
+ [Kept]
+ [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]
+ [ExpectedWarning ("IL2112", "--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--")]
+ [RequiresUnreferencedCode ("--RUC on DerivedFromAnnotatedPublicParameterlessConstructor()--")]
+ public DerivedFromAnnotatedPublicParameterlessConstructor () { }
+
+ [Kept]
+ [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))]
+ [ExpectedWarning ("IL2112", "--RUC on DerivedFromAnnotatedPublicParameterlessConstructor(int)--")]
+ [RequiresUnreferencedCode ("--RUC on DerivedFromAnnotatedPublicParameterlessConstructor(int)--")]
+ public DerivedFromAnnotatedPublicParameterlessConstructor (int i) { }
+ }
+
+ [KeptMember (".ctor()")]
+ [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))]
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)]
class AnnotatedBase
{
@@ -279,10 +341,8 @@ namespace Mono.Linker.Tests.Cases.Reflection
[KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))]
[KeptBaseType (typeof (AnnotatedBase))]
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicFields)]
- // In theory we could avoid warning for public methods on base types because that
- // annotation is already inherited from the base type, but currently we warn on base
- // members whenever a type has an explicit annotation.
- [ExpectedWarning ("IL2113", nameof (AnnotatedBase), nameof (AnnotatedBase.RUCMethod))]
+ // No warning for public methods on base type because that annotation is already
+ // inherited from the base type.
[ExpectedWarning ("IL2115", nameof (AnnotatedBase), nameof (AnnotatedBase.DAMField1))]
class AnnotatedDerivedFromAnnotatedBase : AnnotatedBase
{
@@ -300,6 +360,18 @@ namespace Mono.Linker.Tests.Cases.Reflection
}
[KeptMember (".ctor()")]
+ [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))]
+ [KeptBaseType (typeof (AnnotatedBase))]
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
+ // This warning is redundant because the base type already has DAMT.PublicMethods,
+ // but we produce it anyway due to implementation difficulties in the case of DAMT.All.
+ [ExpectedWarning ("IL2113", "--RUC on AnnotatedBase--")]
+ [ExpectedWarning ("IL2115", nameof (AnnotatedBase), nameof (AnnotatedBase.DAMField1))]
+ class AnnotatedAllDerivedFromAnnotatedBase : AnnotatedBase
+ {
+ }
+
+ [KeptMember (".ctor()")]
class Base
{
[Kept]