diff --git a/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs b/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs index 9bcc484b178a32..07b78f196d2e34 100644 --- a/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs +++ b/src/coreclr/tools/Common/Compiler/ProcessLinkerXmlBase.cs @@ -217,9 +217,10 @@ protected virtual void ProcessTypes(ModuleDesc assembly, XPathNavigator nav, boo continue; } - // TODO: Process exported types + MetadataType? type = CecilCompatibleTypeParser.GetType(assembly, fullname); - TypeDesc? type = CecilCompatibleTypeParser.GetType(assembly, fullname); + if (type != null && type.Module != assembly) + type = ProcessExportedType(type, assembly, typeNav); if (type == null) { @@ -234,6 +235,8 @@ protected virtual void ProcessTypes(ModuleDesc assembly, XPathNavigator nav, boo } } + protected virtual MetadataType? ProcessExportedType(MetadataType exported, ModuleDesc assembly, XPathNavigator nav) => exported; + private void MatchType(TypeDesc type, Regex regex, XPathNavigator nav) { StringBuilder sb = new StringBuilder(); @@ -759,7 +762,7 @@ public bool TryConvertValue(string value, TypeDesc type, out object? result) public class CecilCompatibleTypeParser { - public static TypeDesc? GetType(ModuleDesc assembly, string fullName) + public static MetadataType? GetType(ModuleDesc assembly, string fullName) { Debug.Assert(!string.IsNullOrEmpty(fullName)); var position = fullName.IndexOf('/'); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs index 979ade817b3d27..0cf8ec1638793a 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs @@ -40,7 +40,7 @@ protected override void ProcessAssembly(ModuleDesc assembly, XPathNavigator nav, ProcessTypes(assembly, nav, warnOnUnresolvedTypes); } - // protected override TypeDesc? ProcessExportedType(ExportedType exported, ModuleDesc assembly, XPathNavigator nav) => null; + protected override MetadataType ProcessExportedType(MetadataType exported, ModuleDesc assembly, XPathNavigator nav) => null; protected override bool ProcessTypePattern(string fullname, ModuleDesc assembly, XPathNavigator nav) => false; diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DescriptorMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DescriptorMarker.cs index e86c20c31a7837..32514dccc5eee6 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DescriptorMarker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DescriptorMarker.cs @@ -162,6 +162,14 @@ private void MarkAndPreserve(TypeDesc type, XPathNavigator nav, TypePreserve pre } #endif + protected override MetadataType? ProcessExportedType(MetadataType exported, ModuleDesc assembly, XPathNavigator nav) + { + // Rooting module metadata roots type forwarder metadata for all types in the module that are reflection visible. + // (We don't track individual type forwarders right now.) + _dependencies.Add(_factory.ModuleMetadata(assembly), "Type used through forwarder"); + return base.ProcessExportedType(exported, assembly, nav); + } + protected override void ProcessType(TypeDesc type, XPathNavigator nav) { Debug.Assert(ShouldProcessElement(nav)); diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ILLinkDescriptor.cs b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ILLinkDescriptor.cs index 105ff1379df446..4e4404a5b89e90 100644 --- a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ILLinkDescriptor.cs +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ILLinkDescriptor.cs @@ -17,6 +17,7 @@ public static int Run() ThrowIfMemberNotPresent(typeof(ILLinkDescriptor), nameof(PropertyKeptViaDescriptor)); ThrowIfMemberNotPresent(typeof(ILLinkDescriptor), nameof(EventKeptViaDescriptor)); ThrowIfTypeNotPresent(typeof(ILLinkDescriptor), nameof(NestedTypeKeptViaDescriptor)); + ThrowIfTypeNotPresent("LibraryClass, ShimLibrary"); ThrowIfTypePresent(typeof(ILLinkDescriptor), nameof(NestedTypeNonKept)); return 100; } @@ -51,6 +52,10 @@ class NestedTypeNonKept Justification = "That's the point")] private static bool IsTypePresent(Type testType, string typeName) => testType.GetNestedType(typeName, BindingFlags.NonPublic | BindingFlags.Public) != null; + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2057:UnrecognizedReflectionPattern", + Justification = "That's the point")] + private static bool IsTypePresent(string typeName) => Type.GetType(typeName) != null; + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "That's the point")] private static bool IsMemberPresent(Type testType, string memberName) { @@ -70,6 +75,14 @@ private static void ThrowIfTypeNotPresent(Type testType, string typeName) } } + private static void ThrowIfTypeNotPresent(string typeName) + { + if (!IsTypePresent(typeName)) + { + throw new Exception(typeName); + } + } + private static void ThrowIfTypePresent(Type testType, string typeName) { if (IsTypePresent(testType, typeName)) diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Library.cs b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Library.cs new file mode 100644 index 00000000000000..d7a9483709bc94 --- /dev/null +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Library.cs @@ -0,0 +1,4 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +public class LibraryClass { } diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Library.csproj b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Library.csproj new file mode 100644 index 00000000000000..71634a59882430 --- /dev/null +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Library.csproj @@ -0,0 +1,8 @@ + + + Library + + + + + diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/NonEmbedded.ILLink.Descriptor.xml b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/NonEmbedded.ILLink.Descriptor.xml index ef70498ef49735..c33d576e31c293 100644 --- a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/NonEmbedded.ILLink.Descriptor.xml +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/NonEmbedded.ILLink.Descriptor.xml @@ -4,4 +4,8 @@ + + + + diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ShimLibrary.cs b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ShimLibrary.cs new file mode 100644 index 00000000000000..dbac9ac09317f3 --- /dev/null +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ShimLibrary.cs @@ -0,0 +1,6 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +[assembly: TypeForwardedTo(typeof(LibraryClass))] diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ShimLibrary.csproj b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ShimLibrary.csproj new file mode 100644 index 00000000000000..cc00bd360d38ef --- /dev/null +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/ShimLibrary.csproj @@ -0,0 +1,11 @@ + + + Library + + + + + + + + diff --git a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/TrimmingBehaviors.csproj b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/TrimmingBehaviors.csproj index fa0c9d0e4d7b2b..c69f6e042a57b8 100644 --- a/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/TrimmingBehaviors.csproj +++ b/src/tests/nativeaot/SmokeTests/TrimmingBehaviors/TrimmingBehaviors.csproj @@ -8,6 +8,11 @@ true + + + + +