Fixes remaining issues with DynamicDependency attribute and adds tests (#79398)
authorVitek Karas <10670590+vitek-karas@users.noreply.github.com>
Mon, 12 Dec 2022 10:33:54 +0000 (02:33 -0800)
committerGitHub <noreply@github.com>
Mon, 12 Dec 2022 10:33:54 +0000 (02:33 -0800)
Ports over all DynamicDependencyAttribute tests we have in linker. All tests are now passing, two had to be partially disabled due to:
* copyused testing which NativeAOT doesn't really support
* known missing support for XML attribute files in AOT

Product changes:
* DynamicDependencyAttribute will produce a warning if it can't resolve the target of the dependency.
* Support for DynamicDependencyAttribute on fields

Small improvements to assembly checker - mainly ability to handle delegate types.

Add tests for reflection-only accessed fields and methods and DynamicDependency on them. Fixed the problem with those tests by also hooking up FieldMetadataNote and MethodMetadataNode.

46 files changed:
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/DynamicDependencyAttributeAlgorithm.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FieldMetadataNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/MethodMetadataNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/AssemblyDependency.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/AssemblyDependencyWithMultipleReferences.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyInCopyAssembly.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/FacadeAssembly.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/ImplementationLibrary.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/ReferenceImplementationLibrary.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/UnusedAssemblyDependency.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyField.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.mono.Attributes.xml [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.netcore.Attributes.xml [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.mono.Attributes.xml [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.netcore.Attributes.xml [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromCopiedAssembly.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyKeptOption.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberTypes.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssembly.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChained.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReference.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithSweptReferences.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnForwardedType.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssembly.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs [new file with mode: 0644]
src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestDatabase.cs
src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestSuites.cs
src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/AssemblyChecker.cs

index aa5f4f0..8f7130c 100644 (file)
@@ -4,12 +4,16 @@
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Reflection.Metadata;
 
 using Internal.TypeSystem;
 using Internal.TypeSystem.Ecma;
 
 using ILCompiler.Logging;
 
+using ILLink.Shared;
+
 using static ILCompiler.Dataflow.DynamicallyAccessedMembersBinder;
 
 using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
@@ -26,135 +30,188 @@ namespace ILCompiler.DependencyAnalysis
         {
             foreach (var attribute in method.GetDecodedCustomAttributes("System.Diagnostics.CodeAnalysis", "DynamicDependencyAttribute"))
             {
-                IEnumerable<TypeSystemEntity> members;
+                AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, method, method.OwningType, attribute);
+            }
+        }
 
-                static MetadataType Linkerify(TypeDesc type)
-                {
-                    // IL Linker compatibility: illink will call Resolve() that will strip parameter types and genericness
-                    // and operate on the definition.
-                    while (type.IsParameterizedType)
-                        type = ((ParameterizedType)type).ParameterType;
-                    return (MetadataType)type.GetTypeDefinition();
-                }
+        public static void AddDependenciesDueToDynamicDependencyAttribute(ref DependencyList dependencies, NodeFactory factory, EcmaField field)
+        {
+            foreach (var attribute in field.GetDecodedCustomAttributes("System.Diagnostics.CodeAnalysis", "DynamicDependencyAttribute"))
+            {
+                AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, field, field.OwningType, attribute);
+            }
+        }
 
-                // First figure out the list of members that this maps to.
-                // These are the ways to specify the members:
-                //
-                // * A string that contains a documentation signature
-                // * DynamicallyAccessedMembers enum
+        private static void AddDependenciesDueToDynamicDependencyAttribute(
+            ref DependencyList dependencies,
+            NodeFactory factory,
+            TypeSystemEntity entity,
+            TypeDesc owningType,
+            CustomAttributeValue<TypeDesc> attribute)
+        {
+            IEnumerable<TypeSystemEntity> members;
 
-                var fixedArgs = attribute.FixedArguments;
-                TypeDesc targetType;
+            static MetadataType Linkerify(TypeDesc type)
+            {
+                // IL Linker compatibility: illink will call Resolve() that will strip parameter types and genericness
+                // and operate on the definition.
+                while (type.IsParameterizedType)
+                    type = ((ParameterizedType)type).ParameterType;
+                return (MetadataType)type.GetTypeDefinition();
+            }
 
-                if (fixedArgs.Length > 0 && fixedArgs[0].Value is string sigFromAttribute)
+            // First figure out the list of members that this maps to.
+            // These are the ways to specify the members:
+            //
+            // * A string that contains a documentation signature
+            // * DynamicallyAccessedMembers enum
+
+            var fixedArgs = attribute.FixedArguments;
+            TypeDesc targetType;
+
+            if (fixedArgs.Length > 0 && fixedArgs[0].Value is string sigFromAttribute)
+            {
+                switch (fixedArgs.Length)
                 {
-                    if (fixedArgs.Length == 1)
-                    {
-                        // DynamicDependencyAttribute(String)
-                        targetType = method.OwningType;
-                    }
-                    else if (fixedArgs.Length == 2 && fixedArgs[1].Value is TypeDesc typeFromAttribute)
-                    {
-                        // DynamicDependencyAttribute(String, Type)
+                    // DynamicDependencyAttribute(String)
+                    case 1:
+                        targetType = owningType;
+                        break;
+
+                    // DynamicDependencyAttribute(String, Type)
+                    case 2 when fixedArgs[1].Value is TypeDesc typeFromAttribute:
                         targetType = typeFromAttribute;
-                    }
-                    else if (fixedArgs.Length == 3 && fixedArgs[1].Value is string typeStringFromAttribute
-                        && fixedArgs[2].Value is string assemblyStringFromAttribute)
-                    {
-                        // DynamicDependencyAttribute(String, String, String)
+                        break;
+
+                    // DynamicDependencyAttribute(String, String, String)
+                    case 3 when fixedArgs[1].Value is string typeStringFromAttribute
+                        && fixedArgs[2].Value is string assemblyStringFromAttribute:
                         ModuleDesc asm = factory.TypeSystemContext.ResolveAssembly(new System.Reflection.AssemblyName(assemblyStringFromAttribute), throwIfNotFound: false);
                         if (asm == null)
                         {
-                            // _context.LogWarning($"Unresolved assembly '{dynamicDependency.AssemblyName}' in 'DynamicDependencyAttribute'", 2035, context);
-                            continue;
+                            ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
+                                new MessageOrigin(entity),
+                                DiagnosticId.UnresolvedAssemblyInDynamicDependencyAttribute,
+                                assemblyStringFromAttribute);
+                            return;
                         }
 
                         targetType = DocumentationSignatureParser.GetTypeByDocumentationSignature((IAssemblyDesc)asm, typeStringFromAttribute);
                         if (targetType == null)
                         {
-                            // _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute", 2036, context);
-                            continue;
+                            ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
+                                new MessageOrigin(entity),
+                                DiagnosticId.UnresolvedTypeInDynamicDependencyAttribute,
+                                typeStringFromAttribute);
+                            return;
                         }
-                    }
-                    else
-                    {
+                        break;
+
+                    default:
                         Debug.Fail("Did we introduce a new overload?");
-                        continue;
-                    }
+                        return;
+                }
+
+                members = DocumentationSignatureParser.GetMembersByDocumentationSignature(Linkerify(targetType), sigFromAttribute, acceptName: true);
 
-                    members = DocumentationSignatureParser.GetMembersByDocumentationSignature(Linkerify(targetType), sigFromAttribute, acceptName: true);
+                if (!members.Any())
+                {
+                    ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
+                        new MessageOrigin(entity),
+                        DiagnosticId.NoMembersResolvedForMemberSignatureOrType,
+                        sigFromAttribute,
+                        targetType.GetDisplayName());
+                    return;
                 }
-                else if (fixedArgs.Length > 0 && fixedArgs[0].Value is int memberTypesFromAttribute)
+            }
+            else if (fixedArgs.Length > 0 && fixedArgs[0].Value is int memberTypesFromAttribute)
+            {
+                if (fixedArgs.Length == 2 && fixedArgs[1].Value is TypeDesc typeFromAttribute)
+                {
+                    // DynamicDependencyAttribute(DynamicallyAccessedMemberTypes, Type)
+                    targetType = typeFromAttribute;
+                }
+                else if (fixedArgs.Length == 3 && fixedArgs[1].Value is string typeStringFromAttribute
+                    && fixedArgs[2].Value is string assemblyStringFromAttribute)
                 {
-                    if (fixedArgs.Length == 2 && fixedArgs[1].Value is TypeDesc typeFromAttribute)
+                    // DynamicDependencyAttribute(DynamicallyAccessedMemberTypes, String, String)
+                    ModuleDesc asm = factory.TypeSystemContext.ResolveAssembly(new System.Reflection.AssemblyName(assemblyStringFromAttribute), throwIfNotFound: false);
+                    if (asm == null)
                     {
-                        // DynamicDependencyAttribute(DynamicallyAccessedMemberTypes, Type)
-                        targetType = typeFromAttribute;
+                        ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
+                            new MessageOrigin(entity),
+                            DiagnosticId.UnresolvedAssemblyInDynamicDependencyAttribute,
+                            assemblyStringFromAttribute);
+                        return;
                     }
-                    else if (fixedArgs.Length == 3 && fixedArgs[1].Value is string typeStringFromAttribute
-                        && fixedArgs[2].Value is string assemblyStringFromAttribute)
-                    {
-                        // DynamicDependencyAttribute(DynamicallyAccessedMemberTypes, String, String)
-                        ModuleDesc asm = factory.TypeSystemContext.ResolveAssembly(new System.Reflection.AssemblyName(assemblyStringFromAttribute), throwIfNotFound: false);
-                        if (asm == null)
-                        {
-                            // _context.LogWarning($"Unresolved assembly '{dynamicDependency.AssemblyName}' in 'DynamicDependencyAttribute'", 2035, context);
-                            continue;
-                        }
 
-                        targetType = DocumentationSignatureParser.GetTypeByDocumentationSignature((IAssemblyDesc)asm, typeStringFromAttribute);
-                        if (targetType == null)
-                        {
-                            // _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute", 2036, context);
-                            continue;
-                        }
-                    }
-                    else
+                    targetType = DocumentationSignatureParser.GetTypeByDocumentationSignature((IAssemblyDesc)asm, typeStringFromAttribute);
+                    if (targetType == null)
                     {
-                        Debug.Fail("Did we introduce a new overload?");
-                        continue;
+                        ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
+                            new MessageOrigin(entity),
+                            DiagnosticId.UnresolvedTypeInDynamicDependencyAttribute,
+                            typeStringFromAttribute);
+                        return;
                     }
-
-                    members = Linkerify(targetType).GetDynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)memberTypesFromAttribute);
                 }
                 else
                 {
                     Debug.Fail("Did we introduce a new overload?");
-                    continue;
+                    return;
                 }
 
-                const string reason = "DynamicDependencyAttribute";
+                members = Linkerify(targetType).GetDynamicallyAccessedMembers((DynamicallyAccessedMemberTypes)memberTypesFromAttribute);
 
-                // Now root the discovered members
-                foreach (var member in members)
+                if (!members.Any())
                 {
-                    switch (member)
-                    {
-                        case MethodDesc m:
-                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, m, reason);
-                            break;
-                        case FieldDesc field:
-                            RootingHelpers.TryGetDependenciesForReflectedField(ref dependencies, factory, field, reason);
-                            break;
-                        case MetadataType nestedType:
-                            RootingHelpers.TryGetDependenciesForReflectedType(ref dependencies, factory, nestedType, reason);
-                            break;
-                        case PropertyPseudoDesc property:
-                            if (property.GetMethod != null)
-                                RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, property.GetMethod, reason);
-                            if (property.SetMethod != null)
-                                RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, property.SetMethod, reason);
-                            break;
-                        case EventPseudoDesc @event:
-                            if (@event.AddMethod != null)
-                                RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, @event.AddMethod, reason);
-                            if (@event.RemoveMethod != null)
-                                RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, @event.RemoveMethod, reason);
-                            break;
-                        default:
-                            Debug.Fail(member.GetType().ToString());
-                            break;
-                    }
+                    ((UsageBasedMetadataManager)factory.MetadataManager).Logger.LogWarning(
+                    new MessageOrigin(entity),
+                        DiagnosticId.NoMembersResolvedForMemberSignatureOrType,
+                        memberTypesFromAttribute.ToString(),
+                        targetType.GetDisplayName());
+                    return;
+                }
+            }
+            else
+            {
+                Debug.Fail("Did we introduce a new overload?");
+                return;
+            }
+
+            Debug.Assert(members.Any());
+
+            const string reason = "DynamicDependencyAttribute";
+
+            // Now root the discovered members
+            foreach (var member in members)
+            {
+                switch (member)
+                {
+                    case MethodDesc m:
+                        RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, m, reason);
+                        break;
+                    case FieldDesc field:
+                        RootingHelpers.TryGetDependenciesForReflectedField(ref dependencies, factory, field, reason);
+                        break;
+                    case MetadataType nestedType:
+                        RootingHelpers.TryGetDependenciesForReflectedType(ref dependencies, factory, nestedType, reason);
+                        break;
+                    case PropertyPseudoDesc property:
+                        if (property.GetMethod != null)
+                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, property.GetMethod, reason);
+                        if (property.SetMethod != null)
+                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, property.SetMethod, reason);
+                        break;
+                    case EventPseudoDesc @event:
+                        if (@event.AddMethod != null)
+                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, @event.AddMethod, reason);
+                        if (@event.RemoveMethod != null)
+                            RootingHelpers.TryGetDependenciesForReflectedMethod(ref dependencies, factory, @event.RemoveMethod, reason);
+                        break;
+                    default:
+                        Debug.Fail(member.GetType().ToString());
+                        break;
                 }
             }
         }
index 8cf60ae..d00ef89 100644 (file)
@@ -37,6 +37,11 @@ namespace ILCompiler.DependencyAnalysis
 
             CustomAttributeBasedDependencyAlgorithm.AddDependenciesDueToCustomAttributes(ref dependencies, factory, ((EcmaField)_field));
 
+            if (_field is EcmaField ecmaField)
+            {
+                DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
+            }
+
             return dependencies;
         }
         protected override string GetName(NodeFactory factory)
index 723f9e0..6f5b542 100644 (file)
@@ -45,6 +45,11 @@ namespace ILCompiler.DependencyAnalysis
                 TypeMetadataNode.GetMetadataDependencies(ref dependencies, factory, paramType, reason);
             }
 
+            if (_method is EcmaMethod ecmaMethod)
+            {
+                DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaMethod);
+            }
+
             return dependencies;
         }
         protected override string GetName(NodeFactory factory)
index 8144079..be19078 100644 (file)
@@ -743,6 +743,11 @@ namespace ILCompiler
                 dependencies ??= new DependencyList();
                 dependencies.Add(factory.ReflectableField(fieldToReport), reason);
             }
+
+            if (writtenField.GetTypicalFieldDefinition() is EcmaField ecmaField)
+            {
+                DynamicDependencyAttributeAlgorithm.AddDependenciesDueToDynamicDependencyAttribute(ref dependencies, factory, ecmaField);
+            }
         }
 
         public override void GetDependenciesDueToAccess(ref DependencyList dependencies, NodeFactory factory, MethodIL methodIL, MethodDesc calledMethod)
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/AssemblyDependency.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/AssemblyDependency.cs
new file mode 100644 (file)
index 0000000..a14adca
--- /dev/null
@@ -0,0 +1,17 @@
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class AssemblyDependency
+       {
+               public AssemblyDependency ()
+               {
+               }
+
+               public static void UsedToKeepReferenceAtCompileTime ()
+               {
+               }
+
+               class TypeThatIsUsedViaReflection
+               {
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/AssemblyDependencyWithMultipleReferences.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/AssemblyDependencyWithMultipleReferences.cs
new file mode 100644 (file)
index 0000000..ca78054
--- /dev/null
@@ -0,0 +1,10 @@
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class AssemblyDependencyWithReference : AssemblyDependency
+       {
+       }
+
+       public class UsedToReferenceUnusedAssembly : UnusedAssemblyDependency
+       {
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary.cs
new file mode 100644 (file)
index 0000000..060995f
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+#if METHOD
+       public class DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary_Method
+#else
+       public class DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary_Field
+#endif
+       {
+               public static void Method ()
+               {
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyInCopyAssembly.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyInCopyAssembly.cs
new file mode 100644 (file)
index 0000000..c505c2c
--- /dev/null
@@ -0,0 +1,18 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class DynamicDependencyInCopyAssembly
+       {
+               [DynamicDependency ("ExtraMethod1")]
+               public DynamicDependencyInCopyAssembly ()
+               {
+               }
+
+               static void ExtraMethod1 ()
+               {
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs
new file mode 100644 (file)
index 0000000..fc625b8
--- /dev/null
@@ -0,0 +1,16 @@
+using System;
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class DynamicDependencyMethodInAssemblyLibrary
+       {
+               public DynamicDependencyMethodInAssemblyLibrary ()
+               {
+               }
+
+               private void Foo ()
+               {
+               }
+
+               private int privateField;
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs
new file mode 100644 (file)
index 0000000..33910f8
--- /dev/null
@@ -0,0 +1,7 @@
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public abstract class DynamicDependencyMethodInNonReferencedAssemblyBase
+       {
+               public abstract string Method ();
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs
new file mode 100644 (file)
index 0000000..12a1569
--- /dev/null
@@ -0,0 +1,10 @@
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class DynamicDependencyMethodInNonReferencedAssemblyBase2 : DynamicDependencyMethodInNonReferencedAssemblyBase
+       {
+               public override string Method ()
+               {
+                       return "Base2";
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs
new file mode 100644 (file)
index 0000000..2aeca1b
--- /dev/null
@@ -0,0 +1,19 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary : DynamicDependencyMethodInNonReferencedAssemblyBase
+       {
+               public override string Method ()
+               {
+                       Dependency ();
+                       return "Dependency";
+               }
+
+               [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyBase2", "base2")]
+               public static void Dependency ()
+               {
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs
new file mode 100644 (file)
index 0000000..d0392bb
--- /dev/null
@@ -0,0 +1,11 @@
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary : DynamicDependencyMethodInNonReferencedAssemblyBase
+       {
+               public override string Method ()
+               {
+                       DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.Dependency ();
+                       return "Dependency";
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs
new file mode 100644 (file)
index 0000000..b2d1f08
--- /dev/null
@@ -0,0 +1,14 @@
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class DynamicDependencyMethodInNonReferencedAssemblyLibrary : DynamicDependencyMethodInNonReferencedAssemblyBase
+       {
+               public override string Method ()
+               {
+                       return "Dependency";
+               }
+
+               private void UnusedMethod ()
+               {
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml
new file mode 100644 (file)
index 0000000..cdfc173
--- /dev/null
@@ -0,0 +1,5 @@
+<linker>
+    <assembly fullname="DynamicDependencyMethodInNonReferencedAssemblyLibrary, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+        <type fullname="Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary" preserve="all" />
+    </assembly>
+</linker>
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs
new file mode 100644 (file)
index 0000000..e74ee73
--- /dev/null
@@ -0,0 +1,9 @@
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib
+       {
+               public static void MethodPreservedViaDependencyAttribute ()
+               {
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/FacadeAssembly.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/FacadeAssembly.cs
new file mode 100644 (file)
index 0000000..128a6cb
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System.Runtime.CompilerServices;
+
+[assembly: TypeForwardedTo (typeof (Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.ImplementationLibrary))]
+[assembly: TypeForwardedTo (typeof (Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.ImplementationLibraryGenericType<,>))]
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/ImplementationLibrary.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/ImplementationLibrary.cs
new file mode 100644 (file)
index 0000000..4ec02c7
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class ImplementationLibrary
+       {
+               public class NestedType
+               {
+               }
+       }
+
+       public class ImplementationLibraryGenericType<T, S>
+       {
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/ReferenceImplementationLibrary.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/ReferenceImplementationLibrary.cs
new file mode 100644 (file)
index 0000000..55bd4c4
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       [NotATestCase]
+       public class ReferenceImplementationLibrary
+       {
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/UnusedAssemblyDependency.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/UnusedAssemblyDependency.cs
new file mode 100644 (file)
index 0000000..c9cbd81
--- /dev/null
@@ -0,0 +1,13 @@
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+       public class UnusedAssemblyDependency
+       {
+               public UnusedAssemblyDependency ()
+               {
+               }
+
+               public static void UsedToKeepReferenceAtCompileTime ()
+               {
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyField.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyField.cs
new file mode 100644 (file)
index 0000000..24265a1
--- /dev/null
@@ -0,0 +1,55 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Helpers;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       public class DynamicDependencyField
+       {
+               public static void Main ()
+               {
+                       DirectReference.Test ();
+                       ReferenceViaReflection.Test ();
+               }
+
+               [KeptMember (".ctor()")]
+               class DirectReference
+               {
+                       [Kept]
+                       [DynamicDependency ("ExtraMethod1")]
+                       public int field;
+
+                       [Kept]
+                       static void ExtraMethod1 ()
+                       {
+                       }
+
+                       [Kept]
+                       public static void Test ()
+                       {
+                               var b = new DirectReference ();
+                               b.field = 3;
+                       }
+               }
+
+               class ReferenceViaReflection
+               {
+                       [Kept]
+                       [DynamicDependency ("TargetMethod")]
+                       public static int source;
+
+                       [Kept]
+                       static void TargetMethod ()
+                       {
+                       }
+
+                       [Kept]
+                       public static void Test ()
+                       {
+                               typeof (ReferenceViaReflection).RequiresPublicFields ();
+                       }
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.cs
new file mode 100644 (file)
index 0000000..88e5701
--- /dev/null
@@ -0,0 +1,59 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       // For netcoreapp we don't have to specify the assembly for the attribute, since the attribute comes from corelib
+       // and will be found always.
+       // For mono though, we have to specify the assembly (Mono.Linker.Tests.Cases.Expectations) because at the time of processing
+       // that assembly is not yet loaded into the closure in the linker, so it won't find the attribute type.
+#if NETCOREAPP
+       [SetupLinkAttributesFile ("DynamicDependencyFromAttributeXml.netcore.Attributes.xml")]
+#else
+       [SetupLinkAttributesFile ("DynamicDependencyFromAttributeXml.mono.Attributes.xml")]
+#endif
+       [IgnoreLinkAttributes (false)]
+       [SetupLinkerArgument ("--enable-opt", "unreachablebodies", "missing.dll")]
+       class DynamicDependencyFromAttributeXml
+       {
+               public static void Main ()
+               {
+                       DependencyToUnusedMethod ();
+                       DependencyToUnusedType ();
+               }
+
+               [Kept]
+               static void DependencyToUnusedMethod ()
+               {
+               }
+
+               // https://github.com/dotnet/runtime/issues/79393
+               [Kept (By = ProducedBy.Trimmer)]
+               static void UnusedMethod ()
+               {
+               }
+
+               [Kept]
+               static void DependencyToUnusedType ()
+               {
+               }
+
+               class NonUsedType
+               {
+                       // https://github.com/dotnet/runtime/issues/79393
+                       [Kept (By = ProducedBy.Trimmer)]
+                       public NonUsedType ()
+                       {
+                       }
+
+                       // https://github.com/dotnet/runtime/issues/79393
+                       [Kept (By = ProducedBy.Trimmer)]
+                       public static void PleasePreserveThisMethod ()
+                       {
+                       }
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.mono.Attributes.xml b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.mono.Attributes.xml
new file mode 100644 (file)
index 0000000..5c47e5b
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<linker>
+       <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+               <type fullname="Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyFromAttributeXml">
+                       <method name="DependencyToUnusedMethod">
+                               <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute" assembly="Mono.Linker.Tests.Cases.Expectations">
+                                       <argument>UnusedMethod</argument>
+                               </attribute>
+                       </method>
+                       <method name="DependencyToUnusedType">
+                               <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute" assembly="Mono.Linker.Tests.Cases.Expectations">
+                                       <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes, test">All</argument>
+                                       <argument type="System.Type">Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyFromAttributeXml/NonUsedType</argument>
+                               </attribute>
+                       </method>
+               </type>
+       </assembly>
+</linker>
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.netcore.Attributes.xml b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.netcore.Attributes.xml
new file mode 100644 (file)
index 0000000..6ac2870
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<linker xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../src/ILLink.Shared/ILLink.LinkAttributes.xsd">
+  <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+    <type fullname="Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyFromAttributeXml">
+      <method name="DependencyToUnusedMethod">
+        <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute">
+          <argument>UnusedMethod</argument>
+        </attribute>
+      </method>
+      <method name="DependencyToUnusedType">
+        <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute">
+          <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">All</argument>
+          <argument type="System.Type">Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyFromAttributeXml/NonUsedType, test</argument>
+        </attribute>
+      </method>
+    </type>
+  </assembly>
+</linker>
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.cs
new file mode 100644 (file)
index 0000000..f3daf2e
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupCompileBefore ("method_library.dll", new[] { "Dependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary.cs" }, defines: new[] { "METHOD" })]
+       [SetupCompileBefore ("field_library.dll", new[] { "Dependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary.cs" }, defines: new[] { "FIELD" })]
+       [KeptAssembly ("method_library.dll")]
+       [KeptAssembly ("field_library.dll")]
+       [KeptMemberInAssembly ("method_library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary_Method", "Method()")]
+       [KeptMemberInAssembly ("field_library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary_Field", "Method()")]
+#if NETCOREAPP
+       [SetupLinkAttributesFile ("DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.netcore.Attributes.xml")]
+#else
+       [SetupLinkAttributesFile ("DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.mono.Attributes.xml")]
+#endif
+       public class DynamicDependencyFromAttributeXmlOnNonReferencedAssembly
+       {
+               public static void Main ()
+               {
+                       MethodWithDependencyInXml ();
+                       _fieldWithDependencyInXml = 0;
+               }
+
+               [Kept]
+               static void MethodWithDependencyInXml ()
+               {
+               }
+
+               [Kept]
+               static int _fieldWithDependencyInXml;
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.mono.Attributes.xml b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.mono.Attributes.xml
new file mode 100644 (file)
index 0000000..a753e7b
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<linker>
+  <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+    <type fullname="Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyFromAttributeXmlOnNonReferencedAssembly">
+      <method name="MethodWithDependencyInXml">
+        <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute" assembly="Mono.Linker.Tests.Cases.Expectations">
+          <argument>Method</argument>
+          <argument>Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary_Method</argument>
+          <argument>method_library</argument>
+        </attribute>
+      </method>
+      <field name="_fieldWithDependencyInXml">
+        <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute" assembly="Mono.Linker.Tests.Cases.Expectations">
+          <argument>Method</argument>
+          <argument>Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary_Field</argument>
+          <argument>field_library</argument>
+        </attribute>
+      </field>
+    </type>
+  </assembly>
+</linker>
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.netcore.Attributes.xml b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXmlOnNonReferencedAssembly.netcore.Attributes.xml
new file mode 100644 (file)
index 0000000..41b7660
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<linker xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../src/ILLink.Shared/ILLink.LinkAttributes.xsd">
+  <assembly fullname="test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null">
+    <type fullname="Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyFromAttributeXmlOnNonReferencedAssembly">
+      <method name="MethodWithDependencyInXml">
+        <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute">
+          <argument>Method</argument>
+          <argument>Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary_Method</argument>
+          <argument>method_library</argument>
+        </attribute>
+      </method>
+      <field name="_fieldWithDependencyInXml">
+        <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute">
+          <argument>Method</argument>
+          <argument>Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyFromAttributeXmlOnNonReferencedAssemblyLibrary_Field</argument>
+          <argument>field_library</argument>
+        </attribute>
+      </field>
+    </type>
+  </assembly>
+</linker>
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromCopiedAssembly.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromCopiedAssembly.cs
new file mode 100644 (file)
index 0000000..b5681d1
--- /dev/null
@@ -0,0 +1,23 @@
+using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupLinkerAction ("copy", "lib")]
+       [SetupCompileBefore ("lib.dll", new[] { "Dependencies/DynamicDependencyInCopyAssembly.cs" })]
+       [KeptAllTypesAndMembersInAssembly ("lib.dll")]
+       public class DynamicDependencyFromCopiedAssembly
+       {
+               public static void Main ()
+               {
+                       Test ();
+               }
+
+               [Kept]
+               static void Test ()
+               {
+                       var b = new DynamicDependencyInCopyAssembly ();
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyKeptOption.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyKeptOption.cs
new file mode 100644 (file)
index 0000000..9814d94
--- /dev/null
@@ -0,0 +1,30 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupLinkerArgument ("--keep-dep-attributes", "true")]
+       class DynamicDependencyKeptOption
+       {
+               public static void Main ()
+               {
+                       B.Test ();
+               }
+
+               class B
+               {
+                       [Kept]
+                       int field;
+
+                       [Kept]
+                       [KeptAttributeAttribute (typeof (DynamicDependencyAttribute))]
+
+                       [DynamicDependency ("field")]
+                       public static void Test ()
+                       {
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs
new file mode 100644 (file)
index 0000000..2a4bc9d
--- /dev/null
@@ -0,0 +1,24 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs" })]
+       [ExpectedNoWarnings]
+       public class DynamicDependencyMemberSignatureWildcard
+       {
+               public static void Main ()
+               {
+                       Dependency ();
+               }
+
+               [Kept]
+               [ExpectedWarning ("IL2037", "'*'", "'Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary'")]
+               [DynamicDependency ("*", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")]
+               static void Dependency ()
+               {
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberTypes.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberTypes.cs
new file mode 100644 (file)
index 0000000..f0829fa
--- /dev/null
@@ -0,0 +1,315 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       class DynamicDependencyMemberTypes
+       {
+               public static void Main ()
+               {
+                       B.Method ();
+               }
+
+               static class B
+               {
+                       [Kept]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof (TypeWithAutoImplementedPublicParameterlessConstructor))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, typeof (TypeWithPublicParameterlessConstructor))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.PublicConstructors, typeof (TypeWithPublicConstructor))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicConstructors, typeof (TypeWithNonPublicConstructor))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.PublicMethods, typeof (TypeWithPublicMethod))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicMethods, typeof (TypeWithNonPublicMethod))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.PublicFields, typeof (TypeWithPublicField))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicFields, typeof (TypeWithNonPublicField))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.PublicNestedTypes, typeof (TypeWithPublicNestedType))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicNestedTypes, typeof (TypeWithNonPublicNestedType))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.PublicProperties, typeof (TypeWithPublicProperty))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicProperties, typeof (TypeWithNonPublicProperty))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.PublicEvents, typeof (TypeWithPublicEvent))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicEvents, typeof (TypeWithNonPublicEvent))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.All, typeof (TypeWithAll))]
+                       [DynamicDependency (DynamicallyAccessedMemberTypes.None, typeof (TypeWithNone))]
+                       public static void Method ()
+                       {
+                       }
+               }
+
+
+               [KeptMember (".ctor()")]
+               class TypeWithAutoImplementedPublicParameterlessConstructor
+               {
+                       public void Method () { }
+
+                       public int field;
+               }
+
+               class TypeWithPublicParameterlessConstructor
+               {
+                       [Kept]
+                       public TypeWithPublicParameterlessConstructor () { }
+
+                       public TypeWithPublicParameterlessConstructor (int i) { }
+               }
+
+               class TypeWithPublicConstructor
+               {
+                       [Kept]
+                       public TypeWithPublicConstructor (int i) { }
+
+                       [Kept]
+                       public TypeWithPublicConstructor (string s) { }
+
+                       TypeWithPublicConstructor () { }
+               }
+
+               class TypeWithNonPublicConstructor
+               {
+                       public TypeWithNonPublicConstructor (int i) { }
+
+                       [Kept]
+                       TypeWithNonPublicConstructor () { }
+
+                       [Kept]
+                       TypeWithNonPublicConstructor (string s) { }
+               }
+
+
+               class TypeWithPublicMethod
+               {
+                       [Kept]
+                       public void PublicMethod () { }
+
+                       void PrivateMethod () { }
+
+                       public int field;
+               }
+
+               class TypeWithNonPublicMethod
+               {
+                       [Kept]
+                       void PrivateMethod () { }
+
+                       public void NonPublicMethod () { }
+               }
+
+               class TypeWithPublicField
+               {
+                       [Kept]
+                       public int publicField;
+
+                       string nonPublicField;
+
+                       public void Method () { }
+               }
+
+               class TypeWithNonPublicField
+               {
+                       [Kept]
+                       int nonPublicField;
+
+                       public string publicField;
+
+                       void Method () { }
+               }
+
+               [Kept]
+               class TypeWithPublicNestedType
+               {
+                       [Kept]
+                       [KeptMember (".ctor()")]
+                       public class PublicNestedType
+                       {
+                               [Kept]
+                               public void Method () { }
+                               [Kept]
+                               public int field;
+                               [Kept]
+                               void NonPublicMethod () { }
+                               [Kept]
+                               static class EmptyInnerNestedType { }
+                       }
+
+                       public void Method () { }
+
+                       void NonPublicMethod () { }
+
+                       class NonPublicNestedType
+                       {
+                       }
+
+                       [Kept]
+                       [KeptBaseType (typeof (MulticastDelegate))]
+                       [KeptMember (".ctor(System.Object,System.IntPtr)")]
+                       [KeptMember ("Invoke()")]
+                       [KeptMember ("BeginInvoke(System.AsyncCallback,System.Object)")]
+                       [KeptMember ("EndInvoke(System.IAsyncResult)")]
+                       public delegate int PublicDelegate ();
+
+                       private delegate int PrivateDelegate ();
+               }
+
+               [Kept]
+               class TypeWithNonPublicNestedType
+               {
+                       [Kept]
+                       [KeptMember (".ctor()")]
+                       class NonPublicNestedType
+                       {
+                               [Kept]
+                               public void Method () { }
+
+                               [Kept]
+                               public int field;
+
+                               [Kept]
+                               void NonPublicMethod () { }
+                       }
+
+                       public void Method () { }
+
+                       void NonPublicMethod () { }
+
+                       public class PublicNestedType
+                       {
+                       }
+
+                       public delegate int PublicDelegate ();
+
+                       [Kept]
+                       [KeptBaseType (typeof (MulticastDelegate))]
+                       [KeptMember (".ctor(System.Object,System.IntPtr)")]
+                       [KeptMember ("Invoke()")]
+                       [KeptMember ("BeginInvoke(System.AsyncCallback,System.Object)")]
+                       [KeptMember ("EndInvoke(System.IAsyncResult)")]
+                       private delegate int PrivateDelegate ();
+               }
+
+               class TypeWithPublicProperty
+               {
+                       [Kept]
+                       public int Property { [Kept][ExpectBodyModified] get; [Kept][ExpectBodyModified] set; }
+
+                       int NonPublicProperty { get; set; }
+
+                       public void Method () { }
+               }
+
+               class TypeWithNonPublicProperty
+               {
+                       [Kept]
+                       int NonPublicProperty { [Kept][ExpectBodyModified] get; [Kept][ExpectBodyModified] set; }
+
+                       public int PublicProperty { get; set; }
+
+                       void NonPublicMethod () { }
+               }
+
+               class TypeWithPublicEvent
+               {
+                       [Kept]
+                       [KeptEventAddMethod]
+                       [KeptEventRemoveMethod]
+                       [method: ExpectBodyModified]
+                       public event EventHandler PublicEvent;
+
+                       event EventHandler NonPublicEvent;
+
+                       public void Method () { }
+               }
+
+               class TypeWithNonPublicEvent
+               {
+                       [Kept]
+                       [KeptEventAddMethod]
+                       [KeptEventRemoveMethod]
+                       [method: ExpectBodyModified]
+                       event EventHandler NonPublicEvent;
+
+                       public event EventHandler PublicEven;
+
+                       void NonPublicMethod () { }
+               }
+
+               [KeptMember (".ctor()")]
+               class TypeWithAll
+               {
+                       [Kept]
+                       public void PublicMethod () { }
+
+                       [Kept]
+                       void NonPublicMehod () { }
+
+                       [Kept]
+                       public int publicField;
+
+                       [Kept]
+                       int nonPublicField;
+
+                       [Kept]
+                       [KeptBackingField]
+                       public int PublicProperty { [Kept] get; [Kept] set; }
+
+                       [Kept]
+                       [KeptBackingField]
+                       int NonPublicProperty { [Kept] get; [Kept] set; }
+
+                       [Kept]
+                       [KeptBackingField]
+                       [KeptEventAddMethod]
+                       [KeptEventRemoveMethod]
+                       public event EventHandler PublicEvent;
+
+                       [Kept]
+                       [KeptBackingField]
+                       [KeptEventAddMethod]
+                       [KeptEventRemoveMethod]
+                       event EventHandler NonPublicEvent;
+
+                       [Kept]
+                       [KeptMember (".ctor()")]
+                       public class PublicNestedType
+                       {
+                               [Kept]
+                               [KeptMember (".ctor()")]
+                               class RecursiveNestedType
+                               {
+                                       [Kept]
+                                       void Method () { }
+                               }
+                       }
+
+                       [Kept]
+                       [KeptMember (".ctor()")]
+                       class NonPublicNestedType
+                       {
+                               [Kept]
+                               [KeptMember (".ctor()")]
+                               class RecursiveNestedType
+                               {
+                                       [Kept]
+                                       void Method () { }
+                               }
+                       }
+
+                       [Kept]
+                       [KeptBaseType (typeof (MulticastDelegate))]
+                       [KeptMember (".ctor(System.Object,System.IntPtr)")]
+                       [KeptMember ("Invoke()")]
+                       [KeptMember ("BeginInvoke(System.AsyncCallback,System.Object)")]
+                       [KeptMember ("EndInvoke(System.IAsyncResult)")]
+                       public delegate int PublicDelegate ();
+               }
+
+               public class TypeWithNone
+               {
+                       public void Method () { }
+
+                       public int field;
+
+                       public class NestedType { }
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs
new file mode 100644 (file)
index 0000000..96a5924
--- /dev/null
@@ -0,0 +1,222 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Helpers;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       class DynamicDependencyMethod
+       {
+               public static void Main ()
+               {
+                       new B (); // Needed to avoid lazy body marking stubbing
+
+                       B.Method ();
+                       B.SameContext ();
+                       B.Broken ();
+                       B.Conditional ();
+
+                       ReferenceViaReflection.Test ();
+               }
+
+               [KeptMember (".ctor()")]
+               class B
+               {
+                       [Kept]
+                       int field;
+
+                       [Kept]
+                       void Method2 (out sbyte arg)
+                       {
+                               arg = 1;
+                       }
+
+                       [Kept]
+                       [DynamicDependency ("Dependency1()", typeof (C))]
+                       [DynamicDependency ("Dependency2``1(``0[],System.Int32", typeof (C))]
+                       [DynamicDependency ("Dependency3", typeof (C))]
+                       [DynamicDependency ("RecursiveDependency", typeof (C))]
+                       [DynamicDependency ("#ctor()", typeof (C))] // To avoid lazy body marking stubbing
+                       [DynamicDependency ("field", typeof (C))]
+                       [DynamicDependency ("NextOne(Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Nested@)", typeof (Nested))]
+                       [DynamicDependency ("#cctor()", typeof (Nested))]
+                       // Dependency on a property itself should be expressed as a dependency on one or both accessor methods
+                       [DynamicDependency ("get_Property()", typeof (C))]
+                       [DynamicDependency ("get_Property2", typeof (C))]
+                       [DynamicDependency ("M``1(Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.S{" +
+                               "Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.G{" +
+                                       "Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.A,``0}}" +
+                                       "[0:,0:,0:][][][0:,0:]@)", typeof (Complex))]
+                       public static void Method ()
+                       {
+                       }
+
+                       [Kept]
+                       [DynamicDependency ("field")]
+                       [DynamicDependency ("Method2(System.SByte@)")]
+                       public static void SameContext ()
+                       {
+                       }
+
+                       [Kept]
+
+                       [ExpectedWarning ("IL2037", "MissingMethod", "'Mono.Linker.Tests.Cases.DynamicDependencies.C'")]
+                       [DynamicDependency ("MissingMethod", typeof (C))]
+
+                       [ExpectedWarning ("IL2037", "Dependency2``1(``0,System.Int32,System.Object)", "'Mono.Linker.Tests.Cases.DynamicDependencies.C'")]
+                       [DynamicDependency ("Dependency2``1(``0,System.Int32,System.Object)", typeof (C))]
+
+                       [ExpectedWarning ("IL2037", "''", "'Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.B'")]
+                       [DynamicDependency ("")]
+
+                       [ExpectedWarning ("IL2037", "#ctor()", "'Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.NestedStruct'")]
+                       [DynamicDependency ("#ctor()", typeof (NestedStruct))]
+
+                       [ExpectedWarning ("IL2037", "#cctor()", "'Mono.Linker.Tests.Cases.DynamicDependencies.C'")]
+                       [DynamicDependency ("#cctor()", typeof (C))]
+
+                       [ExpectedWarning ("IL2036", "NonExistentType")]
+                       [DynamicDependency ("method", "NonExistentType", "test")]
+                       public static void Broken ()
+                       {
+                       }
+
+                       [Kept]
+                       [DynamicDependency ("ConditionalTest()", typeof (C), Condition = "don't have it")]
+                       public static void Conditional ()
+                       {
+                       }
+               }
+
+               class Nested
+               {
+                       [Kept]
+                       private static void NextOne (ref Nested arg1)
+                       {
+                       }
+
+                       [Kept]
+                       static Nested ()
+                       {
+
+                       }
+               }
+
+               class Complex
+               {
+                       // NativeAOT currently only validates runtime type information, in this case ilc only keeps metadata, but no runtime info
+                       // since the type is never instantiated or used anywhere else, just in the method signature.
+                       [Kept (By = ProducedBy.Trimmer)]
+                       public struct S<T> { }
+                       [Kept]
+                       public class A { }
+                       [Kept (By = ProducedBy.Trimmer)]
+                       public class G<T, U> { }
+
+                       [Kept]
+                       public void M<V> (ref S<G<A, V>>[,][][][,,] a)
+                       {
+                       }
+               }
+
+               struct NestedStruct
+               {
+                       public string Name;
+
+                       public NestedStruct (string name)
+                       {
+                               Name = name;
+                       }
+               }
+       }
+
+       [KeptMember (".ctor()")]
+       class C
+       {
+               [Kept]
+               internal string field;
+
+               [Kept]
+               internal void Dependency1 ()
+               {
+               }
+
+               internal void Dependency1 (long arg1)
+               {
+               }
+
+               [Kept]
+               internal void Dependency2<T> (T[] arg1, int arg2)
+               {
+               }
+
+               [Kept]
+               internal void Dependency3 (string str)
+               {
+               }
+
+               [Kept]
+               [DynamicDependency ("#ctor", typeof (NestedInC))]
+               internal void RecursiveDependency ()
+               {
+               }
+
+               [KeptMember (".ctor()")]
+               class NestedInC
+               {
+               }
+
+               [Kept]
+               [KeptBackingField]
+               internal string Property { [Kept] get; set; }
+
+               [Kept]
+               [KeptBackingField]
+               internal string Property2 { [Kept] get; set; }
+
+               // For now, Condition has no effect: https://github.com/dotnet/linker/issues/1231
+               [Kept]
+               internal void ConditionalTest ()
+               {
+               }
+       }
+
+       abstract class ReferenceViaReflection
+       {
+               [Kept]
+               [DynamicDependency (nameof (TargetMethodViaReflection))]
+               public static void SourceMethodViaReflection () { }
+
+               [Kept]
+               private static void TargetMethodViaReflection () { }
+
+
+               [Kept]
+               public static void Test ()
+               {
+                       var i = new Impl (); // Avoid removal of non-implemented abstract methods
+
+                       typeof (ReferenceViaReflection).RequiresPublicMethods ();
+                       typeof (AbstractMethods).RequiresPublicMethods ();
+               }
+
+               [KeptMember (".ctor()")]
+               private abstract class AbstractMethods
+               {
+                       [Kept (By = ProducedBy.Trimmer)] // NativeAOT test infra doesn't check reflection-only methods (without entry point) yet
+                       [DynamicDependency (nameof (TargetMethod))]
+                       public abstract void SourceAbstractViaReflection ();
+
+                       [Kept]
+                       private static void TargetMethod () { }
+               }
+
+               [KeptMember (".ctor()")]
+               private class Impl : AbstractMethods
+               {
+                       [Kept]
+                       public override void SourceAbstractViaReflection () { }
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs
new file mode 100644 (file)
index 0000000..3baa037
--- /dev/null
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", ".ctor()")]
+       [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "privateField")]
+       [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs" })]
+       [SetupLinkerArgument ("--skip-unresolved", "true")]
+       public class DynamicDependencyMethodInAssembly
+       {
+               public static void Main ()
+               {
+                       Dependency ();
+               }
+
+               [Kept]
+               [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")]
+               [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicFields, "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")]
+
+               [ExpectedWarning ("IL2035", "NonExistentAssembly")]
+               [DynamicDependency ("method", "type", "NonExistentAssembly")]
+               static void Dependency ()
+               {
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssembly.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssembly.cs
new file mode 100644 (file)
index 0000000..35dd9b9
--- /dev/null
@@ -0,0 +1,41 @@
+using System.Diagnostics.CodeAnalysis;
+using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })]
+       [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)]
+       [KeptAssembly ("base.dll")]
+       [KeptAssembly ("library.dll")]
+       [KeptMemberInAssembly ("base.dll", typeof (DynamicDependencyMethodInNonReferencedAssemblyBase), "Method()")]
+       [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "Method()")]
+       public class DynamicDependencyMethodInNonReferencedAssembly
+       {
+               public static void Main ()
+               {
+                       var obj = new Foo ();
+                       var val = obj.Method ();
+                       Dependency ();
+               }
+
+               [Kept]
+               [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "library")]
+               static void Dependency ()
+               {
+               }
+
+               [Kept]
+               [KeptMember (".ctor()")]
+               [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))]
+               class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase
+               {
+                       [Kept]
+                       public override string Method ()
+                       {
+                               return "Foo";
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChained.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChained.cs
new file mode 100644 (file)
index 0000000..3f43c89
--- /dev/null
@@ -0,0 +1,44 @@
+using System.Diagnostics.CodeAnalysis;
+using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })]
+       [SetupCompileBefore ("base2.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs" }, references: new[] { "base.dll" }, addAsReference: false)]
+       [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)]
+       [KeptAssembly ("base.dll")]
+       [KeptAssembly ("base2.dll")]
+       [KeptAssembly ("library.dll")]
+       [KeptMemberInAssembly ("base.dll", typeof (DynamicDependencyMethodInNonReferencedAssemblyBase), "Method()")]
+       [KeptMemberInAssembly ("base2.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyBase2", "Method()")]
+       [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary", "Method()")]
+       public class DynamicDependencyMethodInNonReferencedAssemblyChained
+       {
+               public static void Main ()
+               {
+                       var obj = new Foo ();
+                       var val = obj.Method ();
+                       Dependency ();
+               }
+
+               [Kept]
+               [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary", "library")]
+               static void Dependency ()
+               {
+               }
+
+               [Kept]
+               [KeptMember (".ctor()")]
+               [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))]
+               class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase
+               {
+                       [Kept]
+                       public override string Method ()
+                       {
+                               return "Foo";
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReference.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReference.cs
new file mode 100644 (file)
index 0000000..32fd60d
--- /dev/null
@@ -0,0 +1,47 @@
+using System.Diagnostics.CodeAnalysis;
+using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })]
+       [SetupCompileBefore ("base2.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs" }, references: new[] { "base.dll" }, addAsReference: false)]
+       [SetupCompileBefore ("reference.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)]
+       [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs" }, references: new[] { "base.dll", "reference.dll" }, addAsReference: false)]
+       [KeptAssembly ("base.dll")]
+       [KeptAssembly ("base2.dll")]
+       [KeptAssembly ("library.dll")]
+       [KeptAssembly ("reference.dll")]
+       [KeptMemberInAssembly ("base.dll", typeof (DynamicDependencyMethodInNonReferencedAssemblyBase), "Method()")]
+       [KeptMemberInAssembly ("base2.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyBase2", "Method()")]
+       [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary", "Method()")]
+       [KeptMemberInAssembly ("reference.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary", "Method()")]
+       public class DynamicDependencyMethodInNonReferencedAssemblyChainedReference
+       {
+               public static void Main ()
+               {
+                       var obj = new Foo ();
+                       var val = obj.Method ();
+                       Dependency ();
+               }
+
+               [Kept]
+               [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary", "library")]
+               static void Dependency ()
+               {
+               }
+
+               [Kept]
+               [KeptMember (".ctor()")]
+               [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))]
+               class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase
+               {
+                       [Kept]
+                       public override string Method ()
+                       {
+                               return "Foo";
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs
new file mode 100644 (file)
index 0000000..65a0356
--- /dev/null
@@ -0,0 +1,46 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [IgnoreDescriptors (false)]
+       [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })]
+       [SetupCompileBefore (
+               "DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll",
+               new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" },
+               references: new[] { "base.dll" },
+               resources: new object[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml" },
+               addAsReference: false)]
+       [KeptAssembly ("base.dll")]
+       [KeptMemberInAssembly ("DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "UnusedMethod()")]
+       public class DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml
+       {
+               public static void Main ()
+               {
+                       var obj = new Foo ();
+                       var val = obj.Method ();
+                       Dependency ();
+               }
+
+               [Kept]
+               [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "DynamicDependencyMethodInNonReferencedAssemblyLibrary")]
+               static void Dependency ()
+               {
+               }
+
+               [Kept]
+               [KeptMember (".ctor()")]
+               [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))]
+               class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase
+               {
+                       [Kept]
+                       public override string Method ()
+                       {
+                               return "Foo";
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithSweptReferences.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithSweptReferences.cs
new file mode 100644 (file)
index 0000000..4fca50c
--- /dev/null
@@ -0,0 +1,32 @@
+using System.Diagnostics.CodeAnalysis;
+using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupCSharpCompilerToUse ("csc")]
+       [SetupCompileBefore ("unusedreference.dll", new[] { "Dependencies/UnusedAssemblyDependency.cs" })]
+       [SetupCompileBefore ("reference.dll", new[] { "Dependencies/AssemblyDependency.cs" }, addAsReference: false)]
+       [SetupCompileBefore ("library.dll", new[] { "Dependencies/AssemblyDependencyWithMultipleReferences.cs" }, new[] { "reference.dll", "unusedreference.dll" }, addAsReference: false)]
+       // TODO: keep library even if type is not found in it (https://github.com/dotnet/linker/issues/1795)
+       // [KeptAssembly ("library")]
+       public class DynamicDependencyMethodInNonReferencedAssemblyWithSweptReferences
+       {
+               public static void Main ()
+               {
+                       DynamicDependencyOnNonExistingTypeInAssembly ();
+               }
+
+               [Kept]
+               [DynamicDependency ("#ctor()", "DoesntExist", "library")]
+               static void DynamicDependencyOnNonExistingTypeInAssembly ()
+               {
+               }
+
+               static void ReferenceUnusedAssemblyDependency ()
+               {
+                       UnusedAssemblyDependency.UsedToKeepReferenceAtCompileTime ();
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnForwardedType.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnForwardedType.cs
new file mode 100644 (file)
index 0000000..ec828c8
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupCSharpCompilerToUse ("csc")]
+       [SetupCompileBefore ("FacadeAssembly.dll", new[] { "Dependencies/ReferenceImplementationLibrary.cs" })]
+       [SetupCompileAfter ("ImplementationLibrary.dll", new[] { "Dependencies/ImplementationLibrary.cs" })]
+       [SetupCompileAfter ("FacadeAssembly.dll", new[] { "Dependencies/FacadeAssembly.cs" }, new[] { "ImplementationLibrary.dll" })]
+       [KeptAssembly ("FacadeAssembly.dll")]
+       [LogDoesNotContain ("IL2036")]
+       public class DynamicDependencyOnForwardedType
+       {
+               [DynamicDependency (".ctor", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.ImplementationLibrary", "FacadeAssembly")]
+               [DynamicDependency (".ctor", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.ImplementationLibraryGenericType`2", "FacadeAssembly")]
+               [DynamicDependency (".ctor", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.ImplementationLibrary.NestedType", "FacadeAssembly")]
+               static void Main ()
+               {
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssembly.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssembly.cs
new file mode 100644 (file)
index 0000000..74bbc69
--- /dev/null
@@ -0,0 +1,39 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })]
+       [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)]
+       [KeptAssembly ("base.dll")]
+       [RemovedAssembly ("library.dll")]
+       [KeptMemberInAssembly ("base.dll", typeof (DynamicDependencyMethodInNonReferencedAssemblyBase), "Method()")]
+       public class DynamicDependencyOnUnusedMethodInNonReferencedAssembly
+       {
+               public static void Main ()
+               {
+                       var obj = new Foo ();
+                       var val = obj.Method ();
+               }
+
+               [DynamicDependency (".ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "library")]
+               static void Dependency ()
+               {
+               }
+
+               [Kept]
+               [KeptMember (".ctor()")]
+               [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))]
+               class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase
+               {
+                       [Kept]
+                       public override string Method ()
+                       {
+                               return "Foo";
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs
new file mode 100644 (file)
index 0000000..7d71a28
--- /dev/null
@@ -0,0 +1,33 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       [SetupLinkerDefaultAction ("copyused")]
+       [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs" }, addAsReference: false)]
+       [RemovedAssembly ("library.dll")]
+       public class DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction
+       {
+#if NETCOREAPP
+               [Kept (By = ProducedBy.Trimmer)] // Native AOT doesn't really support copyused behavior
+               public DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction ()
+               {
+               }
+#endif
+
+               public static void Main ()
+               {
+               }
+
+               [DynamicDependency ("MethodPreservedViaDependencyAttribute()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib", "library")]
+#if NETCOREAPP
+               [Kept (By = ProducedBy.Trimmer)] // Native AOT doesn't really support copyused behavior
+               [KeptAttributeAttribute (typeof (DynamicDependencyAttribute))]
+#endif
+               static void Dependency ()
+               {
+               }
+       }
+}
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs
new file mode 100644 (file)
index 0000000..6efb465
--- /dev/null
@@ -0,0 +1,47 @@
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.DynamicDependencies
+{
+       /// <summary>
+       /// This test is here to ensure that link xml embedded in an assembly used by a [DynamicDependency] is not processed if the dependency is not used
+       /// </summary>
+       [IgnoreDescriptors (false)]
+       [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })]
+       [SetupCompileBefore (
+               "DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll",
+               new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" },
+               references: new[] { "base.dll" },
+               resources: new object[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml" },
+               addAsReference: false)]
+       [KeptAssembly ("base.dll")]
+       [RemovedAssembly ("DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll")]
+       public class DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml
+       {
+               public static void Main ()
+               {
+                       var obj = new Foo ();
+                       var val = obj.Method ();
+               }
+
+               [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "DynamicDependencyMethodInNonReferencedAssemblyLibrary")]
+               static void Dependency ()
+               {
+               }
+
+               [Kept]
+               [KeptMember (".ctor()")]
+               [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))]
+               class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase
+               {
+                       [Kept]
+                       public override string Method ()
+                       {
+                               return "Foo";
+                       }
+               }
+       }
+}
\ No newline at end of file
index 1e62026..94ec554 100644 (file)
   </PropertyGroup>
 
   <ItemGroup>
+    <Compile Remove="DynamicDependencies\Dependencies\FacadeAssembly.cs" />
+  </ItemGroup>
+
+  <ItemGroup>
     <ProjectReference Include="..\Mono.Linker.Tests.Cases.Expectations\Mono.Linker.Tests.Cases.Expectations.csproj" />
   </ItemGroup>
 
index a26edda..f0e5902 100644 (file)
@@ -19,6 +19,11 @@ namespace Mono.Linker.Tests.TestCases
                        return TestNamesBySuiteName ();
                }
 
+               public static IEnumerable<object[]> DynamicDependencies ()
+               {
+                       return TestNamesBySuiteName ();
+               }
+
                public static IEnumerable<object[]> Repro ()
                {
                        return TestNamesBySuiteName ();
index 00cbb14..923c082 100644 (file)
@@ -18,6 +18,13 @@ namespace Mono.Linker.Tests.TestCases
                }
 
                [Theory]
+               [MemberData (nameof (TestDatabase.DynamicDependencies), MemberType = typeof (TestDatabase))]
+               public void DynamicDependencies (string t)
+               {
+                       Run (t);
+               }
+
+               [Theory]
                [MemberData (nameof (TestDatabase.Repro), MemberType = typeof (TestDatabase))]
                public void Repro (string t)
                {
index fb43b9d..51f2fa9 100644 (file)
@@ -10,6 +10,7 @@ using System.Reflection.Metadata.Ecma335;
 using System.Text;
 using FluentAssertions;
 using ILCompiler;
+using Internal.IL.Stubs;
 using Internal.TypeSystem;
 using Internal.TypeSystem.Ecma;
 using Mono.Cecil;
@@ -36,6 +37,7 @@ namespace Mono.Linker.Tests.TestCasesRunner
                                        EcmaMethod method => (method.Module.Assembly.GetName ().Name, MetadataTokens.GetToken (method.Handle)),
                                        PropertyPseudoDesc property => (((EcmaType) property.OwningType).Module.Assembly.GetName ().Name, MetadataTokens.GetToken (property.Handle)),
                                        EventPseudoDesc @event => (((EcmaType) @event.OwningType).Module.Assembly.GetName ().Name, MetadataTokens.GetToken (@event.Handle)),
+                                       ILStubMethod => (null, 0), // Ignore compiler generated methods
                                        _ => throw new NotSupportedException ($"The infra doesn't support getting a token for {entity} yet.")
                                };
 
@@ -172,11 +174,19 @@ namespace Mono.Linker.Tests.TestCasesRunner
                                if (!ShouldIncludeMethod (methodDef))
                                        return;
 
+                               TypeDesc owningType = methodDef.OwningType;
+
+                               // Skip any methods on a delegate - we handle those in the AddType
+                               // (AOT generates different methods for delegates compared to IL/metadata shapes)
+                               if (owningType?.IsDelegate == true)
+                                       return;
+
                                if (!AddMember (methodDef))
                                        return;
 
-                               if (methodDef.OwningType is { } owningType)
+                               if (owningType is not null) {
                                        AddType (owningType);
+                               }
 
                                if (methodDef.GetPropertyForAccessor () is { } property)
                                        AddProperty (property);
@@ -198,6 +208,16 @@ namespace Mono.Linker.Tests.TestCasesRunner
                                if (typeDef is MetadataType { ContainingType: { } containingType }) {
                                        AddType (containingType);
                                }
+
+                               if (typeDef.IsDelegate) {
+                                       // AOT's handling of delegates is very different from the IL/metadata picture
+                                       // So to simplify this, we're going to automatically "mark" all of the delegate's methods
+                                       foreach (MethodDesc m in typeDef.GetMethods()) {
+                                               if (ShouldIncludeEntityByDisplayName(m)) {
+                                                       AddMember (m);
+                                               }
+                                       }
+                               }
                        }
 
                        void AddProperty (PropertyPseudoDesc property)
@@ -539,13 +559,13 @@ namespace Mono.Linker.Tests.TestCasesRunner
                        bool expectedKept = ShouldBeKept (src);
 
                        if (!expectedKept) {
-                               if (linked != null)
+                               if (linked is not null)
                                        Assert.True (false, $"Event `{src}' should have been removed");
 
                                return;
                        }
 
-                       if (linked == null) {
+                       if (linked is null) {
                                Assert.True (false, $"Event `{src}' should have been kept");
                                return;
                        }