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.
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;
{
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;
}
}
}
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)
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)
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)
--- /dev/null
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+ public class AssemblyDependency
+ {
+ public AssemblyDependency ()
+ {
+ }
+
+ public static void UsedToKeepReferenceAtCompileTime ()
+ {
+ }
+
+ class TypeThatIsUsedViaReflection
+ {
+ }
+ }
+}
--- /dev/null
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+ public class AssemblyDependencyWithReference : AssemblyDependency
+ {
+ }
+
+ public class UsedToReferenceUnusedAssembly : UnusedAssemblyDependency
+ {
+ }
+}
\ No newline at end of file
--- /dev/null
+// 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 ()
+ {
+ }
+ }
+}
--- /dev/null
+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 ()
+ {
+ }
+ }
+}
--- /dev/null
+using System;
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+ public class DynamicDependencyMethodInAssemblyLibrary
+ {
+ public DynamicDependencyMethodInAssemblyLibrary ()
+ {
+ }
+
+ private void Foo ()
+ {
+ }
+
+ private int privateField;
+ }
+}
--- /dev/null
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+ public abstract class DynamicDependencyMethodInNonReferencedAssemblyBase
+ {
+ public abstract string Method ();
+ }
+}
\ No newline at end of file
--- /dev/null
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+ public class DynamicDependencyMethodInNonReferencedAssemblyBase2 : DynamicDependencyMethodInNonReferencedAssemblyBase
+ {
+ public override string Method ()
+ {
+ return "Base2";
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+<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>
--- /dev/null
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+ public class DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib
+ {
+ public static void MethodPreservedViaDependencyAttribute ()
+ {
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// 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<,>))]
--- /dev/null
+// 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>
+ {
+ }
+}
--- /dev/null
+// 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
+ {
+ }
+}
--- /dev/null
+namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies
+{
+ public class UnusedAssemblyDependency
+ {
+ public UnusedAssemblyDependency ()
+ {
+ }
+
+ public static void UsedToKeepReferenceAtCompileTime ()
+ {
+ }
+ }
+}
--- /dev/null
+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 ();
+ }
+ }
+ }
+}
--- /dev/null
+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 ()
+ {
+ }
+ }
+ }
+}
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+// 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;
+ }
+}
--- /dev/null
+<?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>
--- /dev/null
+<?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>
--- /dev/null
+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 ();
+ }
+ }
+}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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 { }
+ }
+ }
+}
--- /dev/null
+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 () { }
+ }
+ }
+}
--- /dev/null
+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 ()
+ {
+ }
+ }
+}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+// 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 ()
+ {
+ }
+ }
+}
--- /dev/null
+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
--- /dev/null
+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 ()
+ {
+ }
+ }
+}
--- /dev/null
+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
</PropertyGroup>
<ItemGroup>
+ <Compile Remove="DynamicDependencies\Dependencies\FacadeAssembly.cs" />
+ </ItemGroup>
+
+ <ItemGroup>
<ProjectReference Include="..\Mono.Linker.Tests.Cases.Expectations\Mono.Linker.Tests.Cases.Expectations.csproj" />
</ItemGroup>
return TestNamesBySuiteName ();
}
+ public static IEnumerable<object[]> DynamicDependencies ()
+ {
+ return TestNamesBySuiteName ();
+ }
+
public static IEnumerable<object[]> Repro ()
{
return TestNamesBySuiteName ();
}
[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)
{
using System.Text;
using FluentAssertions;
using ILCompiler;
+using Internal.IL.Stubs;
using Internal.TypeSystem;
using Internal.TypeSystem.Ecma;
using Mono.Cecil;
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.")
};
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);
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)
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;
}