From 0cbbe395c64fa5025b93a051e8ce437a2bf7ea4f Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Fri, 10 Jul 2020 10:11:51 -0500 Subject: [PATCH 1/3] Preserve DebuggerTypeProxyAttribute classes Also, ensure the test app assembly is linked, and not copied during trimming tests, which was a bug in our test infrastructure. Fix #37307 --- .../SupportFiles/Directory.Build.targets | 13 ++++- .../Diagnostics/DebuggerTypeProxyAttribute.cs | 11 ++++- .../System.Runtime/ref/System.Runtime.cs | 5 +- .../DebuggerTypeProxyAttributeTests.cs | 49 +++++++++++++++++++ .../DefaultValueAttributeCtorTest.cs | 4 ++ .../System.Runtime.TrimmingTests.proj | 2 + 6 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/libraries/System.Runtime/tests/TrimmingTests/DebuggerTypeProxyAttributeTests.cs diff --git a/eng/testing/linker/SupportFiles/Directory.Build.targets b/eng/testing/linker/SupportFiles/Directory.Build.targets index 90ce573551e90..f1603cde43ad9 100644 --- a/eng/testing/linker/SupportFiles/Directory.Build.targets +++ b/eng/testing/linker/SupportFiles/Directory.Build.targets @@ -19,6 +19,17 @@ + + + + + <_ManagedAssembliesToLink> + link + + + + - \ No newline at end of file + diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebuggerTypeProxyAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebuggerTypeProxyAttribute.cs index 500a946951bcf..1f99516869be6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebuggerTypeProxyAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/DebuggerTypeProxyAttribute.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics.CodeAnalysis; + namespace System.Diagnostics { [AttributeUsage(AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] @@ -8,7 +10,8 @@ public sealed class DebuggerTypeProxyAttribute : Attribute { private Type? _target; - public DebuggerTypeProxyAttribute(Type type) + public DebuggerTypeProxyAttribute( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type type) { if (type == null) { @@ -18,11 +21,15 @@ public DebuggerTypeProxyAttribute(Type type) ProxyTypeName = type.AssemblyQualifiedName!; } - public DebuggerTypeProxyAttribute(string typeName) + public DebuggerTypeProxyAttribute( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] string typeName) { ProxyTypeName = typeName; } + // The Proxy is only invoked by the debugger, so it needs to have its + // members preserved + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] public string ProxyTypeName { get; } public Type? Target diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index ee91e1dd2f824..43c3bee240e40 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -5715,8 +5715,9 @@ public DebuggerStepThroughAttribute() { } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Struct, AllowMultiple=true)] public sealed partial class DebuggerTypeProxyAttribute : System.Attribute { - public DebuggerTypeProxyAttribute(string typeName) { } - public DebuggerTypeProxyAttribute(System.Type type) { } + public DebuggerTypeProxyAttribute([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] string typeName) { } + public DebuggerTypeProxyAttribute([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.All)] System.Type type) { } + [System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicEvents)] public string ProxyTypeName { get { throw null; } } public System.Type? Target { get { throw null; } set { } } public string? TargetTypeName { get { throw null; } set { } } diff --git a/src/libraries/System.Runtime/tests/TrimmingTests/DebuggerTypeProxyAttributeTests.cs b/src/libraries/System.Runtime/tests/TrimmingTests/DebuggerTypeProxyAttributeTests.cs new file mode 100644 index 0000000000000..667448cadedc5 --- /dev/null +++ b/src/libraries/System.Runtime/tests/TrimmingTests/DebuggerTypeProxyAttributeTests.cs @@ -0,0 +1,49 @@ +using System; +using System.Diagnostics; + +/// +/// Tests that types used by DebuggerTypeProxyAttribute are not trimmed out +/// when Debugger.IsSupported is true (the default). +/// +class Program +{ + static int Main(string[] args) + { + MyClass myClass = new MyClass() { Name = "trimmed" }; + + Type[] allTypes = typeof(MyClass).Assembly.GetTypes(); + for (int i = 0; i < allTypes.Length; i++) + { + if (allTypes[i].Name.Contains("DebuggerProxy")) + { + Type proxyType = allTypes[i]; + if (proxyType.GetProperties().Length == 1 && + proxyType.GetConstructors().Length == 1) + { + return 100; + } + } + } + + // didn't find the proxy type, or it wasn't preserved correctly + return -1; + } + + [DebuggerTypeProxy(typeof(DebuggerProxy))] + public class MyClass + { + public string Name { get; set; } + + private class DebuggerProxy + { + private MyClass _instance; + + public DebuggerProxy(MyClass instance) + { + _instance = instance; + } + + public string DebuggerName => _instance.Name; + } + } +} diff --git a/src/libraries/System.Runtime/tests/TrimmingTests/DefaultValueAttributeCtorTest.cs b/src/libraries/System.Runtime/tests/TrimmingTests/DefaultValueAttributeCtorTest.cs index c30fb88e0b836..aaf82add5a051 100644 --- a/src/libraries/System.Runtime/tests/TrimmingTests/DefaultValueAttributeCtorTest.cs +++ b/src/libraries/System.Runtime/tests/TrimmingTests/DefaultValueAttributeCtorTest.cs @@ -10,6 +10,10 @@ class Program { static int Main(string[] args) { + // workaround TypeConverterAttribute not being annotated correctly + // https://github.com/dotnet/runtime/issues/39125 + var _ = new MyStringConverter(); + TypeDescriptor.AddAttributes(typeof(string), new TypeConverterAttribute(typeof(MyStringConverter))); var attribute = new DefaultValueAttribute(typeof(string), "Hello, world!"); diff --git a/src/libraries/System.Runtime/tests/TrimmingTests/System.Runtime.TrimmingTests.proj b/src/libraries/System.Runtime/tests/TrimmingTests/System.Runtime.TrimmingTests.proj index cfd1a4d2a7b81..ce96e07448a3c 100644 --- a/src/libraries/System.Runtime/tests/TrimmingTests/System.Runtime.TrimmingTests.proj +++ b/src/libraries/System.Runtime/tests/TrimmingTests/System.Runtime.TrimmingTests.proj @@ -6,6 +6,8 @@ osx-x64;linux-x64 + +