diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs index 9ca8b98e9e135..d1a8db0c1b999 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs @@ -455,7 +455,7 @@ private partial bool TryHandleIntrinsic ( if (annotation != default) { - _reflectionMarker.Dependencies.Add(_reflectionMarker.Factory.ObjectGetTypeFlowDependencies(closestMetadataType), "GetType called on this type"); + _reflectionMarker.Dependencies.Add(_reflectionMarker.Factory.ObjectGetTypeCalled(closestMetadataType), "GetType called on this type"); } // Return a value which is "unknown type" with annotation. For now we'll use the return value node diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs index ce3493118082a..4738e0755bf08 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs @@ -130,6 +130,25 @@ public static DependencyList ProcessTypeGetTypeDataflow(NodeFactory factory, Flo { DynamicallyAccessedMemberTypes annotation = flowAnnotations.GetTypeAnnotation(type); Debug.Assert(annotation != DynamicallyAccessedMemberTypes.None); + + // We're on an interface and we're processing annotations for the purposes of a object.GetType() call. + // Most of the annotations don't apply to the members of interfaces - the result of object.GetType() is + // never the interface type, it's a concrete type that implements the interface. Limit this to the only + // annotations that are applicable in this situation. + if (type.IsInterface) + { + // .All applies to interface members same as to the type + if (annotation != DynamicallyAccessedMemberTypes.All) + { + // Filter to the MemberTypes that apply to interfaces + annotation &= DynamicallyAccessedMemberTypes.Interfaces; + + // If we're left with nothing, we're done + if (annotation == DynamicallyAccessedMemberTypes.None) + return new DependencyList(); + } + } + var reflectionMarker = new ReflectionMarker(logger, factory, flowAnnotations, typeHierarchyDataFlowOrigin: type, enabled: true); // We need to apply annotations to this type, and its base/interface types (recursively) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs index 84e0418e3f9e4..d66f9fcc413a6 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs @@ -377,6 +377,11 @@ private void CreateNodeCaches() return new GenericStaticBaseInfoNode(type); }); + _objectGetTypeCalled = new NodeCache(type => + { + return new ObjectGetTypeCalledNode(type); + }); + _objectGetTypeFlowDependencies = new NodeCache(type => { return new ObjectGetTypeFlowDependenciesNode(type); @@ -1147,6 +1152,12 @@ internal GenericStaticBaseInfoNode GenericStaticBaseInfo(MetadataType type) return _genericStaticBaseInfos.GetOrAdd(type); } + private NodeCache _objectGetTypeCalled; + internal ObjectGetTypeCalledNode ObjectGetTypeCalled(MetadataType type) + { + return _objectGetTypeCalled.GetOrAdd(type); + } + private NodeCache _objectGetTypeFlowDependencies; internal ObjectGetTypeFlowDependenciesNode ObjectGetTypeFlowDependencies(MetadataType type) { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectGetTypeCalledNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectGetTypeCalledNode.cs new file mode 100644 index 0000000000000..1072172986318 --- /dev/null +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectGetTypeCalledNode.cs @@ -0,0 +1,40 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; + +using ILCompiler.DependencyAnalysisFramework; + +using Internal.TypeSystem; + +namespace ILCompiler.DependencyAnalysis +{ + /// + /// Represents the fact that object.GetType was called on a location typed as this + /// type or one of the subtypes of it. + /// + internal sealed class ObjectGetTypeCalledNode : DependencyNodeCore + { + private readonly MetadataType _type; + + public ObjectGetTypeCalledNode(MetadataType type) + { + _type = type; + } + + protected override string GetName(NodeFactory factory) + { + return $"Object.GetType called on {_type}"; + } + + public override IEnumerable GetStaticDependencies(NodeFactory factory) => null; + public override bool InterestingForDynamicDependencyAnalysis => false; + public override bool HasDynamicDependencies => false; + public override bool HasConditionalStaticDependencies => false; + public override bool StaticDependenciesAreComputed => true; + public override IEnumerable GetConditionalStaticDependencies(NodeFactory factory) => null; + public override IEnumerable SearchDynamicDependencies(List> markedNodes, int firstNode, NodeFactory factory) => null; + + } +} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectGetTypeFlowDependenciesNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectGetTypeFlowDependenciesNode.cs index a30e1a7dc3c55..49fa353f50e55 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectGetTypeFlowDependenciesNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ObjectGetTypeFlowDependenciesNode.cs @@ -6,6 +6,8 @@ using ILCompiler.DependencyAnalysisFramework; +using ILLink.Shared.TrimAnalysis; + using Internal.TypeSystem; namespace ILCompiler.DependencyAnalysis @@ -25,21 +27,31 @@ public ObjectGetTypeFlowDependenciesNode(MetadataType type) protected override string GetName(NodeFactory factory) { - return $"Object.GetType dependencies called on {_type}"; + return $"Object.GetType dependencies for {_type}"; } public override IEnumerable GetStaticDependencies(NodeFactory factory) { var mdManager = (UsageBasedMetadataManager)factory.MetadataManager; + FlowAnnotations flowAnnotations = mdManager.FlowAnnotations; + + DependencyList result = Dataflow.ReflectionMethodBodyScanner.ProcessTypeGetTypeDataflow(factory, mdManager.FlowAnnotations, mdManager.Logger, _type); + + MetadataType baseType = _type.MetadataBaseType; + if (baseType != null && flowAnnotations.GetTypeAnnotation(baseType) != default) + { + result.Add(factory.ObjectGetTypeFlowDependencies(baseType), "Apply annotations to bases"); + } - // We don't mark any members on interfaces - these nodes are only used as conditional dependencies - // of other nodes. Calling `object.GetType()` on something typed as an interface will return - // something that implements the interface, not the interface itself. We're not reflecting on the - // interface. - if (_type.IsInterface) - return Array.Empty(); + foreach (DefType interfaceType in _type.RuntimeInterfaces) + { + if (flowAnnotations.GetTypeAnnotation(interfaceType) != default) + { + result.Add(factory.ObjectGetTypeFlowDependencies((MetadataType)interfaceType), "Apply annotations to interfaces"); + } + } - return Dataflow.ReflectionMethodBodyScanner.ProcessTypeGetTypeDataflow(factory, mdManager.FlowAnnotations, mdManager.Logger, _type); + return result; } public override bool InterestingForDynamicDependencyAnalysis => false; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs index a301d770dc018..fd0c4e025d65e 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs @@ -408,9 +408,19 @@ public override void GetConditionalDependenciesDueToEETypePresence(ref CombinedD { // Check to see if we have any dataflow annotations on the type. // The check below also covers flow annotations inherited through base classes and implemented interfaces. - if (type.IsDefType - && !type.IsInterface /* "IFoo x; x.GetType();" -> this doesn't actually return an interface type */ - && FlowAnnotations.GetTypeAnnotation(type) != default) + bool hasFlowAnnotations = type.IsDefType && FlowAnnotations.GetTypeAnnotation(type) != default; + + if (hasFlowAnnotations) + { + dependencies ??= new CombinedDependencyList(); + dependencies.Add(new DependencyNodeCore.CombinedDependencyListEntry( + factory.ObjectGetTypeFlowDependencies((MetadataType)type), + factory.ObjectGetTypeCalled((MetadataType)type), + "Type exists and GetType called on it")); + } + + if (hasFlowAnnotations + && !type.IsInterface /* "IFoo x; x.GetType();" -> this doesn't actually return an interface type */) { // We have some flow annotations on this type. // @@ -428,8 +438,8 @@ public override void GetConditionalDependenciesDueToEETypePresence(ref CombinedD // Ensure we have the flow dependencies. dependencies ??= new CombinedDependencyList(); dependencies.Add(new DependencyNodeCore.CombinedDependencyListEntry( - factory.ObjectGetTypeFlowDependencies((MetadataType)type), - factory.ObjectGetTypeFlowDependencies((MetadataType)baseType), + factory.ObjectGetTypeCalled((MetadataType)type), + factory.ObjectGetTypeCalled((MetadataType)baseType), "GetType called on the base type")); // We don't have to follow all the bases since the base MethodTable will bubble this up @@ -444,8 +454,8 @@ public override void GetConditionalDependenciesDueToEETypePresence(ref CombinedD // Ensure we have the flow dependencies. dependencies ??= new CombinedDependencyList(); dependencies.Add(new DependencyNodeCore.CombinedDependencyListEntry( - factory.ObjectGetTypeFlowDependencies((MetadataType)type), - factory.ObjectGetTypeFlowDependencies((MetadataType)interfaceType), + factory.ObjectGetTypeCalled((MetadataType)type), + factory.ObjectGetTypeCalled((MetadataType)interfaceType), "GetType called on the interface")); } diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index 29a917f01c68c..954ae4124058a 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -428,6 +428,7 @@ + diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs index a75ca2bcd0c4f..dbdbcae08372e 100644 --- a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs @@ -565,10 +565,7 @@ public static void Run() // so that we can tests this doesn't lead to keeping the type. Assert.Equal(666, s_neverAllocatedTypeAskingForNonPublicMethods.GetType().CountMethods()); } - // This is not great - the GetType() call above "wished" NeverAllocatedTypeAskingForNonPublicMethods - // into existence, but it shouldn't have. We could do better here if this is a problem. - // If we do that, change this .NotNull to .Null. - Assert.NotNull(typeof(TestObjectGetTypeDataflow).GetNestedTypeSecretly(nameof(NeverAllocatedTypeAskingForNonPublicMethods))); + Assert.Null(typeof(TestObjectGetTypeDataflow).GetNestedTypeSecretly(nameof(NeverAllocatedTypeAskingForNonPublicMethods))); // Sanity check Assert.NotNull(typeof(TestObjectGetTypeDataflow).GetNestedTypeSecretly(nameof(TypeWithNonPublicMethodsKept))); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs index 71c1999c9600f..a90bee0d79c6e 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/ObjectGetTypeDataflow.cs @@ -18,6 +18,7 @@ public static void Main () { SealedConstructorAsSource.Test (); InstantiatedGenericAsSource.Test (); + InstantiatedGenericAsSourceInstantiated.Test (); EnumTypeSatisfiesPublicFields.Test (); EnumConstraintSatisfiesPublicFields.Test (); InstantiatedTypeParameterAsSource.Test (); @@ -50,15 +51,15 @@ class InstantiatedGenericAsSource { [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] class Generic { - [ExpectedWarning ("IL2112")] + [ExpectedWarning ("IL2112", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/110563")] [RequiresUnreferencedCode (nameof (KeptForMethodParameter))] public void KeptForMethodParameter () {} - [ExpectedWarning ("IL2112")] + [ExpectedWarning ("IL2112", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/110563")] [RequiresUnreferencedCode (nameof (KeptForField))] public void KeptForField () {} - [ExpectedWarning ("IL2112")] + [ExpectedWarning ("IL2112", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/110563")] [RequiresUnreferencedCode (nameof (KeptJustBecause))] public void KeptJustBecause () {} } @@ -82,6 +83,43 @@ public static void Test () } } + class InstantiatedGenericAsSourceInstantiated + { + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + class Generic + { + [ExpectedWarning ("IL2112")] + [RequiresUnreferencedCode (nameof (KeptForMethodParameter))] + public void KeptForMethodParameter () { } + + [ExpectedWarning ("IL2112")] + [RequiresUnreferencedCode (nameof (KeptForField))] + public void KeptForField () { } + + [ExpectedWarning ("IL2112")] + [RequiresUnreferencedCode (nameof (KeptJustBecause))] + public void KeptJustBecause () { } + } + + static void TestMethodParameter (Generic instance) + { + instance.GetType ().GetMethod ("KeptForMethodParameter"); + } + + static Generic field = new Generic (); + + static void TestField () + { + field.GetType ().GetMethod ("KeptForField"); + } + + public static void Test () + { + TestMethodParameter (null); + TestField (); + } + } + class EnumTypeSatisfiesPublicFields { static void ParameterType (Enum instance) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/InstantiatedGenericEquality.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/InstantiatedGenericEquality.cs index 2c9b69c9df973..1fe5fb5be8521 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/InstantiatedGenericEquality.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Generics/InstantiatedGenericEquality.cs @@ -18,11 +18,11 @@ public static void Main () class GenericReturnType { - [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute), By = Tool.Trimmer /* Type is needed due to IL metadata only */)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] class ReturnType { - [Kept] + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] public void Method () { } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs index 58090e4ec1c51..0152323e9ef3c 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ObjectGetType.cs @@ -1582,16 +1582,46 @@ public static void Test () } } - class AnnotatedDerived + class AnnotatedBaseInstantiated { [Kept] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + [KeptMember (".ctor()")] class Base { [Kept] public void Method () { } } - [Kept (By = Tool.Trimmer /* The object.GetType() call is statically unreachable, this could be trimmed */)] + [Kept] + [KeptBaseType (typeof (Base), By = Tool.Trimmer)] + [KeptMember (".ctor()")] + class Derived : Base + { + } + + [Kept] + static Derived derivedInstance; + + [Kept] + public static void Test () + { + derivedInstance = new Derived (); + derivedInstance.GetType ().RequiresPublicMethods (); + } + } + + class AnnotatedDerived + { + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] + class Base + { + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] + public void Method () { } + } + + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] [KeptBaseType (typeof (Base), By = Tool.Trimmer)] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute), By = Tool.Trimmer)] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] @@ -1609,14 +1639,73 @@ public static void Test () } } + class AnnotatedDerivedInstantiated + { + [Kept] + [KeptMember (".ctor()")] + class Base + { + [Kept] + public void Method () { } + } + + [Kept] + [KeptBaseType (typeof (Base))] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] + [KeptMember (".ctor()")] + class Derived : Base + { + } + + [Kept] + static Derived derivedInstance; + + [Kept] + public static void Test () + { + derivedInstance = new Derived (); + derivedInstance.GetType ().RequiresPublicMethods (); + } + } + class AnnotatedInterface + { + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute), By = Tool.Trimmer)] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] + interface IBase + { + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] + public void Method () { } + } + + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] + [KeptMember (".ctor()", By = Tool.Trimmer)] + [KeptInterface (typeof (IBase), By = Tool.Trimmer)] + class Implementation : IBase + { + } + + [Kept] + static Implementation implementationInstance; + + [Kept] + public static void Test () + { + var a = implementationInstance as IBase; + implementationInstance.GetType ().RequiresPublicMethods (); + } + } + + class AnnotatedInterfaceInstantiated { [Kept] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] interface IBase { - [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/104740 */)] + [Kept] public void Method () { } } @@ -1640,6 +1729,35 @@ public static void Test () } class AnnotatedImplementation + { + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] + interface IBase + { + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] + public void Method () { } + } + + [Kept (By = Tool.Trimmer /* https://github.com/dotnet/runtime/issues/110563 */)] + [KeptMember (".ctor()", By = Tool.Trimmer)] + [KeptInterface (typeof (IBase), By = Tool.Trimmer)] + [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute), By = Tool.Trimmer)] + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)] + class Implementation : IBase + { + } + + [Kept] + static Implementation implementationInstance; + + [Kept] + public static void Test () + { + var a = implementationInstance as IBase; + implementationInstance.GetType ().RequiresPublicMethods (); + } + } + + class AnnotatedImplementationInstantiated { [Kept] interface IBase @@ -1672,10 +1790,14 @@ public static void Test () [Kept] public static void Test () { - AnnotatedBase.Test (); ; + AnnotatedBase.Test (); + AnnotatedBaseInstantiated.Test (); AnnotatedDerived.Test (); + AnnotatedDerivedInstantiated.Test (); AnnotatedInterface.Test (); + AnnotatedInterfaceInstantiated.Test (); AnnotatedImplementation.Test (); + AnnotatedImplementationInstantiated.Test (); } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs index bded9f86c640e..1fe8f1fb82730 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchyReflectionWarnings.cs @@ -17,6 +17,7 @@ namespace Mono.Linker.Tests.Cases.Reflection [SkipKeptItemsValidation (By = Tool.NativeAot)] public class TypeHierarchyReflectionWarnings { + [ExpectedWarning ("IL2026", "--AnnotatedRUCPublicMethods--")] public static void Main () { annotatedBase.GetType ().RequiresPublicMethods (); @@ -45,8 +46,15 @@ public static void Main () var t7 = typeof (DerivedFromAnnotatedPublicParameterlessConstructor); annotatedRUCPublicMethods.GetType ().RequiresPublicMethods (); - // Instantiate this type just so its property getters are considered reachable - var b = new DerivedFromAnnotatedDerivedFromBase (); + // Instantiate these types just so things are considered reachable + _ = new DerivedFromAnnotatedDerivedFromBase (); + _ = new AnnotatedPublicMethods (); + _ = new AnnotatedPublicFields (); + _ = new AnnotatedPublicEvents (); + _ = new AnnotatedPublicProperties (); + _ = new AnnotatedInterfaces (); + _ = new AnnotatedPublicNestedTypes (); + _ = new AnnotatedRUCPublicMethods (); // Check that this field doesn't produce a warning even if it is kept // for some non-reflection access. @@ -62,8 +70,8 @@ public static void Main () RucOnVirtualOnAnnotatedInterfaceUsedByImplementation.Test (); UseByDerived.Test (); - CompilerGeneratedCodeRUC.Test (null); - CompilerGeneratedCodeDAM.Test (null); + CompilerGeneratedCodeRUC.Test (new CompilerGeneratedCodeRUC ()); + CompilerGeneratedCodeDAM.Test (new CompilerGeneratedCodeDAM ()); } [Kept] @@ -152,6 +160,7 @@ class DerivedFromAnnotatedAllWithInterface : AnnotatedAll, InterfaceImplementedB } [Kept] + [KeptMember (".ctor()")] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] class AnnotatedPublicMethods @@ -204,6 +213,7 @@ Type type } [Kept] + [KeptMember (".ctor()")] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] class AnnotatedPublicFields @@ -217,6 +227,7 @@ class AnnotatedPublicFields } [Kept] + [KeptMember (".ctor()")] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] class AnnotatedPublicProperties @@ -237,6 +248,7 @@ public static string DAMProperty { } [Kept] + [KeptMember (".ctor()")] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicEvents)] class AnnotatedPublicEvents @@ -272,6 +284,7 @@ interface RequiredInterface } [Kept] + [KeptMember (".ctor()")] [KeptInterface (typeof (RequiredInterface))] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.Interfaces)] @@ -497,6 +510,7 @@ public class BaseTypeOfNestedType public void RUCMethod () { } } + [KeptMember (".ctor()")] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicNestedTypes)] // Warnings about base types of nested types are shown at the (outer) type level. @@ -595,6 +609,7 @@ public class NestedType : AnnotatedBaseSharedByNestedTypes [RequiresUnreferencedCode ("--AnnotatedRUCPublicMethods--")] public class AnnotatedRUCPublicMethods { + [Kept] public AnnotatedRUCPublicMethods () { } [Kept] @@ -702,7 +717,7 @@ public class Base [Kept] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode ("--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--")] - [ExpectedWarning ("IL2112", "--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/104740")] + [ExpectedWarning ("IL2112", "--RUCOnVirtualMethodDerivedAnnotated.Base.RUCVirtualMethod--")] public virtual void RUCVirtualMethod () { } } @@ -740,7 +755,7 @@ public interface Interface [Kept] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode ("--RUCOnVirtualOnAnnotatedInterface.Interface.RUCVirtualMethod--")] - [ExpectedWarning ("IL2112", "--RUCOnVirtualOnAnnotatedInterface.Interface.RUCVirtualMethod--", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/104740")] + [ExpectedWarning ("IL2112", "--RUCOnVirtualOnAnnotatedInterface.Interface.RUCVirtualMethod--")] void RUCVirtualMethod () { } } @@ -778,7 +793,7 @@ public interface Interface [Kept] [KeptAttributeAttribute (typeof (RequiresUnreferencedCodeAttribute))] [RequiresUnreferencedCode ("--RucOnVirtualOnAnnotatedInterfaceUsedByImplementation.Interface.RUCVirtualMethod--")] - [ExpectedWarning ("IL2112", "--RucOnVirtualOnAnnotatedInterfaceUsedByImplementation.Interface.RUCVirtualMethod--", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/104740")] + [ExpectedWarning ("IL2112", "--RucOnVirtualOnAnnotatedInterfaceUsedByImplementation.Interface.RUCVirtualMethod--")] void RUCVirtualMethod () { } } @@ -821,7 +836,7 @@ class AnnotatedBase [RequiresUnreferencedCode ("--AnnotatedBase.VirtualMethodWithRequires--")] [RequiresDynamicCode ("--AnnotatedBase.VirtualMethodWithRequires--")] [RequiresAssemblyFiles ("--AnnotatedBase.VirtualMethodWithRequires--")] - [ExpectedWarning ("IL2112", "--AnnotatedBase.VirtualMethodWithRequires--", Tool.Trimmer | Tool.Analyzer, "https://github.com/dotnet/runtime/issues/104740")] + [ExpectedWarning ("IL2112", "--AnnotatedBase.VirtualMethodWithRequires--")] public virtual void VirtualMethodWithRequires () { } } @@ -900,6 +915,7 @@ public static void Test () class CompilerGeneratedBackingField { [Kept] + [KeptMember (".ctor()")] public class BaseWithField { [KeptBackingField] @@ -908,6 +924,7 @@ public class BaseWithField } [Kept] + [KeptMember (".ctor()")] [KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] [KeptBaseType (typeof (BaseWithField))] [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicFields)] @@ -923,6 +940,7 @@ public class DerivedWithAnnotation : BaseWithField [Kept] public static void Test () { + derivedInstance = new DerivedWithAnnotation (); derivedInstance.GetType ().RequiresNonPublicFields (); } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchySuppressions.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchySuppressions.cs index 49d9b13bf9ca9..2120d4afea237 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchySuppressions.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/TypeHierarchySuppressions.cs @@ -27,6 +27,7 @@ public static void Main () // derived types to access annotated methods without any warnings: derivedFromSuppressed.GetType ().GetMethod ("RUCDerivedMethod"); + _ = new AnnotatedAllSuppressed (); } [Kept] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs index f9a97cfffdccd..da4fbcd59c330 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresOnClass.cs @@ -821,13 +821,15 @@ static void TestDAMAccessOnInstantiatedGeneric () } [ExpectedWarning ("IL2026", "--TestDAMOnTypeAccessInRUCScope--")] + [ExpectedWarning ("IL2026", "DAMAnnotatedClass.DAMAnnotatedClass()")] + [ExpectedWarning ("IL3050", "DAMAnnotatedClass.DAMAnnotatedClass()", Tool.NativeAot | Tool.Analyzer, "")] public static void Test () { TestDAMAccess (); TestDirectReflectionAccess (); TestDynamicDependencyAccess (); - TestDAMOnTypeAccess (null); - TestDAMOnTypeAccessInRUCScope (); + TestDAMOnTypeAccess (new DAMAnnotatedClass ()); + TestDAMOnTypeAccessInRUCScope (new DAMAnnotatedClassAccessedFromRUCScope ()); TestDAMAccessOnOpenGeneric (); TestDAMAccessOnInstantiatedGeneric (); } @@ -1208,12 +1210,14 @@ static void TestDAMOnTypeAccess (DAMAnnotatedClass instance) instance.GetType ().GetProperty ("publicProperty"); } + [ExpectedWarning ("IL2026", "DAMAnnotatedClass.DAMAnnotatedClass()")] + [ExpectedWarning ("IL3050", "DAMAnnotatedClass.DAMAnnotatedClass()", Tool.NativeAot | Tool.Analyzer, "")] public static void Test () { TestDAMAccess (); TestDirectReflectionAccess (); TestDynamicDependencyAccess (); - TestDAMOnTypeAccess (null); + TestDAMOnTypeAccess (new DAMAnnotatedClass ()); } }