From aba0e20147e123aca6ab8e7dcb379e0122299c1a Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Thu, 28 Oct 2021 15:01:12 -0700 Subject: Revert "Revert "Fix handling of unknown BindingFlags (#2288)"" This reverts commit 02b53c5f601fb527438f26afb2c121b86fe0489a. --- .../Linker.Dataflow/ReflectionMethodBodyScanner.cs | 21 ++++++++------ .../Reflection/EventUsedViaReflection.cs | 32 ++++++++++++++++++++++ .../Reflection/FieldUsedViaReflection.cs | 19 +++++++++++++ .../Reflection/MethodUsedViaReflection.cs | 20 ++++++++++++++ .../Reflection/NestedTypeUsedViaReflection.cs | 21 ++++++++++++++ .../Reflection/PropertyUsedViaReflection.cs | 24 ++++++++++++++++ 6 files changed, 129 insertions(+), 8 deletions(-) diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index d90565b6d..2d2db4c56 100644 --- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -1112,8 +1112,7 @@ namespace Mono.Linker.Dataflow reflectionContext.RecordHandledPattern (); } else { // Otherwise fall back to the bitfield requirements - var requiredMemberTypes = HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicConstructors : DynamicallyAccessedMemberTypes.None; - requiredMemberTypes |= HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None; + var requiredMemberTypes = GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags); // We can scope down the public constructors requirement if we know the number of parameters is 0 if (requiredMemberTypes == DynamicallyAccessedMemberTypes.PublicConstructors && ctorParameterCount == 0) requiredMemberTypes = DynamicallyAccessedMemberTypes.PublicParameterlessConstructor; @@ -2401,27 +2400,33 @@ namespace Mono.Linker.Dataflow static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForNestedTypes (BindingFlags? bindingFlags) => (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicNestedTypes : DynamicallyAccessedMemberTypes.None) | - (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None); + (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None) | + (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes : DynamicallyAccessedMemberTypes.None); static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (BindingFlags? bindingFlags) => (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicConstructors : DynamicallyAccessedMemberTypes.None) | - (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None); + (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None) | + (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors : DynamicallyAccessedMemberTypes.None); static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMethods (BindingFlags? bindingFlags) => (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicMethods : DynamicallyAccessedMemberTypes.None) | - (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None); + (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None) | + (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods : DynamicallyAccessedMemberTypes.None); static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForFields (BindingFlags? bindingFlags) => (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicFields : DynamicallyAccessedMemberTypes.None) | - (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None); + (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None) | + (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields : DynamicallyAccessedMemberTypes.None); static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForProperties (BindingFlags? bindingFlags) => (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicProperties : DynamicallyAccessedMemberTypes.None) | - (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None); + (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None) | + (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties : DynamicallyAccessedMemberTypes.None); static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (BindingFlags? bindingFlags) => (HasBindingFlag (bindingFlags, BindingFlags.Public) ? DynamicallyAccessedMemberTypes.PublicEvents : DynamicallyAccessedMemberTypes.None) | - (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None); + (HasBindingFlag (bindingFlags, BindingFlags.NonPublic) ? DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None) | + (BindingFlagsAreUnsupported (bindingFlags) ? DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents : DynamicallyAccessedMemberTypes.None); static DynamicallyAccessedMemberTypes GetDynamicallyAccessedMemberTypesFromBindingFlagsForMembers (BindingFlags? bindingFlags) => GetDynamicallyAccessedMemberTypesFromBindingFlagsForConstructors (bindingFlags) | GetDynamicallyAccessedMemberTypesFromBindingFlagsForEvents (bindingFlags) | diff --git a/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs index ba33cdc4e..5f93cf879 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/EventUsedViaReflection.cs @@ -17,6 +17,7 @@ namespace Mono.Linker.Tests.Cases.Reflection TestNameBindingFlags (); TestNameWrongBindingFlags (); TestNameUnknownBindingFlags (BindingFlags.Public); + TestNameUnknownBindingFlagsAndName (BindingFlags.Public, "DoesntMatter"); TestNullName (); TestEmptyName (); TestNonExistingName (); @@ -71,6 +72,13 @@ namespace Mono.Linker.Tests.Cases.Reflection var eventInfo = typeof (UnknownBindingFlags).GetEvent ("PrivateEvent", bindingFlags); } + [Kept] + static void TestNameUnknownBindingFlagsAndName (BindingFlags bindingFlags, string name) + { + // Since the binding flags are not known linker should mark all events on the type + var eventInfo = typeof (UnknownBindingFlagsAndName).GetEvent (name, bindingFlags); + } + [Kept] static void TestNullName () { @@ -221,6 +229,30 @@ namespace Mono.Linker.Tests.Cases.Reflection public event EventHandler PublicEvent; } + class UnknownBindingFlagsAndName + { + [Kept] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + [method: ExpectBodyModified] + internal event EventHandler InternalEvent; + [Kept] + [KeptBackingField] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + static event EventHandler Static; + [Kept] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + [method: ExpectBodyModified] + private event EventHandler PrivateEvent; + [Kept] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + [method: ExpectBodyModified] + public event EventHandler PublicEvent; + } + class IfClass { [Kept] diff --git a/test/Mono.Linker.Tests.Cases/Reflection/FieldUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/FieldUsedViaReflection.cs index 7d7fc22d3..94535adb1 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/FieldUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/FieldUsedViaReflection.cs @@ -15,6 +15,7 @@ namespace Mono.Linker.Tests.Cases.Reflection TestNameBindingFlags (); TestNameWrongBindingFlags (); TestNameUnknownBindingFlags (BindingFlags.Public); + TestNameUnknownBindingFlagsAndName (BindingFlags.Public, "DoesntMatter"); TestNullName (); TestEmptyName (); TestNonExistingName (); @@ -66,6 +67,13 @@ namespace Mono.Linker.Tests.Cases.Reflection var field = typeof (UnknownBindingFlags).GetField ("field", bindingFlags); } + [Kept] + static void TestNameUnknownBindingFlagsAndName (BindingFlags bindingFlags, string name) + { + // Since the binding flags and name are not known linker should mark all fields on the type + var field = typeof (UnknownBindingFlagsAndName).GetField (name, bindingFlags); + } + [Kept] static void TestNullName () { @@ -186,6 +194,17 @@ namespace Mono.Linker.Tests.Cases.Reflection private static int privatefield; } + [Kept] + private class UnknownBindingFlagsAndName + { + [Kept] + public static int field; + [Kept] + public int nonStatic; + [Kept] + private static int privatefield; + } + [Kept] private class IfClass { diff --git a/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs index 18e70c058..162ff3dc2 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs @@ -17,6 +17,7 @@ namespace Mono.Linker.Tests.Cases.Reflection GetMethod_Name_Types.TestNameAndType (); GetMethod_Name_BindingAttr.TestExplicitBindingFlags (); GetMethod_Name_BindingAttr.TestUnknownBindingFlags (BindingFlags.Public); + GetMethod_Name_BindingAttr.TestUnknownBindingFlagsAndName (BindingFlags.Public, "DoesntMatter"); GetMethod_Name_BindingAttr.TestUnknownNullBindingFlags (BindingFlags.Public); GetMethod_Name_BindingAttr_Binder_Types_Modifiers.TestNameBindingFlagsAndParameterModifier (); GetMethod_Name_BindingAttr_Binder_CallConvention_Types_Modifiers.TestNameBindingFlagsCallingConventionParameterModifier (); @@ -199,6 +200,25 @@ namespace Mono.Linker.Tests.Cases.Reflection method.Invoke (null, new object[] { }); } + [Kept] + class UnknownBindingFlagsAndName + { + [Kept] + private static int OnlyCalledViaReflection () + { + return 42; + } + } + + [Kept] + [RecognizedReflectionAccessPattern] + public static void TestUnknownBindingFlagsAndName (BindingFlags bindingFlags, string name) + { + // Since the binding flags and name are not known linker should mark all methods on the type + var method = typeof (UnknownBindingFlagsAndName).GetMethod (name, bindingFlags); + method.Invoke (null, new object[] { }); + } + [Kept] private class NullBindingFlags { diff --git a/test/Mono.Linker.Tests.Cases/Reflection/NestedTypeUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/NestedTypeUsedViaReflection.cs index cda87ee85..2700a8793 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/NestedTypeUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/NestedTypeUsedViaReflection.cs @@ -16,6 +16,7 @@ namespace Mono.Linker.Tests.Cases.Reflection TestPrivateByName (); TestByBindingFlags (); TestByUnknownBindingFlags (BindingFlags.Public); + TestByUnknownBindingFlagsAndName (BindingFlags.Public, "DoesntMatter"); TestNonExistingName (); TestNullType (); TestIgnoreCaseBindingFlags (); @@ -80,6 +81,16 @@ namespace Mono.Linker.Tests.Cases.Reflection _ = typeof (UnknownBindingFlags).GetNestedType (nameof (PublicNestedType), bindingFlags); } + [Kept] + [RecognizedReflectionAccessPattern ( + typeof (Type), nameof (Type.GetNestedType), new Type[] { typeof (string), typeof (BindingFlags) }, + typeof (UnknownBindingFlagsAndName.PublicNestedType), null, (Type[]) null)] + static void TestByUnknownBindingFlagsAndName (BindingFlags bindingFlags, string name) + { + // Since the binding flags and name are not known linker should mark all nested types on the type + _ = typeof (UnknownBindingFlagsAndName).GetNestedType (name, bindingFlags); + } + [Kept] static void TestNonExistingName () { @@ -124,6 +135,16 @@ namespace Mono.Linker.Tests.Cases.Reflection private static class PrivateNestedType { } } + [Kept] + private class UnknownBindingFlagsAndName + { + [Kept] + public static class PublicNestedType { } + + [Kept] + private static class PrivateNestedType { } + } + [Kept] private class IgnoreCaseClass { diff --git a/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs index 3971f9108..7dc32c00b 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs @@ -17,6 +17,7 @@ namespace Mono.Linker.Tests.Cases.Reflection TestGetterOnly (); TestBindingFlags (); TestUnknownBindingFlags (BindingFlags.Public); + TestUnknownBindingFlagsAndName (BindingFlags.Public, "IrrelevantName"); TestNullName (); TestEmptyName (); TestNonExistingName (); @@ -89,6 +90,17 @@ namespace Mono.Linker.Tests.Cases.Reflection property.GetValue (null, new object[] { }); } + [Kept] + [RecognizedReflectionAccessPattern ( + typeof (Type), nameof (Type.GetProperty), new Type[] { typeof (string), typeof (BindingFlags) }, + typeof (UnknownBindingFlagsAndName), nameof (UnknownBindingFlagsAndName.SomeProperty), (Type[]) null)] + static void TestUnknownBindingFlagsAndName (BindingFlags bindingFlags, string name) + { + // Since the binding flags and name are not known linker should mark all properties on the type + var property = typeof (UnknownBindingFlagsAndName).GetProperty (name, bindingFlags); + property.GetValue (null, new object[] { }); + } + [Kept] static void TestNullName () { @@ -313,6 +325,18 @@ namespace Mono.Linker.Tests.Cases.Reflection } } + [Kept] + class UnknownBindingFlagsAndName + { + [Kept] + internal static int SomeProperty { + [Kept] + private get { return _field; } + [Kept] + set { _field = value; } + } + } + [Kept] class IgnoreCaseBindingFlagsClass { -- cgit v1.2.3 From c740c25d3cdc5e052606b600bcb07321c976f331 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Thu, 28 Oct 2021 15:01:22 -0700 Subject: Revert "Revert "Make BindingFlagsAreUnsupported more precise (#2296)"" This reverts commit cf525c5d5e5dd5ce098962b21adeea22b687ff1d. --- .../Linker.Dataflow/ReflectionMethodBodyScanner.cs | 28 +++++++++++++++++++++- .../Reflection/MethodUsedViaReflection.cs | 27 +++++++++++++++++++-- .../Reflection/MethodsUsedViaReflection.cs | 26 ++++++++++++++++++-- .../Reflection/PropertiesUsedViaReflection.cs | 26 ++++++++++++++++++-- .../Reflection/PropertyUsedViaReflection.cs | 25 +++++++++++++++++-- 5 files changed, 123 insertions(+), 9 deletions(-) diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs index 2d2db4c56..a523de225 100644 --- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs +++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs @@ -2276,7 +2276,33 @@ namespace Mono.Linker.Dataflow static BindingFlags? GetBindingFlagsFromValue (ValueNode? parameter) => (BindingFlags?) parameter.AsConstInt (); - static bool BindingFlagsAreUnsupported (BindingFlags? bindingFlags) => bindingFlags == null || (bindingFlags & BindingFlags.IgnoreCase) == BindingFlags.IgnoreCase || (int) bindingFlags > 255; + static bool BindingFlagsAreUnsupported (BindingFlags? bindingFlags) + { + if (bindingFlags == null) + return true; + + // Binding flags we understand + const BindingFlags UnderstoodBindingFlags = + BindingFlags.DeclaredOnly | + BindingFlags.Instance | + BindingFlags.Static | + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.FlattenHierarchy | + BindingFlags.ExactBinding; + + // Binding flags that don't affect binding outside InvokeMember (that we don't analyze). + const BindingFlags IgnorableBindingFlags = + BindingFlags.InvokeMethod | + BindingFlags.CreateInstance | + BindingFlags.GetField | + BindingFlags.SetField | + BindingFlags.GetProperty | + BindingFlags.SetProperty; + + BindingFlags flags = bindingFlags.Value; + return (flags & ~(UnderstoodBindingFlags | IgnorableBindingFlags)) != 0; + } static bool HasBindingFlag (BindingFlags? bindingFlags, BindingFlags? search) => bindingFlags != null && (bindingFlags & search) == search; diff --git a/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs index 162ff3dc2..bff3994a2 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/MethodUsedViaReflection.cs @@ -38,6 +38,7 @@ namespace Mono.Linker.Tests.Cases.Reflection DerivedAndBase.TestMethodInBaseType (); IgnoreCaseBindingFlags.TestIgnoreCaseBindingFlags (); FailIgnoreCaseBindingFlags.TestFailIgnoreCaseBindingFlags (); + IgnorableBindingFlags.TestIgnorableBindingFlags (); UnsupportedBindingFlags.TestUnsupportedBindingFlags (); } @@ -751,6 +752,28 @@ namespace Mono.Linker.Tests.Cases.Reflection } } + [Kept] + class IgnorableBindingFlags + { + [Kept] + public int OnlyCalledViaReflection () + { + return 54; + } + + private bool Unmarked () + { + return true; + } + + [Kept] + public static void TestIgnorableBindingFlags () + { + var method = typeof (IgnorableBindingFlags).GetMethod ("OnlyCalledViaReflection", BindingFlags.Public | BindingFlags.InvokeMethod); + method.Invoke (null, new object[] { }); + } + } + [Kept] class UnsupportedBindingFlags { @@ -761,7 +784,7 @@ namespace Mono.Linker.Tests.Cases.Reflection } [Kept] - private bool MarkedDueToInvokeMethod () + private bool MarkedDueToChangeType () { return true; } @@ -769,7 +792,7 @@ namespace Mono.Linker.Tests.Cases.Reflection [Kept] public static void TestUnsupportedBindingFlags () { - var method = typeof (UnsupportedBindingFlags).GetMethod ("OnlyCalledViaReflection", BindingFlags.InvokeMethod); + var method = typeof (UnsupportedBindingFlags).GetMethod ("OnlyCalledViaReflection", BindingFlags.Public | BindingFlags.SuppressChangeType); method.Invoke (null, new object[] { }); } } diff --git a/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs index 9fdbf389a..5658a1a99 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/MethodsUsedViaReflection.cs @@ -22,6 +22,7 @@ namespace Mono.Linker.Tests.Cases.Reflection TestDataFlowWithAnnotation (typeof (MyType)); TestIfElse (1); TestIgnoreCaseBindingFlags (); + TestIgnorableBindingFlags (); TestUnsupportedBindingFlags (); } @@ -99,10 +100,16 @@ namespace Mono.Linker.Tests.Cases.Reflection var methods = typeof (IgnoreCaseClass).GetMethods (BindingFlags.IgnoreCase | BindingFlags.Public); } + [Kept] + static void TestIgnorableBindingFlags () + { + var methods = typeof (InvokeMethodClass).GetMethods (BindingFlags.Public | BindingFlags.InvokeMethod); + } + [Kept] static void TestUnsupportedBindingFlags () { - var methods = typeof (InvokeMethodClass).GetMethods (BindingFlags.InvokeMethod); + var methods = typeof (SuppressChangeTypeClass).GetMethods (BindingFlags.Public | BindingFlags.SuppressChangeType); } [Kept] @@ -287,8 +294,23 @@ namespace Mono.Linker.Tests.Cases.Reflection return 54; } + private bool Unmarked () + { + return true; + } + } + + [Kept] + private class SuppressChangeTypeClass + { + [Kept] + public int OnlyCalledViaReflection () + { + return 54; + } + [Kept] - private bool MarkedDueToInvokeMethod () + private bool MarkedDueToSuppressChangeType () { return true; } diff --git a/test/Mono.Linker.Tests.Cases/Reflection/PropertiesUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/PropertiesUsedViaReflection.cs index a7b7dbea8..4f8346b7c 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/PropertiesUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/PropertiesUsedViaReflection.cs @@ -23,6 +23,7 @@ namespace Mono.Linker.Tests.Cases.Reflection TestDataFlowWithAnnotation (typeof (MyType)); TestIfElse (1); TestIgnoreCaseBindingFlags (); + TestIgnorableBindingFlags (); TestUnsupportedBindingFlags (); } @@ -105,11 +106,18 @@ namespace Mono.Linker.Tests.Cases.Reflection var properties = typeof (IgnoreCaseBindingFlagsClass).GetProperties (BindingFlags.IgnoreCase | BindingFlags.Public); } + [Kept] + [RecognizedReflectionAccessPattern] + static void TestIgnorableBindingFlags () + { + var properties = typeof (ExactBindingBindingFlagsClass).GetProperties (BindingFlags.Public | BindingFlags.ExactBinding); + } + [Kept] [RecognizedReflectionAccessPattern] static void TestUnsupportedBindingFlags () { - var properties = typeof (ExactBindingBindingFlagsClass).GetProperties (BindingFlags.ExactBinding); + var properties = typeof (ChangeTypeBindingFlagsClass).GetProperties (BindingFlags.Public | BindingFlags.SuppressChangeType); } [Kept] @@ -256,8 +264,22 @@ namespace Mono.Linker.Tests.Cases.Reflection set { _field = value; } } + private static int Unmarked { + get { return _field; } + } + } + + [Kept] + class ChangeTypeBindingFlagsClass + { + [Kept] + public static int SetterOnly { + [Kept] + set { _field = value; } + } + [Kept] - private static int MarkedDueToExactBinding { + private static int KeptDueToChangeType { [Kept] get { return _field; } } diff --git a/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs index 7dc32c00b..4004e894b 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/PropertyUsedViaReflection.cs @@ -28,6 +28,7 @@ namespace Mono.Linker.Tests.Cases.Reflection TestPropertyInBaseType (); TestIgnoreCaseBindingFlags (); TestFailIgnoreCaseBindingFlags (); + TestIgnorableBindingFlags (); TestUnsupportedBindingFlags (); } @@ -205,10 +206,16 @@ namespace Mono.Linker.Tests.Cases.Reflection var property = typeof (FailIgnoreCaseBindingFlagsClass).GetProperty ("setteronly", BindingFlags.Public); } + [Kept] + static void TestIgnorableBindingFlags () + { + var property = typeof (ExactBindingBindingFlagsClass).GetProperty ("SetterOnly", BindingFlags.Public | BindingFlags.ExactBinding); + } + [Kept] static void TestUnsupportedBindingFlags () { - var property = typeof (ExactBindingBindingFlagsClass).GetProperty ("SetterOnly", BindingFlags.ExactBinding); + var property = typeof (ChangeTypeBindingFlagsClass).GetProperty ("SetterOnly", BindingFlags.Public | BindingFlags.SuppressChangeType); } [Kept] @@ -370,8 +377,22 @@ namespace Mono.Linker.Tests.Cases.Reflection set { _field = value; } } + public static int Unmarked { + get { return _field; } + } + } + + [Kept] + class ChangeTypeBindingFlagsClass + { + [Kept] + public static int SetterOnly { + [Kept] + set { _field = value; } + } + [Kept] - public static int MarkedDueToExactBinding { + public static int Marked { [Kept] get { return _field; } } -- cgit v1.2.3 From 1083cf6dd3e9f9db59de7e9c16f981d8bb2daa5a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 12:27:27 +0000 Subject: Update dependencies from https://github.com/dotnet/arcade build 20211029.1 (#2345) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/templates/job/execute-sdl.yml | 6 +----- eng/common/templates/job/onelocbuild.yml | 5 ++++- eng/common/templates/job/source-index-stage1.yml | 2 +- eng/common/templates/jobs/jobs.yml | 4 ++-- global.json | 2 +- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 035206c8f..ee4e1efba 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,14 +3,14 @@ - + https://github.com/dotnet/arcade - 0cdef445272ad6a7374dfed71496c5affef90305 + 0558f85d950fee2838bf02b9ba1f20d67f00b504 - + https://github.com/dotnet/arcade - 0cdef445272ad6a7374dfed71496c5affef90305 + 0558f85d950fee2838bf02b9ba1f20d67f00b504 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 59cc427dd..e4dd433b4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,7 +18,7 @@ 5.0.0 17.0.0-preview-21267-01 17.0.0-preview-21267-01 - 7.0.0-beta.21524.1 + 7.0.0-beta.21529.1 6.0.0-beta.21271.1 3.10.0-2.final 3.10.0-2.final diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml index 69eb67849..3aafc82e4 100644 --- a/eng/common/templates/job/execute-sdl.yml +++ b/eng/common/templates/job/execute-sdl.yml @@ -60,11 +60,7 @@ jobs: - name: GuardianPackagesConfigFile value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config pool: - # To extract archives (.tar.gz, .zip), we need access to "tar", added in Windows 10/2019. - ${{ if eq(parameters.extractArchiveArtifacts, 'false') }}: - name: Hosted VS2017 - ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}: - vmImage: windows-2019 + vmImage: windows-2019 steps: - checkout: self clean: true diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index e8bc77d2e..c4fc18b3e 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -4,7 +4,7 @@ parameters: # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool pool: - vmImage: vs2017-win2016 + vmImage: 'windows-2019' CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex GithubPat: $(BotAccount-dotnet-bot-repo-PAT) @@ -12,6 +12,7 @@ parameters: SourcesDirectory: $(Build.SourcesDirectory) CreatePr: true AutoCompletePr: false + ReusePr: true UseLfLineEndings: true UseCheckedInLocProjectJson: false LanguageSet: VS_Main_Languages @@ -64,6 +65,8 @@ jobs: ${{ if eq(parameters.CreatePr, true) }}: isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }} isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }} + ${{ if eq(parameters.RepoType, 'gitHub') }}: + isShouldReusePrSelected: ${{ parameters.ReusePr }} packageSourceAuth: patAuth patVariable: ${{ parameters.CeapexPat }} ${{ if eq(parameters.RepoType, 'gitHub') }}: diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml index 1cc0c29e4..ae85a99a8 100644 --- a/eng/common/templates/job/source-index-stage1.yml +++ b/eng/common/templates/job/source-index-stage1.yml @@ -6,7 +6,7 @@ parameters: preSteps: [] binlogPath: artifacts/log/Debug/Build.binlog pool: - vmImage: vs2017-win2016 + vmImage: 'windows-2019' condition: '' dependsOn: '' diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml index a1f8fce96..8dd1fdbd1 100644 --- a/eng/common/templates/jobs/jobs.yml +++ b/eng/common/templates/jobs/jobs.yml @@ -83,7 +83,7 @@ jobs: - ${{ if eq(parameters.enableSourceBuild, true) }}: - Source_Build_Complete pool: - vmImage: vs2017-win2016 + vmImage: 'windows-2019' runAsPublic: ${{ parameters.runAsPublic }} publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }} enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }} @@ -96,4 +96,4 @@ jobs: dependsOn: - Asset_Registry_Publish pool: - vmImage: vs2017-win2016 + vmImage: 'windows-2019' diff --git a/global.json b/global.json index 8f2190165..c0accb00e 100644 --- a/global.json +++ b/global.json @@ -3,7 +3,7 @@ "dotnet": "6.0.100-rc.1.21430.12" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21524.1", + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21529.1", "Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21524.4" } -- cgit v1.2.3 From 0881e462ab279239e023b58bf1d10611ee2183b3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 12:27:33 +0000 Subject: Update dependencies from https://github.com/dotnet/runtime build 20211101.1 (#2346) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ee4e1efba..297c0de70 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -12,9 +12,9 @@ https://github.com/dotnet/arcade 0558f85d950fee2838bf02b9ba1f20d67f00b504 - + https://github.com/dotnet/runtime - 9e795c014b0be513c84f96427c544bae486bb101 + 2a87ffeaedb6b534d6eaa000d5ba9b545f4aac1e - 7.0.0-alpha.1.21524.4 + 7.0.0-alpha.1.21551.1 $(MicrosoftNETSdkILPackageVersion) diff --git a/global.json b/global.json index c0accb00e..508c398a4 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21529.1", "Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21524.4" + "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21551.1" } } -- cgit v1.2.3 From 8e455f03b6a196ea4096f3eacdcc9b146be1e866 Mon Sep 17 00:00:00 2001 From: Tlakaelel Axayakatl Ceja Date: Tue, 2 Nov 2021 15:50:38 -0700 Subject: Test Restructure (#2336) Move RequiresAssemblyFiles from Analyzer to the linker RequiresCapability file Move the new constraint code from RequiresUnreferencedCode to be on the base Requires file Add Warning Id to messages from the analyzer to distinguish in a test which analyzer missed/found a warning Add RequiresAssemblyFilesMismatchAttribute Title and Message to fix bug Add testing in linker for mismatching attributes Add testing in linker for Delegates in CompilerGenerated file Add support for static constructor compiler-generated calls Add additional warnings from DAM and RUC interaction. Not supported by the analyzer yet --- src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs | 46 ++ .../RequiresAssemblyFilesAnalyzer.cs | 6 +- .../RequiresUnreferencedCodeAnalyzer.cs | 56 --- src/ILLink.Shared/DiagnosticId.cs | 2 +- src/ILLink.Shared/SharedStrings.resx | 6 + .../ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs | 2 +- .../RequiresAssemblyFilesAnalyzerTests.cs | 555 --------------------- .../RequiresUnreferencedCodeAnalyzerTests.cs | 550 -------------------- test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs | 2 +- .../Assertions/LogContainsAttribute.cs | 4 + .../Assertions/LogDoesNotContainAttribute.cs | 6 + .../Dependencies/ReferenceInterfaces.cs | 44 ++ .../Dependencies/RequiresInCopyAssembly.cs | 13 + .../RequiresCapability/RequiresCapability.cs | 355 ++++++++++++- .../RequiresCapabilityFromCopiedAssembly.cs | 1 + .../RequiresInCompilerGeneratedCode.cs | 233 +++++++++ .../TestCasesRunner/ResultChecker.cs | 3 + 17 files changed, 716 insertions(+), 1168 deletions(-) create mode 100644 test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs diff --git a/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs b/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs index 05e97d464..c57a8aecd 100644 --- a/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs +++ b/src/ILLink.RoslynAnalyzer/RequiresAnalyzerBase.cs @@ -8,6 +8,7 @@ using System.Linq; using ILLink.Shared; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Operations; @@ -144,6 +145,51 @@ namespace ILLink.RoslynAnalyzer CheckCalledMember (operationContext, methodSymbol, incompatibleMembers); }, OperationKind.DelegateCreation); + context.RegisterSyntaxNodeAction (syntaxNodeAnalysisContext => { + var model = syntaxNodeAnalysisContext.SemanticModel; + if (syntaxNodeAnalysisContext.ContainingSymbol is not ISymbol containingSymbol || containingSymbol.HasAttribute (RequiresAttributeName)) + return; + + GenericNameSyntax genericNameSyntaxNode = (GenericNameSyntax) syntaxNodeAnalysisContext.Node; + var typeParams = ImmutableArray.Empty; + var typeArgs = ImmutableArray.Empty; + switch (model.GetSymbolInfo (genericNameSyntaxNode).Symbol) { + case INamedTypeSymbol typeSymbol: + typeParams = typeSymbol.TypeParameters; + typeArgs = typeSymbol.TypeArguments; + break; + + case IMethodSymbol methodSymbol: + typeParams = methodSymbol.TypeParameters; + typeArgs = methodSymbol.TypeArguments; + break; + + default: + return; + } + + for (int i = 0; i < typeParams.Length; i++) { + var typeParam = typeParams[i]; + var typeArg = typeArgs[i]; + if (!typeParam.HasConstructorConstraint) + continue; + + var typeArgCtors = ((INamedTypeSymbol) typeArg).InstanceConstructors; + foreach (var instanceCtor in typeArgCtors) { + if (instanceCtor.Arity > 0) + continue; + + if (instanceCtor.TryGetAttribute (RequiresAttributeName, out var requiresUnreferencedCodeAttribute)) { + syntaxNodeAnalysisContext.ReportDiagnostic (Diagnostic.Create (RequiresDiagnosticRule, + syntaxNodeAnalysisContext.Node.GetLocation (), + containingSymbol.GetDisplayName (), + (string) requiresUnreferencedCodeAttribute.ConstructorArguments[0].Value!, + GetUrlFromAttribute (requiresUnreferencedCodeAttribute))); + } + } + } + }, SyntaxKind.GenericName); + // Register any extra operation actions supported by the analyzer. foreach (var extraOperationAction in ExtraOperationActions) context.RegisterOperationAction (extraOperationAction.Action, extraOperationAction.OperationKind); diff --git a/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs b/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs index 146eef064..f2e14ff60 100644 --- a/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/RequiresAssemblyFilesAnalyzer.cs @@ -24,9 +24,9 @@ namespace ILLink.RoslynAnalyzer static readonly DiagnosticDescriptor s_requiresAssemblyFilesRule = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.RequiresAssemblyFiles, helpLinkUri: "https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/il3002"); - static readonly DiagnosticDescriptor s_requiresAssembyFilesAttributeMismatch = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.RequiresAssembyFilesAttributeMismatch); + static readonly DiagnosticDescriptor s_requiresAssemblyFilesAttributeMismatch = DiagnosticDescriptors.GetDiagnosticDescriptor (DiagnosticId.RequiresAssemblyFilesAttributeMismatch); - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_locationRule, s_getFilesRule, s_requiresAssemblyFilesRule, s_requiresAssembyFilesAttributeMismatch); + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_locationRule, s_getFilesRule, s_requiresAssemblyFilesRule, s_requiresAssemblyFilesAttributeMismatch); private protected override string RequiresAttributeName => RequiresAssemblyFilesAttribute; @@ -36,7 +36,7 @@ namespace ILLink.RoslynAnalyzer private protected override DiagnosticDescriptor RequiresDiagnosticRule => s_requiresAssemblyFilesRule; - private protected override DiagnosticDescriptor RequiresAttributeMismatch => s_requiresAssembyFilesAttributeMismatch; + private protected override DiagnosticDescriptor RequiresAttributeMismatch => s_requiresAssemblyFilesAttributeMismatch; protected override bool IsAnalyzerEnabled (AnalyzerOptions options, Compilation compilation) { diff --git a/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs b/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs index ba060ccf0..7e4f7e5a2 100644 --- a/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs +++ b/src/ILLink.RoslynAnalyzer/RequiresUnreferencedCodeAnalyzer.cs @@ -3,11 +3,8 @@ using System; using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; using ILLink.Shared; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; namespace ILLink.RoslynAnalyzer @@ -35,56 +32,6 @@ namespace ILLink.RoslynAnalyzer operationContext.Operation.Syntax.GetLocation ())); }; - [SuppressMessage ("MicrosoftCodeAnalysisPerformance", "RS1008", - Justification = "Storing per-compilation data inside a diagnostic analyzer might cause stale compilations to remain alive." + - "This action is registered through a compilation start action, so that instances that register this syntax" + - " node action will not outlive a compilation's lifetime, avoiding the possibility of the locals stored in" + - " this function to cause for any stale compilations to remain in memory.")] - static readonly Action s_constructorConstraint = syntaxNodeAnalysisContext => { - var model = syntaxNodeAnalysisContext.SemanticModel; - if (syntaxNodeAnalysisContext.ContainingSymbol is not ISymbol containingSymbol || containingSymbol.HasAttribute (RequiresUnreferencedCodeAttribute)) - return; - - GenericNameSyntax genericNameSyntaxNode = (GenericNameSyntax) syntaxNodeAnalysisContext.Node; - var typeParams = ImmutableArray.Empty; - var typeArgs = ImmutableArray.Empty; - switch (model.GetSymbolInfo (genericNameSyntaxNode).Symbol) { - case INamedTypeSymbol typeSymbol: - typeParams = typeSymbol.TypeParameters; - typeArgs = typeSymbol.TypeArguments; - break; - - case IMethodSymbol methodSymbol: - typeParams = methodSymbol.TypeParameters; - typeArgs = methodSymbol.TypeArguments; - break; - - default: - return; - } - - for (int i = 0; i < typeParams.Length; i++) { - var typeParam = typeParams[i]; - var typeArg = typeArgs[i]; - if (!typeParam.HasConstructorConstraint) - continue; - - var typeArgCtors = ((INamedTypeSymbol) typeArg).InstanceConstructors; - foreach (var instanceCtor in typeArgCtors) { - if (instanceCtor.Arity > 0) - continue; - - if (instanceCtor.TryGetAttribute (RequiresUnreferencedCodeAttribute, out var requiresUnreferencedCodeAttribute)) { - syntaxNodeAnalysisContext.ReportDiagnostic (Diagnostic.Create (s_requiresUnreferencedCodeRule, - syntaxNodeAnalysisContext.Node.GetLocation (), - containingSymbol.GetDisplayName (), - (string) requiresUnreferencedCodeAttribute.ConstructorArguments[0].Value!, - GetUrlFromAttribute (requiresUnreferencedCodeAttribute))); - } - } - } - }; - public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create (s_dynamicTypeInvocationRule, s_makeGenericMethodRule, s_makeGenericTypeRule, s_requiresUnreferencedCodeRule, s_requiresUnreferencedCodeAttributeMismatch); @@ -133,9 +80,6 @@ namespace ILLink.RoslynAnalyzer private protected override ImmutableArray<(Action Action, OperationKind[] OperationKind)> ExtraOperationActions => ImmutableArray.Create ((s_dynamicTypeInvocation, new OperationKind[] { OperationKind.DynamicInvocation })); - private protected override ImmutableArray<(Action Action, SyntaxKind[] SyntaxKind)> ExtraSyntaxNodeActions => - ImmutableArray.Create ((s_constructorConstraint, new SyntaxKind[] { SyntaxKind.GenericName })); - protected override bool VerifyAttributeArguments (AttributeData attribute) => attribute.ConstructorArguments.Length >= 1 && attribute.ConstructorArguments[0] is { Type: { SpecialType: SpecialType.System_String } } ctorArg; diff --git a/src/ILLink.Shared/DiagnosticId.cs b/src/ILLink.Shared/DiagnosticId.cs index 6720edbc4..8fe4fc2fe 100644 --- a/src/ILLink.Shared/DiagnosticId.cs +++ b/src/ILLink.Shared/DiagnosticId.cs @@ -14,7 +14,7 @@ AvoidAssemblyLocationInSingleFile = 3000, AvoidAssemblyGetFilesInSingleFile = 3001, RequiresAssemblyFiles = 3002, - RequiresAssembyFilesAttributeMismatch = 3003 + RequiresAssemblyFilesAttributeMismatch = 3003 } public static class DiagnosticIdExtensions diff --git a/src/ILLink.Shared/SharedStrings.resx b/src/ILLink.Shared/SharedStrings.resx index 807f96a88..36ce24594 100644 --- a/src/ILLink.Shared/SharedStrings.resx +++ b/src/ILLink.Shared/SharedStrings.resx @@ -147,6 +147,12 @@ 'RequiresUnreferencedCodeAttribute' annotations must match across all interface implementations or overrides. + + {0}. 'RequiresAssemblyFilesAttribute' annotations must match across all interface implementations or overrides. + + + 'RequiresAssemblyFilesAttribute' annotations must match across all interface implementations or overrides. + Base member '{2}' with '{0}' has a derived member '{1}' without '{0}' diff --git a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs index fed1cbfe6..bade900f4 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs @@ -16,7 +16,7 @@ namespace ILLink.RoslynAnalyzer.Tests [MemberData (nameof (TestCaseUtils.GetTestData), parameters: nameof (RequiresCapability))] public void RequiresCapability (string m) { - RunTest (nameof (RequiresCapability), m, UseMSBuildProperties (MSBuildPropertyOptionNames.EnableTrimAnalyzer)); + RunTest (nameof (RequiresCapability), m, UseMSBuildProperties (MSBuildPropertyOptionNames.EnableTrimAnalyzer, MSBuildPropertyOptionNames.EnableSingleFileAnalyzer)); } [Theory] diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs index a4bdc5be5..7e27f2782 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs @@ -77,29 +77,6 @@ class C VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (12, 17, 12, 18).WithArguments ("C.E", "", "")); } - [Fact] - public Task SimpleDiagnosticOnMethod () - { - var TestRequiresAssemblyFilesOnMethod = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - [RequiresAssemblyFiles] - void M1() - { - } - - void M2() - { - M1(); - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (TestRequiresAssemblyFilesOnMethod, - // (13,3): warning IL3002: Using member 'C.M1()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (13, 3, 13, 7).WithArguments ("C.M1()", "", "")); - } - [Fact] public Task SimpleDiagnosticOnProperty () { @@ -159,29 +136,6 @@ class C VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (24, 3, 24, 4).WithArguments ("C.P", "", "")); } - [Fact] - public Task RequiresAssemblyFilesWithMessageAndUrl () - { - var TestRequiresAssemblyFilesWithMessageAndUrl = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - [RequiresAssemblyFiles (""Message from attribute"", Url = ""https://helpurl"")] - void M1() - { - } - - void M2() - { - M1(); - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (TestRequiresAssemblyFilesWithMessageAndUrl, - // (13,3): warning IL3002: Using member 'C.M1()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. Message from attribute. https://helpurl - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (13, 3, 13, 7).WithArguments ("C.M1()", " Message from attribute.", " https://helpurl")); - } - [Fact] public Task RequiresAssemblyFilesWithUrlOnly () { @@ -394,53 +348,6 @@ class C return VerifyRequiresAssemblyFilesAnalyzer (src); } - [Fact] - public Task LazyDelegateWithRequiresAssemblyFiles () - { - const string src = @" -using System; -using System.Diagnostics.CodeAnalysis; -class C -{ - public static Lazy _default = new Lazy(InitC); - public static C Default => _default.Value; - - [RequiresAssemblyFiles] - public static C InitC() { - C cObject = new C(); - return cObject; - } -}"; - - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (6,50): warning IL3002: Using member 'C.InitC()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (6, 50, 6, 55).WithArguments ("C.InitC()", "", "")); - } - - [Fact] - public Task ActionDelegateWithRequiresAssemblyFiles () - { - const string src = @" -using System; -using System.Diagnostics.CodeAnalysis; -class C -{ - [RequiresAssemblyFiles] - public static void M1() { } - public static void M2() - { - Action a = M1; - Action b = () => M1(); - } -}"; - - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (10,20): warning IL3002: Using member 'C.M1()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (10, 20, 10, 22).WithArguments ("C.M1()", "", ""), - // (11,26): warning IL3002: Using member 'C.M1()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (11, 26, 11, 30).WithArguments ("C.M1()", "", "")); - } - [Fact] public Task RequiresAssemblyFilesDiagnosticFix () { @@ -767,467 +674,5 @@ public class C }, fixedExpected: Array.Empty ()); } - - [Fact] - public Task TestStaticCctorRequiresAssemblyFiles () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtor -{ - [RequiresAssemblyFiles (""Message for --TestStaticCtor--"")] - static StaticCtor () - { - } - - static void TestStaticCctorRequiresUnreferencedCode () - { - _ = new StaticCtor (); - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src); - } - - [Fact] - public Task StaticCtorTriggeredByFieldAccess () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtorTriggeredByFieldAccess -{ - public static int field; - - [RequiresAssemblyFiles (""Message for --StaticCtorTriggeredByFieldAccess.Cctor--"")] - static StaticCtorTriggeredByFieldAccess () - { - field = 0; - } -} -class C -{ - static void TestStaticCtorMarkingIsTriggeredByFieldAccess () - { - var x = StaticCtorTriggeredByFieldAccess.field + 1; - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src); - } - - [Fact] - public Task TestStaticCtorTriggeredByMethodCall () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtorTriggeredByMethodCall -{ - [RequiresAssemblyFiles (""Message for --StaticCtorTriggeredByMethodCall.Cctor--"")] - static StaticCtorTriggeredByMethodCall () - { - } - - [RequiresAssemblyFiles (""Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--"")] - public void TriggerStaticCtorMarking () - { - } -} - -class C -{ - static void TestStaticCtorTriggeredByMethodCall () - { - new StaticCtorTriggeredByMethodCall ().TriggerStaticCtorMarking (); - } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (21,3): warning IL3002: Using member 'StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking()' which has 'RequiresAssemblyFilesAttribute' can break functionality when embedded in a single-file app. Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssemblyFiles).WithSpan (21, 3, 21, 69).WithArguments ("StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking()", " Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--.", "") - ); - } - - [Fact] - public Task OverrideHasAttributeButBaseDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class DerivedClass : BaseClass -{ - [RequiresAssemblyFiles] - public override void VirtualMethod () - { - } - - private string name; - public override string VirtualPropertyWithAnnotationInAccesor - { - [RequiresAssemblyFiles] - get { return name; } - set { name = value; } - } - - [RequiresAssemblyFiles] - public override string VirtualPropertyWithAnnotationInProperty { get; set; } -} - -class BaseClass -{ - public virtual void VirtualMethod () - { - } - - public virtual string VirtualPropertyWithAnnotationInAccesor { get; set; } - - public virtual string VirtualPropertyWithAnnotationInProperty { get; set; } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (7,23): warning IL3003: Member 'DerivedClass.VirtualMethod()' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualMethod()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (7, 23, 7, 36).WithArguments ("Member 'DerivedClass.VirtualMethod()' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualMethod()' without 'RequiresAssemblyFilesAttribute'"), - // (15,3): warning IL3003: Member 'DerivedClass.VirtualPropertyWithAnnotationInAccesor.get' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualPropertyWithAnnotationInAccesor.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (15, 3, 15, 6).WithArguments ("Member 'DerivedClass.VirtualPropertyWithAnnotationInAccesor.get' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualPropertyWithAnnotationInAccesor.get' without 'RequiresAssemblyFilesAttribute'"), - // (20,25): warning IL3003: Member 'DerivedClass.VirtualPropertyWithAnnotationInProperty' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualPropertyWithAnnotationInProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (20, 25, 20, 64).WithArguments ("Member 'DerivedClass.VirtualPropertyWithAnnotationInProperty' with 'RequiresAssemblyFilesAttribute' overrides base member 'BaseClass.VirtualPropertyWithAnnotationInProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public Task VirtualHasAttributeButOverrideDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class DerivedClass : BaseClass -{ - public override void VirtualMethod () - { - } - - private string name; - public override string VirtualPropertyWithAnnotationInAccesor - { - get { return name; } - set { name = value; } - } - - public override string VirtualPropertyWithAnnotationInProperty { get; set; } -} - -class BaseClass -{ - [RequiresAssemblyFiles] - public virtual void VirtualMethod () - { - } - - public virtual string VirtualPropertyWithAnnotationInAccesor {[RequiresAssemblyFiles] get; set; } - - [RequiresAssemblyFiles] - public virtual string VirtualPropertyWithAnnotationInProperty { get; set; } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (6,23): warning IL3003: Base member 'BaseClass.VirtualMethod()' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualMethod()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (6, 23, 6, 36).WithArguments ("Base member 'BaseClass.VirtualMethod()' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualMethod()' without 'RequiresAssemblyFilesAttribute'"), - // (13,3): warning IL3003: Base member 'BaseClass.VirtualPropertyWithAnnotationInAccesor.get' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualPropertyWithAnnotationInAccesor.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Base member 'BaseClass.VirtualPropertyWithAnnotationInAccesor.get' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualPropertyWithAnnotationInAccesor.get' without 'RequiresAssemblyFilesAttribute'"), - // (17,25): warning IL3003: Base member 'BaseClass.VirtualPropertyWithAnnotationInProperty' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualPropertyWithAnnotationInProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (17, 25, 17, 64).WithArguments ("Base member 'BaseClass.VirtualPropertyWithAnnotationInProperty' with 'RequiresAssemblyFilesAttribute' has a derived member 'DerivedClass.VirtualPropertyWithAnnotationInProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public Task ImplementationHasAttributeButInterfaceDoesnt () - { - // Once the interface has the attributes indicated in the warnings we would have warnings for AnotherImplementation. - // In the meantime AnotherImplementation doesn't generate a warning - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRAF -{ - [RequiresAssemblyFiles] - public void Method () { } - - private string name; - public string StringProperty - { - [RequiresAssemblyFiles] - get { return name; } - set { name = value; } - } - - private int num; - [RequiresAssemblyFiles] - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class ExplicitImplementation : IRAF -{ - [RequiresAssemblyFiles] - void IRAF.Method() { } - - private string name; - string IRAF.StringProperty - { - [RequiresAssemblyFiles] - get { return name; } - set { name = value; } - } - - private int num; - [RequiresAssemblyFiles] - int IRAF.NumProperty - { - get { return num; } - set { num = value; } - } -} - -interface IRAF -{ - void Method(); - string StringProperty { get; set; } - int NumProperty { get; set; } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (7,14): warning IL3003: Member 'Implementation.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (7, 14, 7, 20).WithArguments ("Member 'Implementation.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (13,3): warning IL3003: Member 'Implementation.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Member 'Implementation.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (19,13): warning IL3003: Member 'Implementation.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (19, 13, 19, 24).WithArguments ("Member 'Implementation.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'"), - // (48,12): warning IL3003: Member 'ExplicitImplementation.IRAF.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (48, 12, 48, 18).WithArguments ("Member 'ExplicitImplementation.IRAF.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (54,3): warning IL3003: Member 'ExplicitImplementation.IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (54, 3, 54, 6).WithArguments ("Member 'ExplicitImplementation.IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (60,11): warning IL3003: Member 'ExplicitImplementation.IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (60, 11, 60, 22).WithArguments ("Member 'ExplicitImplementation.IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public Task InterfaceHasAttributeButImplementationDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -interface IRAF -{ - [RequiresAssemblyFiles] - void Method(); - string StringProperty { [RequiresAssemblyFiles] get; set; } - [RequiresAssemblyFiles] - int NumProperty { get; set; } -}"; - return VerifyRequiresAssemblyFilesAnalyzer (src, - // (6,14): warning IL3003: Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (6, 14, 6, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (11,3): warning IL3003: Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (11, 3, 11, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (16,13): warning IL3003: Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (16, 13, 16, 24).WithArguments ("Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.NumProperty' without 'RequiresAssemblyFilesAttribute'"), - // (25,14): warning IL3003: Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (25, 14, 25, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (30,3): warning IL3003: Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (30, 3, 30, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (35,13): warning IL3003: Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (35, 13, 35, 24).WithArguments ("Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.NumProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public async Task MissingRAFAttributeOnSource () - { - var references = @" -using System.Diagnostics.CodeAnalysis; - -public interface IRAF -{ - [RequiresAssemblyFiles] - void Method(); - string StringProperty { [RequiresAssemblyFiles] get; set; } - [RequiresAssemblyFiles] - int NumProperty { get; set; } -}"; - - var src = @" -class Implementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} -"; - var compilation = (await TestCaseCompilation.GetCompilation (references)).EmitToImageReference (); - - await VerifyRequiresAssemblyFilesAnalyzer (src, additionalReferences: new[] { compilation }, - // (4,14): warning IL3003: Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (4, 14, 4, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (9,3): warning IL3003: Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (9, 3, 9, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (14,13): warning IL3003: Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (14, 13, 14, 24).WithArguments ("Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'Implementation.NumProperty' without 'RequiresAssemblyFilesAttribute'"), - // (23,14): warning IL3003: Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (23, 14, 23, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (28,3): warning IL3003: Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (28, 3, 28, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (33,13): warning IL3003: Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (33, 13, 33, 24).WithArguments ("Interface member 'IRAF.NumProperty' with 'RequiresAssemblyFilesAttribute' has an implementation member 'AnotherImplementation.NumProperty' without 'RequiresAssemblyFilesAttribute'")); - } - - [Fact] - public async Task MissingRAFAttributeOnReference () - { - var references = @" -public interface IRAF -{ - void Method(); - string StringProperty { get; set; } - int NumProperty { get; set; } -}"; - - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRAF -{ - [RequiresAssemblyFiles] - public void Method () { } - - private string name; - public string StringProperty - { - [RequiresAssemblyFiles] - get { return name; } - set { name = value; } - } - - private int num; - [RequiresAssemblyFiles] - public int NumProperty - { - get { return num; } - set { num = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } - - private int num; - public int NumProperty - { - get { return num; } - set { num = value; } - } -} -"; - var compilation = (await TestCaseCompilation.GetCompilation (references)).EmitToImageReference (); - - await VerifyRequiresAssemblyFilesAnalyzer (src, additionalReferences: new[] { compilation }, - // (7,14): warning IL3003: Member 'Implementation.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (7, 14, 7, 20).WithArguments ("Member 'Implementation.Method()' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.Method()' without 'RequiresAssemblyFilesAttribute'"), - // (13,3): warning IL3003: Member 'Implementation.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Member 'Implementation.StringProperty.get' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresAssemblyFilesAttribute'"), - // (19,13): warning IL3003: Member 'Implementation.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresAssembyFilesAttributeMismatch).WithSpan (19, 13, 19, 24).WithArguments ("Member 'Implementation.NumProperty' with 'RequiresAssemblyFilesAttribute' implements interface member 'IRAF.NumProperty' without 'RequiresAssemblyFilesAttribute'")); - } } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs index 9cb7d8995..b54b65f8e 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs @@ -54,22 +54,7 @@ build_property.{MSBuildPropertyOptionNames.EnableTrimAnalyzer} = true"))); return test.RunAsync (); } - [Fact] - public Task SimpleDiagnostic () - { - var TestRequiresWithMessageOnlyOnMethod = @" -using System.Diagnostics.CodeAnalysis; -class C -{ - [RequiresUnreferencedCodeAttribute(""message"")] - int M1() => 0; - int M2() => M1(); -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (TestRequiresWithMessageOnlyOnMethod, - // (8,17): warning IL2026: Using member 'C.M1()' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. message. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 17, 8, 21).WithArguments ("C.M1()", " message.", "")); - } [Fact] public async Task SimpleDiagnosticFix () @@ -321,541 +306,6 @@ public class C }); } - [Fact] - public Task TestRequiresWithMessageAndUrlOnMethod () - { - var MessageAndUrlOnMethod = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - static void TestRequiresWithMessageAndUrlOnMethod () - { - RequiresWithMessageAndUrl (); - } - [RequiresUnreferencedCode (""Message for --RequiresWithMessageAndUrl--"", Url = ""https://helpurl"")] - static void RequiresWithMessageAndUrl () - { - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (MessageAndUrlOnMethod, - // (8,3): warning IL2026: Using member 'C.RequiresWithMessageAndUrl()' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --RequiresWithMessageAndUrl--. https://helpurl - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 3, 8, 31).WithArguments ("C.RequiresWithMessageAndUrl()", " Message for --RequiresWithMessageAndUrl--.", " https://helpurl") - ); - } - - [Fact] - public Task TestTrailingPeriodsOnWarningMessageAreNotDupplicated () - { - var source = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - [RequiresUnreferencedCode (""Warning message"")] - static void MessageWithoutTrailingPeriod () - { - } - - [RequiresUnreferencedCode (""Warning message."")] - static void MessageWithTrailingPeriod () - { - } - - static void Test () - { - MessageWithoutTrailingPeriod (); - MessageWithTrailingPeriod (); - } -}"; - - return VerifyRequiresUnreferencedCodeAnalyzer (source, - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (18, 3, 18, 34).WithArguments ("C.MessageWithoutTrailingPeriod()", " Warning message.", string.Empty), - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (19, 3, 19, 31).WithArguments ("C.MessageWithTrailingPeriod()", " Warning message.", string.Empty)); - } - - [Fact] - public Task TestRequiresOnPropertyGetter () - { - var PropertyRequires = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - static void TestRequiresOnPropertyGetter () - { - _ = PropertyRequires; - } - - static int PropertyRequires { - [RequiresUnreferencedCode (""Message for --getter PropertyRequires--"")] - get { return 42; } - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (PropertyRequires, - // (8,7): warning IL2026: Using member 'C.PropertyRequires.get' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --getter PropertyRequires--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 7, 8, 23).WithArguments ("C.PropertyRequires.get", " Message for --getter PropertyRequires--.", "") - ); - } - - [Fact] - public Task TestRequiresOnPropertySetter () - { - var PropertyRequires = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - static void TestRequiresOnPropertySetter () - { - PropertyRequires = 0; - } - - static int PropertyRequires { - [RequiresUnreferencedCode (""Message for --setter PropertyRequires--"")] - set { } - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (PropertyRequires, - // (8,3): warning IL2026: Using member 'C.PropertyRequires.set' which has `RequiresUnreferencedCodeAttribute` can break functionality when trimming application code. Message for --setter PropertyRequires--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 3, 8, 19).WithArguments ("C.PropertyRequires.set", " Message for --setter PropertyRequires--.", "") - ); - } - - [Fact] - public Task TestStaticCctorRequiresUnreferencedCode () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtor -{ - [RequiresUnreferencedCode (""Message for --TestStaticCtor--"")] - static StaticCtor () - { - } - - static void TestStaticCctorRequiresUnreferencedCode () - { - _ = new StaticCtor (); - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src); - } - - [Fact] - public Task StaticCtorTriggeredByFieldAccess () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtorTriggeredByFieldAccess -{ - public static int field; - - [RequiresUnreferencedCode (""Message for --StaticCtorTriggeredByFieldAccess.Cctor--"")] - static StaticCtorTriggeredByFieldAccess () - { - field = 0; - } -} -class C -{ - static void TestStaticCtorMarkingIsTriggeredByFieldAccess () - { - var x = StaticCtorTriggeredByFieldAccess.field + 1; - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src); - } - - [Fact] - public Task TestStaticCtorTriggeredByMethodCall () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class StaticCtorTriggeredByMethodCall -{ - [RequiresUnreferencedCode (""Message for --StaticCtorTriggeredByMethodCall.Cctor--"")] - static StaticCtorTriggeredByMethodCall () - { - } - - [RequiresUnreferencedCode (""Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--"")] - public void TriggerStaticCtorMarking () - { - } -} - -class C -{ - static void TestStaticCtorTriggeredByMethodCall () - { - new StaticCtorTriggeredByMethodCall ().TriggerStaticCtorMarking (); - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (21,3): warning IL2026: Using member 'StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (21, 3, 21, 69).WithArguments ("StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking()", " Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--.", "") - ); - } - - [Fact] - public Task TypeIsBeforeFieldInit () - { - var TypeIsBeforeFieldInit = @" -using System.Diagnostics.CodeAnalysis; - -class C -{ - class TypeIsBeforeFieldInit - { - public static int field = AnnotatedMethod (); - - [RequiresUnreferencedCode (""Message from --TypeIsBeforeFieldInit.AnnotatedMethod--"")] - public static int AnnotatedMethod () => 42; - } - - static void TestTypeIsBeforeFieldInit () - { - var x = TypeIsBeforeFieldInit.field + 42; - } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (TypeIsBeforeFieldInit, - // (8,29): warning IL2026: Using member 'C.TypeIsBeforeFieldInit.AnnotatedMethod()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message from --TypeIsBeforeFieldInit.AnnotatedMethod--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (8, 29, 8, 47).WithArguments ("C.TypeIsBeforeFieldInit.AnnotatedMethod()", " Message from --TypeIsBeforeFieldInit.AnnotatedMethod--.", "") - ); - } - - [Fact] - public Task LazyDelegateWithRequiresUnreferencedCode () - { - const string src = @" -using System; -using System.Diagnostics.CodeAnalysis; -class C -{ - public static Lazy _default = new Lazy(InitC); - public static C Default => _default.Value; - - [RequiresUnreferencedCode (""Message from --C.InitC--"")] - public static C InitC() { - C cObject = new C(); - return cObject; - } -}"; - - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (6,50): warning IL2026: Using member 'C.InitC()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message from --C.InitC--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (6, 50, 6, 55).WithArguments ("C.InitC()", " Message from --C.InitC--.", "")); - } - - [Fact] - public Task ActionDelegateWithRequiresAssemblyFiles () - { - const string src = @" -using System; -using System.Diagnostics.CodeAnalysis; -class C -{ - [RequiresUnreferencedCode (""Message from --C.M1--"")] - public static void M1() { } - public static void M2() - { - Action a = M1; - Action b = () => M1(); - } -}"; - - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (10,20): warning IL2026: Using member 'C.M1()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message from --C.M1--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (10, 20, 10, 22).WithArguments ("C.M1()", " Message from --C.M1--.", ""), - // (11,26): warning IL2026: Using member 'C.M1()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. Message from --C.M1--. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCode).WithSpan (11, 26, 11, 30).WithArguments ("C.M1()", " Message from --C.M1--.", "")); - } - - [Fact] - public Task OverrideHasAttributeButBaseDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class DerivedClass : BaseClass -{ - [RequiresUnreferencedCode(""Message"")] - public override void VirtualMethod () - { - } - - private string name; - public override string VirtualProperty - { - [RequiresUnreferencedCode(""Message"")] - get { return name; } - set { name = value; } - } -} - -class BaseClass -{ - public virtual void VirtualMethod () - { - } - - public virtual string VirtualProperty { get; set; } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (7,23): warning IL2046: Member 'DerivedClass.VirtualMethod()' with 'RequiresUnreferencedCodeAttribute' overrides base member 'BaseClass.VirtualMethod()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (7, 23, 7, 36).WithArguments ("Member 'DerivedClass.VirtualMethod()' with 'RequiresUnreferencedCodeAttribute' overrides base member 'BaseClass.VirtualMethod()' without 'RequiresUnreferencedCodeAttribute'"), - // (15,3): warning IL2046: Member 'DerivedClass.VirtualProperty.get' with 'RequiresUnreferencedCodeAttribute' overrides base member 'BaseClass.VirtualProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (15, 3, 15, 6).WithArguments ("Member 'DerivedClass.VirtualProperty.get' with 'RequiresUnreferencedCodeAttribute' overrides base member 'BaseClass.VirtualProperty.get' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public Task VirtualHasAttributeButOverrideDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class DerivedClass : BaseClass -{ - public override void VirtualMethod () - { - } - - private string name; - public override string VirtualProperty - { - get { return name; } - set { name = value; } - } -} - -class BaseClass -{ - [RequiresUnreferencedCode(""Message"")] - public virtual void VirtualMethod () - { - } - - public virtual string VirtualProperty {[RequiresUnreferencedCode(""Message"")] get; set; } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (13,3): warning IL2046: Base member 'BaseClass.VirtualProperty.get' with 'RequiresUnreferencedCodeAttribute' has a derived member 'DerivedClass.VirtualProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Base member 'BaseClass.VirtualProperty.get' with 'RequiresUnreferencedCodeAttribute' has a derived member 'DerivedClass.VirtualProperty.get' without 'RequiresUnreferencedCodeAttribute'"), - // (6,23): warning IL2046: Base member 'BaseClass.VirtualMethod()' with 'RequiresUnreferencedCodeAttribute' has a derived member 'DerivedClass.VirtualMethod()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (6, 23, 6, 36).WithArguments ("Base member 'BaseClass.VirtualMethod()' with 'RequiresUnreferencedCodeAttribute' has a derived member 'DerivedClass.VirtualMethod()' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public Task ImplementationHasAttributeButInterfaceDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRUC -{ - [RequiresUnreferencedCode(""Message"")] - public void RUC () { } - - private string name; - public string Property - { - [RequiresUnreferencedCode(""Message"")] - get { return name; } - set { name = value; } - } -} - -class AnotherImplementation : IRUC -{ - public void RUC () { } - - private string name; - public string Property - { - get { return name; } - set { name = value; } - } -} - -class ExplicitImplementation : IRUC -{ - [RequiresUnreferencedCode(""Message"")] - void IRUC.RUC() { } - - private string name; - string IRUC.Property - { - [RequiresUnreferencedCode(""Message"")] - get { return name; } - set { name = value; } - } -} - -interface IRUC -{ - void RUC(); - string Property { get; set; } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (7,14): warning IL2046: Member 'Implementation.RUC()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.RUC()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (7, 14, 7, 17).WithArguments ("Member 'Implementation.RUC()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.RUC()' without 'RequiresUnreferencedCodeAttribute'"), - // (13,3): warning IL2046: Member 'Implementation.Property.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.Property.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Member 'Implementation.Property.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.Property.get' without 'RequiresUnreferencedCodeAttribute'"), - // (33,12): warning IL2046: Member 'ExplicitImplementation.IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.RUC()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (33, 12, 33, 15).WithArguments ("Member 'ExplicitImplementation.IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.RUC()' without 'RequiresUnreferencedCodeAttribute'"), - // (39,3): warning IL2046: Member 'ExplicitImplementation.IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.Property.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (39, 3, 39, 6).WithArguments ("Member 'ExplicitImplementation.IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRUC.Property.get' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public Task InterfaceHasAttributeButImplementationDoesnt () - { - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRUC -{ - public void RUC () { } - - private string name; - public string Property - { - get { return name; } - set { name = value; } - } -} - -class AnotherImplementation : IRUC -{ - public void RUC () { } - - private string name; - public string Property - { - get { return name; } - set { name = value; } - } -} - -interface IRUC -{ - [RequiresUnreferencedCode(""Message"")] - void RUC(); - string Property {[RequiresUnreferencedCode(""Message"")] get; set; } -}"; - return VerifyRequiresUnreferencedCodeAnalyzer (src, - // (6,14): warning IL2046: Interface member 'IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.RUC()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (6, 14, 6, 17).WithArguments ("Interface member 'IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.RUC()' without 'RequiresUnreferencedCodeAttribute'"), - // (11,3): warning IL2046: Interface member 'IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.Property.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (11, 3, 11, 6).WithArguments ("Interface member 'IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.Property.get' without 'RequiresUnreferencedCodeAttribute'"), - // (18,14): warning IL2046: Interface member 'IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.RUC()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (18, 14, 18, 17).WithArguments ("Interface member 'IRUC.RUC()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.RUC()' without 'RequiresUnreferencedCodeAttribute'"), - // (23,3): warning IL2046: Interface member 'IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.Property.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (23, 3, 23, 6).WithArguments ("Interface member 'IRUC.Property.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.Property.get' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public async Task MissingRAFAttributeOnSource () - { - var references = @" -using System.Diagnostics.CodeAnalysis; - -public interface IRAF -{ - [RequiresUnreferencedCode (""Message"")] - void Method(); - string StringProperty { [RequiresUnreferencedCode (""Message"")] get; set; } -}"; - - var src = @" -class Implementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } -} -"; - var compilation = (await TestCaseCompilation.GetCompilation (references)).EmitToImageReference (); - - await VerifyRequiresUnreferencedCodeAnalyzer (src, additionalReferences: new[] { compilation }, - // (4,14): warning IL2046: Interface member 'IRAF.Method()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.Method()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (4, 14, 4, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.Method()' without 'RequiresUnreferencedCodeAttribute'"), - // (16,14): warning IL2046: Interface member 'IRAF.Method()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (16, 14, 16, 20).WithArguments ("Interface member 'IRAF.Method()' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.Method()' without 'RequiresUnreferencedCodeAttribute'"), - // (9,3): warning IL2046: Interface member 'IRAF.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (9, 3, 9, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'Implementation.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'"), - // (21,3): warning IL2046: Interface member 'IRAF.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (21, 3, 21, 6).WithArguments ("Interface member 'IRAF.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' has an implementation member 'AnotherImplementation.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'")); - } - - [Fact] - public async Task MissingRAFAttributeOnReference () - { - var references = @" -public interface IRAF -{ - void Method(); - string StringProperty { get; set; } -}"; - - var src = @" -using System.Diagnostics.CodeAnalysis; - -class Implementation : IRAF -{ - [RequiresUnreferencedCode (""Message"")] - public void Method () { } - - private string name; - public string StringProperty - { - [RequiresUnreferencedCode (""Message"")] - get { return name; } - set { name = value; } - } -} - -class AnotherImplementation : IRAF -{ - public void Method () { } - - private string name; - public string StringProperty - { - get { return name; } - set { name = value; } - } -} -"; - var compilation = (await TestCaseCompilation.GetCompilation (references)).EmitToImageReference (); - - await VerifyRequiresUnreferencedCodeAnalyzer (src, additionalReferences: new[] { compilation }, - // (7,14): warning IL2046: Member 'Implementation.Method()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRAF.Method()' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (7, 14, 7, 20).WithArguments ("Member 'Implementation.Method()' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRAF.Method()' without 'RequiresUnreferencedCodeAttribute'"), - // (13,3): warning IL2046: Member 'Implementation.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'. Attributes must match across all interface implementations or overrides. - VerifyCS.Diagnostic (DiagnosticId.RequiresUnreferencedCodeAttributeMismatch).WithSpan (13, 3, 13, 6).WithArguments ("Member 'Implementation.StringProperty.get' with 'RequiresUnreferencedCodeAttribute' implements interface member 'IRAF.StringProperty.get' without 'RequiresUnreferencedCodeAttribute'")); - } - [Fact] public Task InvocationOnDynamicType () { diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs index 995825152..e86ee919f 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs @@ -172,7 +172,7 @@ namespace ILLink.RoslynAnalyzer.Tests } } - missingDiagnosticMessage = $"Expected to find warning containing:{string.Join (" ", expectedMessages.Select (m => "'" + m + "'"))}" + + missingDiagnosticMessage = $"Warning '{expectedWarningCode}'. Expected to find warning containing:{string.Join (" ", expectedMessages.Select (m => "'" + m + "'"))}" + $", but no such message was found.{ Environment.NewLine}"; return false; diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs index fe054761b..934512ce5 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs +++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogContainsAttribute.cs @@ -14,6 +14,10 @@ namespace Mono.Linker.Tests.Cases.Expectations.Assertions throw new ArgumentException ("Value cannot be null or empty.", nameof (message)); } + /// + /// Property used by the result checkers of trimmer and analyzers to determine whether + /// the tool should have produced the specified warning on the annotated member. + /// public ProducedBy ProducedBy { get; set; } = ProducedBy.TrimmerAndAnalyzer; } } \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs index 599908cfb..2cd8667ed 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs +++ b/test/Mono.Linker.Tests.Cases.Expectations/Assertions/LogDoesNotContainAttribute.cs @@ -13,5 +13,11 @@ namespace Mono.Linker.Tests.Cases.Expectations.Assertions if (string.IsNullOrEmpty (message)) throw new ArgumentException ("Value cannot be null or empty.", nameof (message)); } + + /// + /// Property used by the result checkers of trimmer and analyzers to determine whether + /// the tool should have produced the specified warning on the annotated member. + /// + public ProducedBy ProducedBy { get; set; } = ProducedBy.TrimmerAndAnalyzer; } } diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs new file mode 100644 index 000000000..e30fd271c --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/ReferenceInterfaces.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies +{ + public class ReferenceInterfaces + { + public interface IBaseWithRequiresInReference + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + public void Method (); + + public string PropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + public string PropertyAnnotationInProperty { get; set; } + } + + public interface IBaseWithoutRequiresInReference + { + public void Method (); + + public string PropertyAnnotationInAccesor { + get; + set; + } + + public string PropertyAnnotationInProperty { get; set; } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/RequiresInCopyAssembly.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/RequiresInCopyAssembly.cs index 74cdff268..c121ff4ef 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/RequiresInCopyAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/Dependencies/RequiresInCopyAssembly.cs @@ -15,24 +15,29 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies } [RequiresUnreferencedCode ("Message for --Method--")] + [RequiresAssemblyFiles ("Message for --Method--")] public void Method () { } [RequiresUnreferencedCode ("Message for --UncalledMethod--")] + [RequiresAssemblyFiles ("Message for --UncalledMethod--")] public void UncalledMethod () { } [RequiresUnreferencedCode ("Message for --MethodCalledThroughReflection--")] + [RequiresAssemblyFiles ("Message for --MethodCalledThroughReflection--")] static void MethodCalledThroughReflection () { } public int UnusedProperty { [RequiresUnreferencedCode ("Message for --getter UnusedProperty--")] + [RequiresAssemblyFiles ("Message for --getter UnusedProperty--")] get { return 42; } + [RequiresAssemblyFiles ("Message for --setter UnusedProperty--")] [RequiresUnreferencedCode ("Message for --setter UnusedProperty--")] set { } } @@ -40,16 +45,19 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies class UnusedBaseType { [RequiresUnreferencedCode ("Message for --UnusedBaseTypeCctor--")] + [RequiresAssemblyFiles ("Message for --UnusedBaseTypeCctor--")] static UnusedBaseType () { } [RequiresUnreferencedCode ("Message for --UnusedVirtualMethod1--")] + [RequiresAssemblyFiles ("Message for --UnusedVirtualMethod1--")] public virtual void UnusedVirtualMethod1 () { } [RequiresUnreferencedCode ("Message for --UnusedVirtualMethod2--")] + [RequiresAssemblyFiles ("Message for --UnusedVirtualMethod2--")] public virtual void UnusedVirtualMethod2 () { } @@ -58,6 +66,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies class UnusedDerivedType : UnusedBaseType { [RequiresUnreferencedCode ("Message for --UnusedVirtualMethod1--")] + [RequiresAssemblyFiles ("Message for --UnusedVirtualMethod1--")] public override void UnusedVirtualMethod1 () { } @@ -71,12 +80,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies interface IUnusedInterface { [RequiresUnreferencedCode ("Message for --IUnusedInterface.UnusedMethod--")] + [RequiresAssemblyFiles ("Message for --IUnusedInterface.UnusedMethod--")] public void UnusedMethod (); } class UnusedImplementationClass : IUnusedInterface { [RequiresUnreferencedCode ("Message for --UnusedImplementationClass.UnusedMethod--")] + [RequiresAssemblyFiles ("Message for --UnusedImplementationClass.UnusedMethod--")] public void UnusedMethod () { } @@ -85,12 +96,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability.Dependencies public interface IBaseInterface { [RequiresUnreferencedCode ("Message for --IBaseInterface.MethodInBaseInterface--")] + [RequiresAssemblyFiles ("Message for --IBaseInterface.MethodInBaseInterface--")] void MethodInBaseInterface (); } public interface IDerivedInterface : IBaseInterface { [RequiresUnreferencedCode ("Message for --IDerivedInterface.MethodInDerivedInterface--")] + [RequiresAssemblyFiles ("Message for --IDerivedInterface.MethodInDerivedInterface--")] void MethodInDerivedInterface (); } } diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs index f7155e5fe..22800682e 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs @@ -19,6 +19,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [SetupLinkerAction ("copy", "lib")] [SetupCompileBefore ("lib.dll", new[] { "Dependencies/RequiresInCopyAssembly.cs" })] [KeptAllTypesAndMembersInAssembly ("lib.dll")] + [SetupLinkerAction ("copy", "lib2")] + [SetupCompileBefore ("lib2.dll", new[] { "Dependencies/ReferenceInterfaces.cs" })] + [KeptAllTypesAndMembersInAssembly ("lib2.dll")] [SetupLinkAttributesFile ("RequiresCapability.attributes.xml")] [SetupLinkerDescriptorFile ("RequiresCapability.descriptor.xml")] [SkipKeptItemsValidation] @@ -82,32 +85,38 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability AccessThroughNewConstraint.TestNewConstraintOnTypeParameter (); AccessThroughNewConstraint.TestNewConstraintOnTypeParameterOfStaticType (); AccessThroughLdToken.Test (); + AttributeMismatch.Test (); RequiresOnClass.Test (); } [ExpectedWarning ("IL2026", "Message for --RequiresWithMessageOnly--.")] + [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageOnly--.", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresWithMessageOnlyOnMethod () { RequiresWithMessageOnly (); } [RequiresUnreferencedCode ("Message for --RequiresWithMessageOnly--")] + [RequiresAssemblyFiles ("Message for --RequiresWithMessageOnly--")] static void RequiresWithMessageOnly () { } [ExpectedWarning ("IL2026", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl")] + [ExpectedWarning ("IL3002", "Message for --RequiresWithMessageAndUrl--.", "https://helpurl", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresWithMessageAndUrlOnMethod () { RequiresWithMessageAndUrl (); } [RequiresUnreferencedCode ("Message for --RequiresWithMessageAndUrl--", Url = "https://helpurl")] + [RequiresAssemblyFiles ("Message for --RequiresWithMessageAndUrl--", Url = "https://helpurl")] static void RequiresWithMessageAndUrl () { } [ExpectedWarning ("IL2026", "Message for --ConstructorRequires--.")] + [ExpectedWarning ("IL3002", "Message for --ConstructorRequires--.", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresOnConstructor () { new ConstructorRequires (); @@ -116,6 +125,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class ConstructorRequires { [RequiresUnreferencedCode ("Message for --ConstructorRequires--")] + [RequiresAssemblyFiles ("Message for --ConstructorRequires--")] public ConstructorRequires () { } @@ -123,6 +133,8 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [ExpectedWarning ("IL2026", "Message for --getter PropertyRequires--.")] [ExpectedWarning ("IL2026", "Message for --setter PropertyRequires--.")] + [ExpectedWarning ("IL3002", "Message for --getter PropertyRequires--.", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL3002", "Message for --setter PropertyRequires--.", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresOnPropertyGetterAndSetter () { _ = PropertyRequires; @@ -131,9 +143,11 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability static int PropertyRequires { [RequiresUnreferencedCode ("Message for --getter PropertyRequires--")] + [RequiresAssemblyFiles ("Message for --getter PropertyRequires--")] get { return 42; } [RequiresUnreferencedCode ("Message for --setter PropertyRequires--")] + [RequiresAssemblyFiles ("Message for --setter PropertyRequires--")] set { } } @@ -144,6 +158,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability static Type GetUnknownType () => null; [RequiresUnreferencedCode ("Message for --MethodWithRequires--")] + [RequiresAssemblyFiles ("Message for --MethodWithRequires--")] static void MethodWithRequires () { } @@ -152,6 +167,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability static Type _requiresPublicConstructors; [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestMethodWithRequires () { // Normally this would warn, but with the attribute on this method it should be auto-suppressed @@ -159,24 +175,28 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestParameter () { _unknownType.RequiresPublicMethods (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestReturnValue () { GetUnknownType ().RequiresPublicEvents (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestField () { _requiresPublicConstructors = _unknownType; } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestMethodWithRequires (); @@ -196,36 +216,42 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class GenericTypeRequiresPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> { } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestGenericMethod () { GenericMethodRequiresPublicMethods (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestGenericMethodMismatch () { GenericMethodRequiresPublicMethods (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestGenericType () { new GenericTypeRequiresPublicFields (); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestMakeGenericTypeWithStaticTypes () { typeof (GenericTypeRequiresPublicFields<>).MakeGenericType (typeof (TUnknown)); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestMakeGenericTypeWithDynamicTypes () { typeof (GenericTypeRequiresPublicFields<>).MakeGenericType (_unknownType); } [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static void TestMakeGenericMethod () { typeof (SuppressGenericParameters) @@ -234,6 +260,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestGenericMethod (); @@ -292,6 +319,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class BaseType { [RequiresUnreferencedCode ("Message for --BaseType.VirtualMethodRequires--")] + [RequiresAssemblyFiles ("Message for --BaseType.VirtualMethodRequires--")] public virtual void VirtualMethodRequires () { } @@ -300,12 +328,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class TypeWhichOverridesMethod : BaseType { [RequiresUnreferencedCode ("Message for --TypeWhichOverridesMethod.VirtualMethodRequires--")] + [RequiresAssemblyFiles ("Message for --TypeWhichOverridesMethod.VirtualMethodRequires--")] public override void VirtualMethodRequires () { } } [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestBaseTypeVirtualMethodRequires () { var tmp = new BaseType (); @@ -314,6 +344,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [LogDoesNotContain ("TypeWhichOverridesMethod.VirtualMethodRequires")] [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestTypeWhichOverridesMethodVirtualMethodRequires () { var tmp = new TypeWhichOverridesMethod (); @@ -322,6 +353,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [LogDoesNotContain ("TypeWhichOverridesMethod.VirtualMethodRequires")] [ExpectedWarning ("IL2026", "--BaseType.VirtualMethodRequires--")] + [ExpectedWarning ("IL3002", "--BaseType.VirtualMethodRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestTypeWhichOverridesMethodVirtualMethodRequiresOnBase () { BaseType tmp = new TypeWhichOverridesMethod (); @@ -330,19 +362,25 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class PropertyBaseType { - public virtual int VirtualPropertyRequires { [RequiresUnreferencedCode ("Message for --PropertyBaseType.VirtualPropertyRequires--")] get; } + public virtual int VirtualPropertyRequires { + [RequiresUnreferencedCode ("Message for --PropertyBaseType.VirtualPropertyRequires--")] + [RequiresAssemblyFiles ("Message for --PropertyBaseType.VirtualPropertyRequires--")] + get; + } } class TypeWhichOverridesProperty : PropertyBaseType { public override int VirtualPropertyRequires { [RequiresUnreferencedCode ("Message for --TypeWhichOverridesProperty.VirtualPropertyRequires--")] + [RequiresAssemblyFiles ("Message for --TypeWhichOverridesProperty.VirtualPropertyRequires--")] get { return 1; } } } [LogDoesNotContain ("TypeWhichOverridesProperty.VirtualPropertyRequires")] [ExpectedWarning ("IL2026", "--PropertyBaseType.VirtualPropertyRequires--")] + [ExpectedWarning ("IL3002", "--PropertyBaseType.VirtualPropertyRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestTypeWhichOverridesVirtualPropertyRequires () { var tmp = new TypeWhichOverridesProperty (); @@ -382,6 +420,8 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability struct StaticCCtorForFieldAccess { + // TODO: Analyzer still allows RUC/RAF on static constructor with no warning + // https://github.com/dotnet/linker/issues/2347 [ExpectedWarning ("IL2116", "StaticCCtorForFieldAccess..cctor()", ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Message for --StaticCCtorForFieldAccess.cctor--")] static StaticCCtorForFieldAccess () { } @@ -397,9 +437,11 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class TypeIsBeforeFieldInit { [ExpectedWarning ("IL2026", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", ProducedBy = ProducedBy.Analyzer)] + [ExpectedWarning ("IL3002", "Message from --TypeIsBeforeFieldInit.AnnotatedMethod--", ProducedBy = ProducedBy.Analyzer)] public static int field = AnnotatedMethod (); [RequiresUnreferencedCode ("Message from --TypeIsBeforeFieldInit.AnnotatedMethod--")] + [RequiresAssemblyFiles ("Message from --TypeIsBeforeFieldInit.AnnotatedMethod--")] public static int AnnotatedMethod () => 42; } @@ -416,19 +458,24 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class StaticCtorTriggeredByMethodCall { + // TODO: Analyzer still allows RUC/RAF on static constructor with no warning + // https://github.com/dotnet/linker/issues/2347 [ExpectedWarning ("IL2116", "StaticCtorTriggeredByMethodCall..cctor()", ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Message for --StaticCtorTriggeredByMethodCall.Cctor--")] + [RequiresAssemblyFiles ("Message for --StaticCtorTriggeredByMethodCall.Cctor--")] static StaticCtorTriggeredByMethodCall () { } [RequiresUnreferencedCode ("Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--")] + [RequiresAssemblyFiles ("Message for --StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--")] public void TriggerStaticCtorMarking () { } } [ExpectedWarning ("IL2026", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--")] + [ExpectedWarning ("IL3002", "--StaticCtorTriggeredByMethodCall.TriggerStaticCtorMarking--", ProducedBy = ProducedBy.Analyzer)] static void TestStaticCtorTriggeredByMethodCall () { new StaticCtorTriggeredByMethodCall ().TriggerStaticCtorMarking (); @@ -449,6 +496,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [LogDoesNotContain ("ImplementationClass.MethodWithRequires")] [ExpectedWarning ("IL2026", "--IRequires.MethodWithRequires--")] + [ExpectedWarning ("IL3002", "--IRequires.MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestInterfaceMethodWithRequires () { IRequires inst = new ImplementationClass (); @@ -461,12 +509,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability interface IRequires { [RequiresUnreferencedCode ("Message for --IRequires.MethodWithRequires--")] + [RequiresAssemblyFiles ("Message for --IRequires.MethodWithRequires--")] public void MethodWithRequires (); } class ImplementationClass : IRequires { [RequiresUnreferencedCode ("Message for --ImplementationClass.RequiresMethod--")] + [RequiresAssemblyFiles ("Message for --ImplementationClass.RequiresMethod--")] public void MethodWithRequires () { } @@ -475,12 +525,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability abstract class CovariantReturnBase { [RequiresUnreferencedCode ("Message for --CovariantReturnBase.GetRequires--")] + [RequiresAssemblyFiles ("Message for --CovariantReturnBase.GetRequires--")] public abstract BaseReturnType GetRequires (); } class CovariantReturnDerived : CovariantReturnBase { [RequiresUnreferencedCode ("Message for --CovariantReturnDerived.GetRequires--")] + [RequiresAssemblyFiles ("Message for --CovariantReturnDerived.GetRequires--")] public override DerivedReturnType GetRequires () { return null; @@ -489,6 +541,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [LogDoesNotContain ("--CovariantReturnBase.GetRequires--")] [ExpectedWarning ("IL2026", "--CovariantReturnDerived.GetRequires--")] + [ExpectedWarning ("IL3002", "--CovariantReturnDerived.GetRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCovariantReturnCallOnDerived () { var tmp = new CovariantReturnDerived (); @@ -496,6 +549,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--Method--")] + [ExpectedWarning ("IL3002", "--Method--", ProducedBy = ProducedBy.Analyzer)] static void TestRequiresInMethodFromCopiedAssembly () { var tmp = new RequiresInCopyAssembly (); @@ -516,11 +570,13 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Message for --RequiresInDynamicDependency--")] + [RequiresAssemblyFiles ("Message for --RequiresInDynamicDependency--")] static void RequiresInDynamicDependency () { } [ExpectedWarning ("IL2026", "--RequiresInDynamicDependency--")] + [ExpectedWarning ("IL3002", "--RequiresInDynamicDependency--", ProducedBy = ProducedBy.Analyzer)] [DynamicDependency ("RequiresInDynamicDependency")] static void TestRequiresInDynamicDependency () { @@ -528,22 +584,27 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Linker adds a trailing period to this message")] + [RequiresAssemblyFiles ("Linker adds a trailing period to this message")] static void WarningMessageWithoutEndingPeriod () { } [ExpectedWarning ("IL2026", "Linker adds a trailing period to this message.")] + [ExpectedWarning ("IL3002", "Linker adds a trailing period to this message.", ProducedBy = ProducedBy.Analyzer)] static void TestThatTrailingPeriodIsAddedToMessage () { WarningMessageWithoutEndingPeriod (); } [RequiresUnreferencedCode ("Linker does not add a period to this message.")] + [RequiresAssemblyFiles ("Linker does not add a period to this message.")] static void WarningMessageEndsWithPeriod () { } + [LogDoesNotContain ("Linker does not add a period to this message..")] [ExpectedWarning ("IL2026", "Linker does not add a period to this message.")] + [ExpectedWarning ("IL3002", "Linker does not add a period to this message.", ProducedBy = ProducedBy.Analyzer)] static void TestThatTrailingPeriodIsNotDuplicatedInWarningMessage () { WarningMessageEndsWithPeriod (); @@ -570,6 +631,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class AttributeWhichRequiresAttribute : Attribute { [RequiresUnreferencedCode ("Message for --AttributeWhichRequiresAttribute.ctor--")] + [RequiresAssemblyFiles ("Message for --AttributeWhichRequiresAttribute.ctor--")] public AttributeWhichRequiresAttribute () { } @@ -585,17 +647,20 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability get => false; [RequiresUnreferencedCode ("--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [RequiresAssemblyFiles ("--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] set { } } } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] class GenericTypeWithAttributedParameter<[AttributeWhichRequires] T> { public static void TestMethod () { } } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] static void GenericMethodWithAttributedParameter<[AttributeWhichRequires] T> () { } static void TestRequiresOnAttributeOnGenericParameter () @@ -605,7 +670,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = ProducedBy.Analyzer)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] class TypeWithAttributeWhichRequires @@ -613,19 +680,25 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = ProducedBy.Analyzer)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static void MethodWithAttributeWhichRequires () { } [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = ProducedBy.Analyzer)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static int _fieldWithAttributeWhichRequires; [ExpectedWarning ("IL2026", "--AttributeWhichRequiresAttribute.ctor--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresAttribute.ctor--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--")] + [ExpectedWarning ("IL3002", "--AttributeWhichRequiresOnPropertyAttribute.PropertyWhichRequires--", ProducedBy = ProducedBy.Analyzer)] [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] static bool PropertyWithAttributeWhichRequires { get; set; } @@ -633,9 +706,11 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [AttributeWhichRequires] [AttributeWhichRequiresOnProperty (PropertyWhichRequires = true)] [RequiresUnreferencedCode ("--MethodWhichRequiresWithAttributeWhichRequires--")] + [RequiresAssemblyFiles ("--MethodWhichRequiresWithAttributeWhichRequires--")] static void MethodWhichRequiresWithAttributeWhichRequires () { } [ExpectedWarning ("IL2026", "--MethodWhichRequiresWithAttributeWhichRequires--")] + [ExpectedWarning ("IL3002", "--MethodWhichRequiresWithAttributeWhichRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestMethodWhichRequiresWithAttributeWhichRequires () { MethodWhichRequiresWithAttributeWhichRequires (); @@ -662,10 +737,12 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class GenericWithStaticMethod { [RequiresUnreferencedCode ("Message for --GenericTypeWithStaticMethodWhichRequires--")] + [RequiresAssemblyFiles ("Message for --GenericTypeWithStaticMethodWhichRequires--")] public static void GenericTypeWithStaticMethodWhichRequires () { } } [ExpectedWarning ("IL2026", "--GenericTypeWithStaticMethodWhichRequires--")] + [ExpectedWarning ("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer)] public static void GenericTypeWithStaticMethodViaLdftn () { var _ = new Action (GenericWithStaticMethod.GenericTypeWithStaticMethodWhichRequires); @@ -682,12 +759,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability abstract class Base { [RequiresUnreferencedCode ("Message for --CovariantReturnViaLdftn.Base.GetRequires--")] + [RequiresAssemblyFiles ("Message for --CovariantReturnViaLdftn.Base.GetRequires--")] public abstract BaseReturnType GetRequires (); } class Derived : Base { [RequiresUnreferencedCode ("Message for --CovariantReturnViaLdftn.Derived.GetRequires--")] + [RequiresAssemblyFiles ("Message for --CovariantReturnViaLdftn.Derived.GetRequires--")] public override DerivedReturnType GetRequires () { return null; @@ -695,6 +774,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--CovariantReturnViaLdftn.Derived.GetRequires--")] + [ExpectedWarning ("IL3002", "--CovariantReturnViaLdftn.Derived.GetRequires--", ProducedBy = ProducedBy.Analyzer)] public static void Test () { var tmp = new Derived (); @@ -748,18 +828,22 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability static event EventHandler EventToTestRemove { add { } [RequiresUnreferencedCode ("Message for --EventToTestRemove.remove--")] + [RequiresAssemblyFiles ("Message for --EventToTestRemove.remove--")] remove { } } [ExpectedWarning ("IL2026", "--EventToTestAdd.add--", ProducedBy = ProducedBy.Trimmer)] static event EventHandler EventToTestAdd { [RequiresUnreferencedCode ("Message for --EventToTestAdd.add--")] + [RequiresAssemblyFiles ("Message for --EventToTestAdd.add--")] add { } remove { } } [ExpectedWarning ("IL2026", "--EventToTestRemove.remove--")] + [ExpectedWarning ("IL3002", "--EventToTestRemove.remove--", ProducedBy = ProducedBy.Analyzer)] [ExpectedWarning ("IL2026", "--EventToTestAdd.add--")] + [ExpectedWarning ("IL3002", "--EventToTestAdd.add--", ProducedBy = ProducedBy.Analyzer)] public static void Test () { EventToTestRemove -= (sender, e) => { }; @@ -772,12 +856,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class NewConstraintTestType { [RequiresUnreferencedCode ("Message for --NewConstraintTestType.ctor--")] + [RequiresAssemblyFiles ("Message for --NewConstraintTestType.ctor--")] public NewConstraintTestType () { } } static void GenericMethod () where T : new() { } [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = ProducedBy.Analyzer)] public static void Test () { GenericMethod (); @@ -793,12 +879,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = ProducedBy.Analyzer)] public static void TestNewConstraintOnTypeParameter () { _ = new NewConstaintOnTypeParameter (); } [ExpectedWarning ("IL2026", "--NewConstraintTestType.ctor--")] + [ExpectedWarning ("IL3002", "--NewConstraintTestType.ctor--", ProducedBy = ProducedBy.Analyzer)] public static void TestNewConstraintOnTypeParameterOfStaticType () { NewConstraintOnTypeParameterOfStaticType.DoNothing (); @@ -809,18 +897,283 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability { static bool PropertyWithLdToken { [RequiresUnreferencedCode ("Message for --PropertyWithLdToken.get--")] + [RequiresAssemblyFiles ("Message for --PropertyWithLdToken.get--")] get { return false; } } [ExpectedWarning ("IL2026", "--PropertyWithLdToken.get--")] + [ExpectedWarning ("IL3002", "--PropertyWithLdToken.get--", ProducedBy = ProducedBy.Analyzer)] public static void Test () { Expression> getter = () => PropertyWithLdToken; } } + class AttributeMismatch + { + static void RequirePublicMethods ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) + { + } + + class BaseClassWithRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + public virtual void VirtualMethod () + { + } + + public virtual string VirtualPropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + public virtual string VirtualPropertyAnnotationInProperty { get; set; } + } + + class BaseClassWithoutRequires + { + public virtual void VirtualMethod () + { + } + + public virtual string VirtualPropertyAnnotationInAccesor { get; set; } + + public virtual string VirtualPropertyAnnotationInProperty { get; set; } + } + + class DerivedClassWithRequires : BaseClassWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL2046", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualMethod()", "BaseClassWithoutRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer)] + public override void VirtualMethod () + { + } + + private string name; + public override string VirtualPropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get { return name; } + set { name = value; } + } + + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "DerivedClassWithRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithoutRequires.VirtualPropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInProperty { get; set; } + } + + class DerivedClassWithoutRequires : BaseClassWithRequires + { + [ExpectedWarning ("IL2046", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()")] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualMethod()", "BaseClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Analyzer)] + public override void VirtualMethod () + { + } + + private string name; + public override string VirtualPropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInAccesor.get", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "DerivedClassWithoutRequires.VirtualPropertyAnnotationInProperty", "BaseClassWithRequires.VirtualPropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public override string VirtualPropertyAnnotationInProperty { get; set; } + } + + public interface IBaseWithRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + void Method (); + + string PropertyAnnotationInAccesor { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get; + set; + } + + [RequiresAssemblyFiles ("Message")] + string PropertyAnnotationInProperty { get; set; } + } + + public interface IBaseWithoutRequires + { + void Method (); + + string PropertyAnnotationInAccesor { get; set; } + + string PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithRequires : IBaseWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get { return name; } + set { name = value; } + } + + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + } + + class ExplicitImplementationClassWithRequires : IBaseWithoutRequires + { + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL2046", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()")] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithoutRequires.Method()", "IBaseWithoutRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + void IBaseWithoutRequires.Method () + { + } + + private string name; + string IBaseWithoutRequires.PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithoutRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get { return name; } + set { name = value; } + } + + [RequiresAssemblyFiles ("Message")] + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithoutRequires.PropertyAnnotationInProperty", "IBaseWithoutRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + string IBaseWithoutRequires.PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithoutRequires : IBaseWithRequires + { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.Method()", "IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + } + + class ExplicitImplementationClassWithoutRequires : IBaseWithRequires + { + [ExpectedWarning ("IL2046", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithRequires.Method()")] + [ExpectedWarning ("IL3003", "IBaseWithRequires.Method()", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithRequires.Method()", ProducedBy = ProducedBy.Analyzer)] + void IBaseWithRequires.Method () + { + } + + private string name; + string IBaseWithRequires.PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "PropertyAnnotationInAccesor.get", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "ExplicitImplementationClassWithoutRequires.Mono.Linker.Tests.Cases.RequiresCapability.RequiresCapability.AttributeMismatch.IBaseWithRequires.PropertyAnnotationInProperty", "IBaseWithRequires.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + string IBaseWithRequires.PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithoutRequiresInSource : ReferenceInterfaces.IBaseWithRequiresInReference + { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.Method()", "IBaseWithRequiresInReference.Method()", ProducedBy = ProducedBy.Analyzer)] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "ImplementationClassWithoutRequiresInSource.PropertyAnnotationInProperty", "IBaseWithRequiresInReference.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + public string PropertyAnnotationInProperty { get; set; } + } + + class ImplementationClassWithRequiresInSource : ReferenceInterfaces.IBaseWithoutRequiresInReference + { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.Method()", "IBaseWithoutRequiresInReference.Method()", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + public void Method () + { + } + + private string name; + public string PropertyAnnotationInAccesor { + [ExpectedWarning ("IL2046", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get")] + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInAccesor.get", "IBaseWithoutRequiresInReference.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Analyzer)] + [RequiresUnreferencedCode ("Message")] + [RequiresAssemblyFiles ("Message")] + get { return name; } + set { name = value; } + } + + [ExpectedWarning ("IL3003", "ImplementationClassWithRequiresInSource.PropertyAnnotationInProperty", "IBaseWithoutRequiresInReference.PropertyAnnotationInProperty", ProducedBy = ProducedBy.Analyzer)] + [RequiresAssemblyFiles ("Message")] + public string PropertyAnnotationInProperty { get; set; } + } + + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualPropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "BaseClassWithRequires.VirtualMethod()", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "IBaseWithRequires.PropertyAnnotationInAccesor.get", ProducedBy = ProducedBy.Trimmer)] + [ExpectedWarning ("IL2026", "IBaseWithRequires.Method()", ProducedBy = ProducedBy.Trimmer)] + public static void Test () + { + RequirePublicMethods (typeof (BaseClassWithRequires)); + RequirePublicMethods (typeof (BaseClassWithoutRequires)); + RequirePublicMethods (typeof (DerivedClassWithRequires)); + RequirePublicMethods (typeof (DerivedClassWithoutRequires)); + RequirePublicMethods (typeof (IBaseWithRequires)); + RequirePublicMethods (typeof (IBaseWithoutRequires)); + RequirePublicMethods (typeof (ImplementationClassWithRequires)); + RequirePublicMethods (typeof (ImplementationClassWithoutRequires)); + RequirePublicMethods (typeof (ExplicitImplementationClassWithRequires)); + RequirePublicMethods (typeof (ExplicitImplementationClassWithoutRequires)); + RequirePublicMethods (typeof (ImplementationClassWithoutRequiresInSource)); + RequirePublicMethods (typeof (ImplementationClassWithRequiresInSource)); + } + } + class RequiresOnClass { [RequiresUnreferencedCode ("Message for --ClassWithRequires--")] diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapabilityFromCopiedAssembly.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapabilityFromCopiedAssembly.cs index b30833564..6036d7044 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapabilityFromCopiedAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapabilityFromCopiedAssembly.cs @@ -11,6 +11,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [SetupCompileBefore ("lib.dll", new[] { "Dependencies/RequiresInCopyAssembly.cs" })] [KeptAllTypesAndMembersInAssembly ("lib.dll")] [LogDoesNotContain ("IL2026")] + [LogDoesNotContain ("IL3002")] [LogDoesNotContain ("IL2027")] public class RequiresCapabilityFromCopiedAssembly { diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs index dbbb7fc18..e5f176d87 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs @@ -44,6 +44,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class WarnInIteratorBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static IEnumerable TestCallBeforeYieldReturn () { MethodWithRequires (); @@ -51,6 +52,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static IEnumerable TestCallAfterYieldReturn () { yield return 0; @@ -68,6 +70,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static IEnumerable TestLdftn () { yield return 0; @@ -75,6 +78,18 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability var action = new Action (MethodWithRequires); } + // Cannot annotate fields either with RUC nor RAF therefore the warning persists + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static IEnumerable TestLazyDelegate () + { + yield return 0; + yield return 1; + _ = _default.Value; + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static IEnumerable TestDynamicallyAccessedMethod () { @@ -89,6 +104,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability TestCallAfterYieldReturn (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -96,6 +112,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class SuppressInIteratorBody { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestCall () { MethodWithRequires (); @@ -105,6 +122,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestReflectionAccess () { yield return 0; @@ -115,6 +133,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestLdftn () { yield return 0; @@ -122,7 +141,20 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability var action = new Action (MethodWithRequires); } + // Cannot annotate fields either with RUC nor RAF therefore the warning persists + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static IEnumerable TestLazyDelegate () + { + yield return 0; + yield return 1; + _ = _default.Value; + } + [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -131,6 +163,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestMethodParameterWithRequirements (Type unknownType = null) { unknownType.RequiresNonPublicMethods (); @@ -138,6 +171,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestGenericMethodParameterRequirement () { MethodWithGenericWhichRequiresMethods (); @@ -145,6 +179,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestGenericTypeParameterRequirement () { new TypeWithGenericWhichRequiresNonPublicFields (); @@ -152,11 +187,13 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); TestMethodParameterWithRequirements (); TestGenericMethodParameterRequirement (); @@ -167,6 +204,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class WarnInAsyncBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async void TestCallBeforeYieldReturn () { MethodWithRequires (); @@ -174,6 +212,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async void TestCallAfterYieldReturn () { await MethodAsync (); @@ -191,12 +230,23 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async void TestLdftn () { await MethodAsync (); var action = new Action (MethodWithRequires); } + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static async void TestLazyDelegate () + { + await MethodAsync (); + _ = _default.Value; + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static async void TestDynamicallyAccessedMethod () { @@ -210,6 +260,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability TestCallAfterYieldReturn (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -217,6 +268,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class SuppressInAsyncBody { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestCall () { MethodWithRequires (); @@ -226,6 +278,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestReflectionAccess () { await MethodAsync (); @@ -236,13 +289,26 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestLdftn () { await MethodAsync (); var action = new Action (MethodWithRequires); } + // Cannot annotate fields either with RUC nor RAF therefore the warning persists + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static async void TestLazyDelegate () + { + await MethodAsync (); + _ = _default.Value; + } + [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -250,6 +316,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestMethodParameterWithRequirements (Type unknownType = null) { unknownType.RequiresNonPublicMethods (); @@ -257,6 +324,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestGenericMethodParameterRequirement () { MethodWithGenericWhichRequiresMethods (); @@ -264,6 +332,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestGenericTypeParameterRequirement () { new TypeWithGenericWhichRequiresNonPublicFields (); @@ -271,11 +340,13 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); TestMethodParameterWithRequirements (); TestGenericMethodParameterRequirement (); @@ -286,6 +357,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class WarnInAsyncIteratorBody { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async IAsyncEnumerable TestCallBeforeYieldReturn () { await MethodAsync (); @@ -294,6 +366,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async IAsyncEnumerable TestCallAfterYieldReturn () { yield return 0; @@ -314,6 +387,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async IAsyncEnumerable TestLdftn () { await MethodAsync (); @@ -321,6 +395,17 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability var action = new Action (MethodWithRequires); } + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static async IAsyncEnumerable TestLazyDelegate () + { + await MethodAsync (); + yield return 0; + _ = _default.Value; + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static async IAsyncEnumerable TestDynamicallyAccessedMethod () { @@ -335,6 +420,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability TestCallAfterYieldReturn (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -342,6 +428,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class SuppressInAsyncIteratorBody { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestCall () { MethodWithRequires (); @@ -352,6 +439,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestReflectionAccess () { await MethodAsync (); @@ -364,6 +452,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestLdftn () { await MethodAsync (); @@ -371,7 +460,20 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability yield return 0; } + // Cannot annotate fields either with RUC nor RAF therefore the warning persists + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static async IAsyncEnumerable TestLazyDelegate () + { + await MethodAsync (); + yield return 0; + _ = _default.Value; + } + [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestDynamicallyAccessedMethod () { typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); @@ -380,6 +482,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestMethodParameterWithRequirements (Type unknownType = null) { unknownType.RequiresNonPublicMethods (); @@ -388,6 +491,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestGenericMethodParameterRequirement () { yield return 0; @@ -396,6 +500,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async IAsyncEnumerable TestGenericTypeParameterRequirement () { new TypeWithGenericWhichRequiresNonPublicFields (); @@ -404,11 +509,13 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); TestMethodParameterWithRequirements (); TestGenericMethodParameterRequirement (); @@ -419,6 +526,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class WarnInLocalFunction { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCall () { LocalFunction (); @@ -427,6 +535,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCallWithClosure (int p = 0) { LocalFunction (); @@ -449,6 +558,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestLdftn () { LocalFunction (); @@ -459,6 +569,20 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } } + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static void TestLazyDelegate () + { + LocalFunction (); + + void LocalFunction () + { + _ = _default.Value; + } + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static void TestDynamicallyAccessedMethod () { @@ -473,6 +597,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability TestCallWithClosure (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -483,20 +608,24 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability // so its suppression effect also doesn't propagate [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCall () { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => MethodWithRequires (); } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCallWithClosure (int p = 0) { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () { p++; @@ -505,38 +634,59 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestReflectionAccess () { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => typeof (RequiresInCompilerGeneratedCode) .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic) .Invoke (null, new object[] { }); } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestLdftn () { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () { var action = new Action (MethodWithRequires); } } + [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static void TestLazyDelegate () + { + LocalFunction (); + + void LocalFunction () + { + _ = _default.Value; + } + } + [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestDynamicallyAccessedMethod () { LocalFunction (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods (); } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestMethodParameterWithRequirements (Type unknownType = null) { LocalFunction (); @@ -546,6 +696,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericMethodParameterRequirement () { LocalFunction (); @@ -555,6 +706,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericTypeParameterRequirement () { LocalFunction (); @@ -564,6 +716,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericLocalFunction () { LocalFunction (); @@ -575,6 +728,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericLocalFunctionInner () { LocalFunction (); @@ -611,32 +765,38 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCallMethodWithRequiresInLtftnLocalFunction () { var _ = new Action (LocalFunction); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => MethodWithRequires (); } class DynamicallyAccessedLocalFunction { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] public static void TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction () { typeof (DynamicallyAccessedLocalFunction).RequiresNonPublicMethods (); [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] void LocalFunction () => MethodWithRequires (); } } [ExpectedWarning ("IL2026")] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] static void TestSuppressionLocalFunction () { LocalFunction (); // This will produce a warning since the location function has Requires on it [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] void LocalFunction (Type unknownType = null) { MethodWithRequires (); @@ -645,11 +805,13 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestSuppressionOnOuterAndLocalFunction () { LocalFunction (); [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] void LocalFunction (Type unknownType = null) { MethodWithRequires (); @@ -658,12 +820,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); TestCallWithClosure (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestMethodParameterWithRequirements (); TestDynamicallyAccessedMethod (); TestGenericMethodParameterRequirement (); @@ -682,12 +846,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class WarnInLambda { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCall () { Action _ = () => MethodWithRequires (); } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestCallWithClosure (int p = 0) { Action _ = () => { @@ -707,6 +873,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static void TestLdftn () { Action _ = () => { @@ -714,6 +881,17 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability }; } + [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static void TestLazyDelegate () + { + Action _ = () => { + var action = _default.Value; + }; + } + [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] static void TestDynamicallyAccessedMethod () { @@ -728,6 +906,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability TestCallWithClosure (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); } } @@ -741,7 +920,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability // - Would be useful for testing - have to use the CompilerGeneratedCode = true trick instead [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCall () { Action _ = () => MethodWithRequires (); @@ -750,6 +931,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet [ExpectedWarning ("IL2067", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCallWithReflectionAnalysisWarning () { // This should not produce warning because the Requires @@ -757,7 +939,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestCallWithClosure (int p = 0) { Action _ = () => { @@ -769,6 +953,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability // Analyzer doesn't recognize reflection access - so doesn't warn in this case [ExpectedWarning ("IL2026", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestReflectionAccess () { Action _ = () => { @@ -779,7 +964,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestLdftn () { Action _ = () => { @@ -787,9 +974,21 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability }; } + [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)] + public static Lazy _default = new Lazy (MethodWithRequiresAndReturns); + + static void TestLazyDelegate () + { + Action _ = () => { + var action = _default.Value; + }; + } + // Analyzer doesn't apply DAM - so won't see this warnings [ExpectedWarning ("IL2026", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestDynamicallyAccessedMethod () { Action _ = () => { @@ -800,6 +999,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet [ExpectedWarning ("IL2077", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestMethodParameterWithRequirements (Type unknownType = null) { Action _ = () => unknownType.RequiresNonPublicMethods (); @@ -808,6 +1008,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericMethodParameterRequirement () { Action _ = () => { @@ -818,6 +1019,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability // The warning is currently not detected by roslyn analyzer since it doesn't analyze DAM yet [ExpectedWarning ("IL2091", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)] [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static void TestGenericTypeParameterRequirement () { Action _ = () => { @@ -826,6 +1028,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestCall (); @@ -833,6 +1036,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability TestCallWithClosure (); TestReflectionAccess (); TestLdftn (); + TestLazyDelegate (); TestDynamicallyAccessedMethod (); TestMethodParameterWithRequirements (); TestGenericMethodParameterRequirement (); @@ -843,6 +1047,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class WarnInComplex { [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)] static async void TestIteratorLocalFunctionInAsync () { await MethodAsync (); @@ -874,6 +1079,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class SuppressInComplex { [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestIteratorLocalFunctionInAsync () { await MethodAsync (); @@ -881,6 +1087,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability await MethodAsync (); [RequiresUnreferencedCode ("Suppress in local function")] + [RequiresAssemblyFiles ("Suppress in local function")] IEnumerable LocalFunction () { yield return 0; @@ -890,6 +1097,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static async void TestIteratorLocalFunctionInAsyncWithoutInner () { await MethodAsync (); @@ -897,6 +1105,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability await MethodAsync (); [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] IEnumerable LocalFunction () { yield return 0; @@ -906,6 +1115,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Suppress in body")] + [RequiresAssemblyFiles ("Suppress in body")] static IEnumerable TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator () { MethodWithGenericWhichRequiresMethods (); @@ -913,6 +1123,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [UnconditionalSuppressMessage ("Trimming", "IL2026")] + [UnconditionalSuppressMessage ("SingleFile", "IL3002")] public static void Test () { TestIteratorLocalFunctionInAsync (); @@ -924,6 +1135,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class StateMachinesOnlyReferencedViaReflection { [RequiresUnreferencedCode ("Requires to suppress")] + [RequiresAssemblyFiles ("Requires to suppress")] static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress () { yield return 0; @@ -931,6 +1143,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("Requires to suppress")] + [RequiresAssemblyFiles ("Requires to suppress")] static async void TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress () { await MethodAsync (); @@ -938,6 +1151,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldWarn () { yield return 0; @@ -945,6 +1159,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)] + [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)] static async void TestAsyncOnlyReferencedViaReflectionWhichShouldWarn () { await MethodAsync (); @@ -966,12 +1181,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability public class AsyncBodyCallingMethodWithRequires { [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static Task MethodWithRequiresAsync (Type type) { return Task.FromResult (new object ()); } [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] static async Task AsyncMethodCallingRequires (Type type) { using (var diposable = await GetDisposableAsync ()) { @@ -980,6 +1197,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer)] public static void Test () { AsyncMethodCallingRequires (typeof (object)); @@ -989,12 +1207,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability public class GenericAsyncBodyCallingMethodWithRequires { [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] static ValueTask MethodWithRequiresAsync () { return ValueTask.FromResult (default (TValue)); } [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] static async Task AsyncMethodCallingRequires () { using (var disposable = await GetDisposableAsync ()) { @@ -1003,6 +1223,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer)] public static void Test () { AsyncMethodCallingRequires (); @@ -1014,12 +1235,14 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class RequiresOnCtor { [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] public RequiresOnCtor () { } } [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] static IAsyncEnumerable AsyncEnumMethodCallingRequires< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] TValue> () { @@ -1035,6 +1258,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer)] public static void Test () { AsyncEnumMethodCallingRequires (); @@ -1052,6 +1276,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability } [RequiresUnreferencedCode ("--MethodWithRequires--")] + [RequiresAssemblyFiles ("--MethodWithRequires--")] static void MethodWithRequires () { } @@ -1059,11 +1284,19 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class TypeWithMethodWithRequires { [RequiresUnreferencedCode ("--TypeWithMethodWithRequires.MethodWithRequires--")] + [RequiresAssemblyFiles ("--TypeWithMethodWithRequires.MethodWithRequires--")] static void MethodWithRequires () { } } + [RequiresUnreferencedCode ("Message from --MethodWithRequiresAndReturns--")] + [RequiresAssemblyFiles ("Message from --MethodWithRequiresAndReturns--")] + public static string MethodWithRequiresAndReturns () + { + return "string"; + } + static void MethodWithGenericWhichRequiresMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] T> () { } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index bab3a4f59..949029edc 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -777,6 +777,9 @@ namespace Mono.Linker.Tests.TestCasesRunner if (actualName.StartsWith (expectedMember.DeclaringType.FullName) && actualName.Contains ("<" + expectedMember.Name + ">")) return true; + if (actualName.StartsWith (expectedMember.DeclaringType.FullName) && + actualName.Contains (".cctor") && (expectedMember is FieldDefinition || expectedMember is PropertyDefinition)) + return true; if (methodDefinition.Name == ".ctor" && methodDefinition.DeclaringType.FullName == expectedMember.FullName) return true; -- cgit v1.2.3 From e884052a735b9c74db579412551409ca8a543829 Mon Sep 17 00:00:00 2001 From: Mike Voorhees Date: Wed, 3 Nov 2021 11:18:59 -0400 Subject: Improve test failure message when a fatal linker error exception happens (#2331) --- src/linker/Linker/Driver.cs | 4 +++- test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/linker/Linker/Driver.cs b/src/linker/Linker/Driver.cs index 2c52424d5..46db485f5 100644 --- a/src/linker/Linker/Driver.cs +++ b/src/linker/Linker/Driver.cs @@ -763,7 +763,7 @@ namespace Mono.Linker // to the error code. // May propagate exceptions, which will result in the process getting an // exit code determined by dotnet. - public int Run (ILogger? customLogger = null) + public int Run (ILogger? customLogger = null, bool throwOnFatalLinkerException = false) { int setupStatus = SetupContext (customLogger); if (setupStatus > 0) @@ -782,6 +782,8 @@ namespace Mono.Linker Debug.Assert (lex.MessageContainer.Category == MessageCategory.Error); Debug.Assert (lex.MessageContainer.Code != null); Debug.Assert (lex.MessageContainer.Code.Value != 0); + if (throwOnFatalLinkerException) + throw; return lex.MessageContainer.Code ?? 1; } catch (ResolutionException e) { Context.LogError ($"{e.Message}", 1040); diff --git a/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs b/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs index 89dd43a08..01f57a3aa 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs @@ -25,7 +25,7 @@ namespace Mono.Linker.Tests.TestCasesRunner { Driver.ProcessResponseFile (args, out var queue); using (var driver = new TestDriver (queue, customizations)) { - driver.Run (logger); + driver.Run (logger, throwOnFatalLinkerException: true); } } } -- cgit v1.2.3 From 8aa0e80b51cf291edb2890bc4bc821e5b4600c5c Mon Sep 17 00:00:00 2001 From: Mateo Torres-Ruiz Date: Wed, 3 Nov 2021 09:19:18 -0600 Subject: Ignore .vscode and emacs backup files in root (#2341) --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 414ad0275..d7f81b2c8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ *.user *.userprefs .vs/ +.vscode/ .idea/ packages/ @@ -36,4 +37,7 @@ bin/ artifacts *.binlog +# Emacs backup files +*~ + test/Mono.Linker.Tests/TestResults.xml -- cgit v1.2.3 From 968a763808c833fe1c5f8374484fd8b88fd655cb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 8 Nov 2021 13:39:08 +0000 Subject: Update dependencies from https://github.com/dotnet/arcade build 20211105.2 (#2356) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/post-build/symbols-validation.ps1 | 16 ++++++++-------- eng/common/templates/job/source-build.yml | 15 +++++++++------ eng/common/templates/job/source-index-stage1.yml | 10 +++++++--- global.json | 2 +- 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 297c0de70..ac43aa6ad 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,14 +3,14 @@ - + https://github.com/dotnet/arcade - 0558f85d950fee2838bf02b9ba1f20d67f00b504 + a7c57abb74deaee6dac921dd68f9c3c58059ebfb - + https://github.com/dotnet/arcade - 0558f85d950fee2838bf02b9ba1f20d67f00b504 + a7c57abb74deaee6dac921dd68f9c3c58059ebfb https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index ed8ca5a93..f57313e11 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,7 +18,7 @@ 5.0.0 17.0.0-preview-21267-01 17.0.0-preview-21267-01 - 7.0.0-beta.21529.1 + 7.0.0-beta.21555.2 6.0.0-beta.21271.1 3.10.0-2.final 3.10.0-2.final diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1 index a4a92efbe..cd2181baf 100644 --- a/eng/common/post-build/symbols-validation.ps1 +++ b/eng/common/post-build/symbols-validation.ps1 @@ -134,17 +134,17 @@ $CountMissingSymbols = { # Save the output and get diagnostic output $output = & $dotnetSymbolExe --symbols --modules $WindowsPdbVerificationParam $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String - if (Test-Path $PdbPath) { - return 'PDB' + if ((Test-Path $PdbPath) -and (Test-path $SymbolPath)) { + return 'Module and PDB for Module' } - elseif (Test-Path $NGenPdb) { - return 'NGen PDB' + elseif ((Test-Path $NGenPdb) -and (Test-Path $PdbPath) -and (Test-Path $SymbolPath)) { + return 'Dll, PDB and NGen PDB' } - elseif (Test-Path $SODbg) { - return 'DBG for SO' + elseif ((Test-Path $SODbg) -and (Test-Path $SymbolPath)) { + return 'So and DBG for SO' } - elseif (Test-Path $DylibDwarf) { - return 'Dwarf for Dylib' + elseif ((Test-Path $DylibDwarf) -and (Test-Path $SymbolPath)) { + return 'Dylib and Dwarf for Dylib' } elseif (Test-Path $SymbolPath) { return 'Module' diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml index 5023d36dc..5cd5325d7 100644 --- a/eng/common/templates/job/source-build.yml +++ b/eng/common/templates/job/source-build.yml @@ -31,11 +31,6 @@ parameters: # container and pool. platform: {} - # The default VM host AzDO pool. This should be capable of running Docker containers: almost all - # source-build builds run in Docker, including the default managed platform. - defaultContainerHostPool: - vmImage: ubuntu-20.04 - jobs: - job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }} displayName: Source-Build (${{ parameters.platform.name }}) @@ -47,7 +42,15 @@ jobs: container: ${{ parameters.platform.container }} ${{ if eq(parameters.platform.pool, '') }}: - pool: ${{ parameters.defaultContainerHostPool }} + # The default VM host AzDO pool. This should be capable of running Docker containers: almost all + # source-build builds run in Docker, including the default managed platform. + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: NetCore1ESPool-Public + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64.Open + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Ubuntu.1804.Amd64 ${{ if ne(parameters.platform.pool, '') }}: pool: ${{ parameters.platform.pool }} diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml index ae85a99a8..4af724eb1 100644 --- a/eng/common/templates/job/source-index-stage1.yml +++ b/eng/common/templates/job/source-index-stage1.yml @@ -5,8 +5,6 @@ parameters: sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" preSteps: [] binlogPath: artifacts/log/Debug/Build.binlog - pool: - vmImage: 'windows-2019' condition: '' dependsOn: '' @@ -24,7 +22,13 @@ jobs: - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}: - group: source-dot-net stage1 variables - pool: ${{ parameters.pool }} + pool: + ${{ if eq(variables['System.TeamProject'], 'public') }}: + name: NetCore1ESPool-Public + demands: ImageOverride -equals Build.Server.Amd64.VS2019.Open + ${{ if eq(variables['System.TeamProject'], 'internal') }}: + name: NetCore1ESPool-Internal + demands: ImageOverride -equals Build.Server.Amd64.VS2019 steps: - ${{ each preStep in parameters.preSteps }}: - ${{ preStep }} diff --git a/global.json b/global.json index 508c398a4..35121fe42 100644 --- a/global.json +++ b/global.json @@ -3,7 +3,7 @@ "dotnet": "6.0.100-rc.1.21430.12" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21529.1", + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21555.2", "Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21551.1" } -- cgit v1.2.3 From 3d3f294ff916bff54350d04143d0ef212c29ebb7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 8 Nov 2021 13:39:16 +0000 Subject: Update dependencies from https://github.com/dotnet/runtime build 20211106.5 (#2357) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ac43aa6ad..b4c07c7cc 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -12,9 +12,9 @@ https://github.com/dotnet/arcade a7c57abb74deaee6dac921dd68f9c3c58059ebfb - + https://github.com/dotnet/runtime - 2a87ffeaedb6b534d6eaa000d5ba9b545f4aac1e + d40f560efbf4f85ec6d59892a6c4bafa39f66d19 - 7.0.0-alpha.1.21551.1 + 7.0.0-alpha.1.21556.5 $(MicrosoftNETSdkILPackageVersion) diff --git a/global.json b/global.json index 35121fe42..50f0cd7d7 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21555.2", "Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21551.1" + "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21556.5" } } -- cgit v1.2.3 From 9e1cdb623ba2411dc17fb86be415e0dcd3f78b8e Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Tue, 9 Nov 2021 18:49:52 -0800 Subject: Move analyzer tests to one test per file Moves away from generating Theory cases for each method in the file and uses one Fact per test file. --- test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs | 19 ++++ .../ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs | 29 ------ .../RequiresCapabilityTests.cs | 41 +++++++++ test/ILLink.RoslynAnalyzer.Tests/TestCase.cs | 20 ++-- test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs | 102 ++++----------------- test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs | 28 +++--- .../RequiresCapability/RequiresCapability.cs | 2 +- 7 files changed, 101 insertions(+), 140 deletions(-) create mode 100644 test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs delete mode 100644 test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs create mode 100644 test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs diff --git a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs new file mode 100644 index 000000000..e0363379e --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs @@ -0,0 +1,19 @@ + +using System.Threading.Tasks; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public abstract class LinkerTestBase : TestCaseUtils + { + protected abstract string TestSuiteName { get; } + + private static readonly (string, string)[] MSBuildProperties = UseMSBuildProperties ( + MSBuildPropertyOptionNames.EnableTrimAnalyzer, + MSBuildPropertyOptionNames.EnableSingleFileAnalyzer); + + protected Task RunTest(string testName) + { + return RunTestFile (TestSuiteName, testName, MSBuildProperties); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs deleted file mode 100644 index bade900f4..000000000 --- a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestCases.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using Xunit; - -namespace ILLink.RoslynAnalyzer.Tests -{ - /// - /// Test cases stored in files - /// - public class LinkerTestCases : TestCaseUtils - { - [Theory] - [MemberData (nameof (TestCaseUtils.GetTestData), parameters: nameof (RequiresCapability))] - public void RequiresCapability (string m) - { - RunTest (nameof (RequiresCapability), m, UseMSBuildProperties (MSBuildPropertyOptionNames.EnableTrimAnalyzer, MSBuildPropertyOptionNames.EnableSingleFileAnalyzer)); - } - - [Theory] - [MemberData (nameof (TestCaseUtils.GetTestData), parameters: nameof (Interop))] - public void Interop (string m) - { - RunTest (nameof (Interop), m, UseMSBuildProperties (MSBuildPropertyOptionNames.EnableTrimAnalyzer)); - } - } -} diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs new file mode 100644 index 000000000..6e31cf9e9 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs @@ -0,0 +1,41 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests +{ + public sealed class RequiresCapabilityTests : LinkerTestBase + { + protected override string TestSuiteName => "RequiresCapability"; + + [Fact] + public Task RequiresCapability() + { + return RunTest(nameof(RequiresCapability)); + } + + [Fact] + public Task RequiresCapabilityFromCopiedAssembly () + { + return RunTest (nameof(RequiresCapabilityFromCopiedAssembly)); + } + + [Fact] + public Task RequiresCapabilityReflectionAnalysisEnabled () + { + return RunTest (nameof(RequiresCapabilityReflectionAnalysisEnabled)); + } + + [Fact] + public Task RequiresInCompilerGeneratedCode () + { + return RunTest(nameof(RequiresInCompilerGeneratedCode)); + } + + [Fact] + public Task RequiresOnAttributeCtor () + { + return RunTest (nameof(RequiresOnAttributeCtor)); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs index f35bdbe21..0f35b908a 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs @@ -28,34 +28,28 @@ namespace ILLink.RoslynAnalyzer.Tests Attributes = attributes; } - public void Run (params (string, string)[] MSBuildProperties) + public void Run ((CompilationWithAnalyzers, SemanticModel) compAndModel) { - var testSyntaxTree = MemberSyntax.SyntaxTree.GetRoot ().SyntaxTree; + var testSyntaxTree = MemberSyntax.SyntaxTree; var testDependenciesSource = GetTestDependencies (testSyntaxTree) .Select (testDependency => CSharpSyntaxTree.ParseText (File.ReadAllText (testDependency))); - var test = new TestChecker ( - MemberSyntax, - TestCaseCompilation.CreateCompilation ( - testSyntaxTree, - MSBuildProperties, - additionalSources: testDependenciesSource).Result); - + var test = new TestChecker (MemberSyntax, compAndModel); test.ValidateAttributes (Attributes); } - private static IEnumerable GetTestDependencies (SyntaxTree testSyntaxTree) + public static IEnumerable GetTestDependencies (SyntaxTree testSyntaxTree) { - TestCaseUtils.GetDirectoryPaths (out var rootSourceDir, out _); + LinkerTestBase.GetDirectoryPaths (out var rootSourceDir, out _); foreach (var attribute in testSyntaxTree.GetRoot ().DescendantNodes ().OfType ()) { if (attribute.Name.ToString () != "SetupCompileBefore") continue; var testNamespace = testSyntaxTree.GetRoot ().DescendantNodes ().OfType ().Single ().Name.ToString (); var testSuiteName = testNamespace.Substring (testNamespace.LastIndexOf ('.') + 1); - var args = TestCaseUtils.GetAttributeArguments (attribute); + var args = LinkerTestBase.GetAttributeArguments (attribute); foreach (var sourceFile in ((ImplicitArrayCreationExpressionSyntax) args["#1"]).DescendantNodes ().OfType ()) - yield return Path.Combine (rootSourceDir, testSuiteName, TestCaseUtils.GetStringFromExpression (sourceFile)); + yield return Path.Combine (rootSourceDir, testSuiteName, LinkerTestBase.GetStringFromExpression (sourceFile)); } } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index d4d359a36..bc99fcbfa 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.CompilerServices; @@ -13,6 +14,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Text; using Xunit; namespace ILLink.RoslynAnalyzer.Tests @@ -38,49 +40,28 @@ namespace ILLink.RoslynAnalyzer.Tests return s_net6Refs; } - public static IEnumerable GetTestData (string testSuiteName) - => s_testCases[testSuiteName].Keys.Select (testName => new object[] { testName }); - - public static void RunTest (string suiteName, string testName, params (string, string)[] MSBuildProperties) - { - s_testCases[suiteName][testName].Run (MSBuildProperties); - } - - private static readonly Dictionary> s_testCases = InitializeTestCases (); - - private static Dictionary> InitializeTestCases () + public static async Task RunTestFile (string suiteName, string testName, params (string, string)[] msbuildProperties) { - var testCases = new Dictionary> (); - foreach (var file in GetTestFiles ()) { - // Some tests are in nested directories. Walk up until we get the test suite directory. - string directory = Path.GetDirectoryName (file)!; - string parentDirectory; - while (Path.GetFileName (parentDirectory = Path.GetDirectoryName (directory)!) != MonoLinkerTestsCases) - directory = parentDirectory; - string suiteName = Path.GetFileName (directory); - - if (!testCases.TryGetValue (suiteName, out var suiteTestCases)) { - suiteTestCases = new (); - testCases.Add (suiteName, suiteTestCases); - } - - foreach (var testCase in BuildTestCasesForFile (file)) { - var canditateTestName = GetMemberSyntaxFullName (testCase.MemberSyntax); - string testName = canditateTestName; - int index = 0; - while (!suiteTestCases.TryAdd (testName, testCase)) { - testName = canditateTestName + "#" + (++index).ToString (); - } - - testCase.Name = testName; - } + GetDirectoryPaths(out string rootSourceDir, out string testAssemblyPath); + Debug.Assert(Path.GetFileName(rootSourceDir) == MonoLinkerTestsCases); + var testPath = Path.Combine(rootSourceDir, suiteName, $"{testName}.cs"); + var tree = SyntaxFactory.ParseSyntaxTree(SourceText.From(testPath)); + + var testDependenciesSource = TestCase.GetTestDependencies(tree) + .Select(f => SyntaxFactory.ParseSyntaxTree(SourceText.From(File.OpenRead(f)))); + var comp = await TestCaseCompilation.CreateCompilation ( + tree, + msbuildProperties, + additionalSources: testDependenciesSource); + foreach (var testCase in BuildTestCasesForFile(tree)) + { + testCase.Run(comp); } - return testCases; } - private static IEnumerable BuildTestCasesForFile (string testFile) + private static IEnumerable BuildTestCasesForFile (SyntaxTree tree) { - var root = CSharpSyntaxTree.ParseText (File.ReadAllText (testFile)).GetRoot (); + var root = tree.GetRoot (); foreach (var node in root.DescendantNodes ()) { if (node is MemberDeclarationSyntax m) { var attrs = m.AttributeLists.SelectMany (al => al.Attributes.Where (IsWellKnown)).ToList (); @@ -180,26 +161,6 @@ namespace ILLink.RoslynAnalyzer.Tests return arguments; } - public static IEnumerable GetTestFiles () - { - GetDirectoryPaths (out var rootSourceDir, out _); - foreach (var subDir in Directory.EnumerateDirectories (rootSourceDir, "*", SearchOption.AllDirectories)) { - var subDirName = Path.GetFileName (subDir); - switch (subDirName) { - case "bin": - case "obj": - case "Properties": - case "Dependencies": - case "Individual": - continue; - } - - foreach (var file in Directory.EnumerateFiles (subDir, "*.cs")) { - yield return file; - } - } - } - public static (string, string)[] UseMSBuildProperties (params string[] MSBuildProperties) { return MSBuildProperties.Select (msbp => ($"build_property.{msbp}", "true")).ToArray (); @@ -211,30 +172,5 @@ namespace ILLink.RoslynAnalyzer.Tests string ThisFile ([CallerFilePath] string path = "") => path; } - - public static string GetMemberSyntaxFullName (MemberDeclarationSyntax member) - { - StringBuilder fullName = new (); - var parent = member.Parent; - while (parent is ClassDeclarationSyntax parentClass) { - fullName.Insert (0, "."); - fullName.Insert (0, parentClass.Identifier.ToString ()); - parent = parentClass.Parent; - } - - fullName.Append (GetMemberSyntaxName (member)); - return fullName.ToString (); - } - - public static string GetMemberSyntaxName (MemberDeclarationSyntax member) => - member switch { - MethodDeclarationSyntax method => method.Identifier.ToString (), - PropertyDeclarationSyntax property => property.Identifier.ToString (), - FieldDeclarationSyntax field => field.Declaration.Variables.Single ().Identifier.ToString (), - EventDeclarationSyntax @event => @event.Identifier.ToString (), - ClassDeclarationSyntax @class => @class.Identifier.ToString (), - ConstructorDeclarationSyntax ctor => ctor.Modifiers.Any (t => t.Text == "static") ? ".cctor" : ".ctor", - _ => "UnknownMember" - }; } } diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs index e86ee919f..5da895fce 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs @@ -68,7 +68,7 @@ namespace ILLink.RoslynAnalyzer.Tests switch (attribute.Name.ToString ()) { case "ExpectedWarning": case "LogContains": - var args = TestCaseUtils.GetAttributeArguments (attribute); + var args = LinkerTestBase.GetAttributeArguments (attribute); if (args.TryGetValue ("ProducedBy", out var producedBy)) { // Skip if this warning is not expected to be produced by any of the analyzers that we are currently testing. return GetProducedBy (producedBy).HasFlag (ProducedBy.Analyzer); @@ -154,15 +154,15 @@ namespace ILLink.RoslynAnalyzer.Tests { missingDiagnosticMessage = null; matchIndex = null; - var args = TestCaseUtils.GetAttributeArguments (attribute); - string expectedWarningCode = TestCaseUtils.GetStringFromExpression (args["#0"]); + var args = LinkerTestBase.GetAttributeArguments (attribute); + string expectedWarningCode = LinkerTestBase.GetStringFromExpression (args["#0"]); if (!expectedWarningCode.StartsWith ("IL")) throw new InvalidOperationException ($"Expected warning code should start with \"IL\" prefix."); List expectedMessages = args .Where (arg => arg.Key.StartsWith ("#") && arg.Key != "#0") - .Select (arg => TestCaseUtils.GetStringFromExpression (arg.Value, SemanticModel)) + .Select (arg => LinkerTestBase.GetStringFromExpression (arg.Value, SemanticModel)) .ToList (); for (int i = 0; i < diagnostics.Count; i++) { @@ -193,8 +193,8 @@ namespace ILLink.RoslynAnalyzer.Tests { missingDiagnosticMessage = null; matchIndex = null; - var args = TestCaseUtils.GetAttributeArguments (attribute); - var text = TestCaseUtils.GetStringFromExpression (args["#0"]); + var args = LinkerTestBase.GetAttributeArguments (attribute); + var text = LinkerTestBase.GetStringFromExpression (args["#0"]); // If the text starts with `warning IL...` then it probably follows the pattern // 'warning : :' @@ -224,8 +224,8 @@ namespace ILLink.RoslynAnalyzer.Tests private void ValidateLogDoesNotContainAttribute (AttributeSyntax attribute, List diagnosticMessages) { - var arg = Assert.Single (TestCaseUtils.GetAttributeArguments (attribute)); - var text = TestCaseUtils.GetStringFromExpression (arg.Value); + var arg = Assert.Single (LinkerTestBase.GetAttributeArguments (attribute)); + var text = LinkerTestBase.GetStringFromExpression (arg.Value); foreach (var diagnostic in DiagnosticMessages) Assert.DoesNotContain (text, diagnostic.GetMessage ()); } @@ -234,21 +234,21 @@ namespace ILLink.RoslynAnalyzer.Tests { missingDiagnosticMessage = null; matchIndex = null; - var args = TestCaseUtils.GetAttributeArguments (attribute); + var args = LinkerTestBase.GetAttributeArguments (attribute); MemberDeclarationSyntax sourceMember = attribute.Ancestors ().OfType ().First (); if (SemanticModel.GetDeclaredSymbol (sourceMember) is not ISymbol memberSymbol) return false; string sourceMemberName = memberSymbol!.GetDisplayName (); - string expectedReflectionMemberMethodType = TestCaseUtils.GetStringFromExpression (args["#0"], SemanticModel); - string expectedReflectionMemberMethodName = TestCaseUtils.GetStringFromExpression (args["#1"], SemanticModel); + string expectedReflectionMemberMethodType = LinkerTestBase.GetStringFromExpression (args["#0"], SemanticModel); + string expectedReflectionMemberMethodName = LinkerTestBase.GetStringFromExpression (args["#1"], SemanticModel); var reflectionMethodParameters = new List (); if (args.TryGetValue ("#2", out var reflectionMethodParametersExpr) || args.TryGetValue ("reflectionMethodParameters", out reflectionMethodParametersExpr)) { if (reflectionMethodParametersExpr is ArrayCreationExpressionSyntax arrayReflectionMethodParametersExpr) { foreach (var rmp in arrayReflectionMethodParametersExpr.Initializer!.Expressions) - reflectionMethodParameters.Add (TestCaseUtils.GetStringFromExpression (rmp, SemanticModel)); + reflectionMethodParameters.Add (LinkerTestBase.GetStringFromExpression (rmp, SemanticModel)); } } @@ -256,13 +256,13 @@ namespace ILLink.RoslynAnalyzer.Tests if (args.TryGetValue ("#3", out var messageExpr) || args.TryGetValue ("message", out messageExpr)) { if (messageExpr is ArrayCreationExpressionSyntax arrayMessageExpr) { foreach (var m in arrayMessageExpr.Initializer!.Expressions) - expectedStringsInMessage.Add (TestCaseUtils.GetStringFromExpression (m, SemanticModel)); + expectedStringsInMessage.Add (LinkerTestBase.GetStringFromExpression (m, SemanticModel)); } } string expectedWarningCode = string.Empty; if (args.TryGetValue ("#4", out var messageCodeExpr) || args.TryGetValue ("messageCode", out messageCodeExpr)) { - expectedWarningCode = TestCaseUtils.GetStringFromExpression (messageCodeExpr); + expectedWarningCode = LinkerTestBase.GetStringFromExpression (messageCodeExpr); Assert.True (expectedWarningCode.StartsWith ("IL"), $"The warning code specified in {messageCodeExpr.ToString ()} must start with the 'IL' prefix. Specified value: '{expectedWarningCode}'"); } diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs index 22800682e..40814d2e6 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresCapability.cs @@ -1925,7 +1925,7 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability public static int field; // `field` cannot be used as named attribute argument because is static, and if accessed via - // a property the property will be the one generating the warning, but then the warning will + // a property the property will be the one generating the warning, but then the warning will // be suppresed by the Requires on the declaring type public int PropertyOnAttribute { get { return field; } -- cgit v1.2.3 From 959a30acdd4622c1e57f48389e97a9ef01aa5963 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Thu, 11 Nov 2021 12:14:31 -0800 Subject: Lint --- test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs | 22 ++++---- .../RequiresCapabilityTests.cs | 58 +++++++++++----------- test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs | 17 +++---- 3 files changed, 48 insertions(+), 49 deletions(-) diff --git a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs index e0363379e..2b5ef8c38 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs @@ -3,17 +3,17 @@ using System.Threading.Tasks; namespace ILLink.RoslynAnalyzer.Tests { - public abstract class LinkerTestBase : TestCaseUtils - { - protected abstract string TestSuiteName { get; } + public abstract class LinkerTestBase : TestCaseUtils + { + protected abstract string TestSuiteName { get; } - private static readonly (string, string)[] MSBuildProperties = UseMSBuildProperties ( - MSBuildPropertyOptionNames.EnableTrimAnalyzer, - MSBuildPropertyOptionNames.EnableSingleFileAnalyzer); + private static readonly (string, string)[] MSBuildProperties = UseMSBuildProperties ( + MSBuildPropertyOptionNames.EnableTrimAnalyzer, + MSBuildPropertyOptionNames.EnableSingleFileAnalyzer); - protected Task RunTest(string testName) - { - return RunTestFile (TestSuiteName, testName, MSBuildProperties); - } - } + protected Task RunTest (string testName) + { + return RunTestFile (TestSuiteName, testName, MSBuildProperties); + } + } } \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs index 6e31cf9e9..6dba8bc95 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs @@ -4,38 +4,38 @@ using Xunit; namespace ILLink.RoslynAnalyzer.Tests { - public sealed class RequiresCapabilityTests : LinkerTestBase - { - protected override string TestSuiteName => "RequiresCapability"; + public sealed class RequiresCapabilityTests : LinkerTestBase + { + protected override string TestSuiteName => "RequiresCapability"; - [Fact] - public Task RequiresCapability() - { - return RunTest(nameof(RequiresCapability)); - } + [Fact] + public Task RequiresCapability () + { + return RunTest (nameof (RequiresCapability)); + } - [Fact] - public Task RequiresCapabilityFromCopiedAssembly () - { - return RunTest (nameof(RequiresCapabilityFromCopiedAssembly)); - } + [Fact] + public Task RequiresCapabilityFromCopiedAssembly () + { + return RunTest (nameof (RequiresCapabilityFromCopiedAssembly)); + } - [Fact] - public Task RequiresCapabilityReflectionAnalysisEnabled () - { - return RunTest (nameof(RequiresCapabilityReflectionAnalysisEnabled)); - } + [Fact] + public Task RequiresCapabilityReflectionAnalysisEnabled () + { + return RunTest (nameof (RequiresCapabilityReflectionAnalysisEnabled)); + } - [Fact] - public Task RequiresInCompilerGeneratedCode () - { - return RunTest(nameof(RequiresInCompilerGeneratedCode)); - } + [Fact] + public Task RequiresInCompilerGeneratedCode () + { + return RunTest (nameof (RequiresInCompilerGeneratedCode)); + } - [Fact] - public Task RequiresOnAttributeCtor () - { - return RunTest (nameof(RequiresOnAttributeCtor)); - } - } + [Fact] + public Task RequiresOnAttributeCtor () + { + return RunTest (nameof (RequiresOnAttributeCtor)); + } + } } \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index bc99fcbfa..9c2a1aca7 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -42,20 +42,19 @@ namespace ILLink.RoslynAnalyzer.Tests public static async Task RunTestFile (string suiteName, string testName, params (string, string)[] msbuildProperties) { - GetDirectoryPaths(out string rootSourceDir, out string testAssemblyPath); - Debug.Assert(Path.GetFileName(rootSourceDir) == MonoLinkerTestsCases); - var testPath = Path.Combine(rootSourceDir, suiteName, $"{testName}.cs"); - var tree = SyntaxFactory.ParseSyntaxTree(SourceText.From(testPath)); + GetDirectoryPaths (out string rootSourceDir, out string testAssemblyPath); + Debug.Assert (Path.GetFileName (rootSourceDir) == MonoLinkerTestsCases); + var testPath = Path.Combine (rootSourceDir, suiteName, $"{testName}.cs"); + var tree = SyntaxFactory.ParseSyntaxTree (SourceText.From (testPath)); - var testDependenciesSource = TestCase.GetTestDependencies(tree) - .Select(f => SyntaxFactory.ParseSyntaxTree(SourceText.From(File.OpenRead(f)))); + var testDependenciesSource = TestCase.GetTestDependencies (tree) + .Select (f => SyntaxFactory.ParseSyntaxTree (SourceText.From (File.OpenRead (f)))); var comp = await TestCaseCompilation.CreateCompilation ( tree, msbuildProperties, additionalSources: testDependenciesSource); - foreach (var testCase in BuildTestCasesForFile(tree)) - { - testCase.Run(comp); + foreach (var testCase in BuildTestCasesForFile (tree)) { + testCase.Run (comp); } } -- cgit v1.2.3 From 1d47968b26535eae0ab4b0463efdcd6f13178193 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Thu, 11 Nov 2021 12:55:41 -0800 Subject: Update CODEOWNERS --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 234b0fced..80251a28e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,5 +7,6 @@ /src/analyzer/ @radekdoulik /src/ILLink.Tasks/ @sbomer +/src/ILLink.RoslynAnalyzer/ @sbomer /src/linker/ @marek-safar @mrvoorhe /test/ @marek-safar @mrvoorhe -- cgit v1.2.3 From 5a3f9169f2894961ba4e68aab105a55b80accc62 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 12 Nov 2021 16:18:04 -0800 Subject: Add back Interop tests --- .../Interop/InternalCalls/ComTests.cs | 41 ++++++++++++++++++ .../Interop/InternalCalls/InternalCallsTests.cs | 47 +++++++++++++++++++++ .../Interop/PInvoke/ComTests.cs | 41 ++++++++++++++++++ .../Interop/PInvoke/IndividualTests.cs | 17 ++++++++ .../Interop/PInvoke/PInvokeTests.cs | 48 ++++++++++++++++++++++ .../Interop/PInvoke/Warnings.cs | 17 ++++++++ test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs | 3 +- test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs | 12 ++++-- 8 files changed, 222 insertions(+), 4 deletions(-) create mode 100644 test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs create mode 100644 test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs create mode 100644 test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs create mode 100644 test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs create mode 100644 test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs create mode 100644 test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs new file mode 100644 index 000000000..852ebe826 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs @@ -0,0 +1,41 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop.InternalCalls +{ + public sealed class ComTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/InternalCalls/Com"; + + [Fact] + public Task DefaultConstructorOfParameterIsRemoved() + { + return RunTest(); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsRemoved() + { + return RunTest(); + } + + [Fact] + public Task FieldsOfParameterAreRemoved() + { + return RunTest(); + } + + [Fact] + public Task FieldsOfReturnTypeAreRemoved() + { + return RunTest(); + } + + [Fact] + public Task FieldsOfThisAreRemoved() + { + return RunTest(); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs new file mode 100644 index 000000000..d3d146edd --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs @@ -0,0 +1,47 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop +{ + public sealed class InternalCallsTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/InternalCalls"; + + [Fact] + public Task UnusedDefaultConstructorIsRemoved() + { + return RunTest(); + } + + [Fact] + public Task UnusedFieldsOfTypesAreNotRemoved() + { + return RunTest(); + } + + [Fact] + public Task UnusedFieldsOfTypesWhenHasThisAreNotRemoved() + { + return RunTest(); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsNotRemoved() + { + return RunTest(); + } + + [Fact] + public Task UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved() + { + return RunTest(); + } + + [Fact] + public Task UnusedFieldsOfTypesPassedByRefAreNotRemoved() + { + return RunTest(); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs new file mode 100644 index 000000000..37b0220a8 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs @@ -0,0 +1,41 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke +{ + public sealed class ComTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke/Com"; + + [Fact] + public Task DefaultConstructorOfParameterIsRemoved () + { + return RunTest(); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsRemoved () + { + return RunTest(); + } + + [Fact] + public Task FieldsOfParameterAreRemoved () + { + return RunTest(); + } + + [Fact] + public Task FieldsOfReturnTypeAreRemoved () + { + return RunTest(); + } + + [Fact] + public Task FieldsOfThisAreRemoved () + { + return RunTest(); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs new file mode 100644 index 000000000..6d3bac52c --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs @@ -0,0 +1,17 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke +{ + public class IndividualTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke/Individual"; + + [Fact] + public Task CanOutputPInvokes() + { + return RunTest(); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs new file mode 100644 index 000000000..483b4c956 --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs @@ -0,0 +1,48 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop +{ + public sealed class PInvokeTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke"; + + + [Fact] + public Task UnusedDefaultConstructorIsRemoved() + { + return RunTest(); + } + + [Fact] + public Task UnusedFieldsOfTypesPassedByRefAreNotRemoved() + { + return RunTest(); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsNotRemoved() + { + return RunTest(); + } + + [Fact] + public Task UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved() + { + return RunTest(); + } + + [Fact] + public Task UnusedFieldsOfTypesAreNotRemoved() + { + return RunTest(); + } + + [Fact] + public Task UnusedPInvoke() + { + return RunTest(); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs new file mode 100644 index 000000000..63fb8b99d --- /dev/null +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs @@ -0,0 +1,17 @@ + +using System.Threading.Tasks; +using Xunit; + +namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke +{ + public sealed class WarningsTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke/Warnings"; + + [Fact] + public Task ComPInvokeWarning() + { + return RunTest(); + } + } +} \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs index 2b5ef8c38..1a382693e 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/LinkerTestBase.cs @@ -1,4 +1,5 @@ +using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace ILLink.RoslynAnalyzer.Tests @@ -11,7 +12,7 @@ namespace ILLink.RoslynAnalyzer.Tests MSBuildPropertyOptionNames.EnableTrimAnalyzer, MSBuildPropertyOptionNames.EnableSingleFileAnalyzer); - protected Task RunTest (string testName) + protected Task RunTest ([CallerMemberName] string testName = "") { return RunTestFile (TestSuiteName, testName, MSBuildProperties); } diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index 9c2a1aca7..eb5e0ca3c 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -45,7 +45,10 @@ namespace ILLink.RoslynAnalyzer.Tests GetDirectoryPaths (out string rootSourceDir, out string testAssemblyPath); Debug.Assert (Path.GetFileName (rootSourceDir) == MonoLinkerTestsCases); var testPath = Path.Combine (rootSourceDir, suiteName, $"{testName}.cs"); - var tree = SyntaxFactory.ParseSyntaxTree (SourceText.From (testPath)); + Assert.True(File.Exists(testPath)); + var tree = SyntaxFactory.ParseSyntaxTree ( + SourceText.From (File.OpenRead(testPath), Encoding.UTF8), + path: testPath); var testDependenciesSource = TestCase.GetTestDependencies (tree) .Select (f => SyntaxFactory.ParseSyntaxTree (SourceText.From (File.OpenRead (f)))); @@ -53,12 +56,15 @@ namespace ILLink.RoslynAnalyzer.Tests tree, msbuildProperties, additionalSources: testDependenciesSource); - foreach (var testCase in BuildTestCasesForFile (tree)) { + foreach (var testCase in BuildTestCasesForTree (tree)) { testCase.Run (comp); } } - private static IEnumerable BuildTestCasesForFile (SyntaxTree tree) + /// + /// Builds a for each member in the tree. + /// + private static IEnumerable BuildTestCasesForTree (SyntaxTree tree) { var root = tree.GetRoot (); foreach (var node in root.DescendantNodes ()) { -- cgit v1.2.3 From adfa7a1dee4741a1b8c4f4667b9fa7055a088a49 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 12 Nov 2021 16:19:09 -0800 Subject: Lint --- .../Interop/InternalCalls/ComTests.cs | 54 ++++++++-------- .../Interop/InternalCalls/InternalCallsTests.cs | 74 +++++++++++----------- .../Interop/PInvoke/ComTests.cs | 10 +-- .../Interop/PInvoke/IndividualTests.cs | 14 ++-- .../Interop/PInvoke/PInvokeTests.cs | 24 +++---- .../Interop/PInvoke/Warnings.cs | 18 +++--- test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs | 4 +- 7 files changed, 99 insertions(+), 99 deletions(-) diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs index 852ebe826..7545840f0 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/ComTests.cs @@ -4,38 +4,38 @@ using Xunit; namespace ILLink.RoslynAnalyzer.Tests.Interop.InternalCalls { - public sealed class ComTests : LinkerTestBase - { + public sealed class ComTests : LinkerTestBase + { protected override string TestSuiteName => "Interop/InternalCalls/Com"; [Fact] - public Task DefaultConstructorOfParameterIsRemoved() - { - return RunTest(); - } + public Task DefaultConstructorOfParameterIsRemoved () + { + return RunTest (); + } - [Fact] - public Task DefaultConstructorOfReturnTypeIsRemoved() - { - return RunTest(); - } + [Fact] + public Task DefaultConstructorOfReturnTypeIsRemoved () + { + return RunTest (); + } - [Fact] - public Task FieldsOfParameterAreRemoved() - { - return RunTest(); - } + [Fact] + public Task FieldsOfParameterAreRemoved () + { + return RunTest (); + } - [Fact] - public Task FieldsOfReturnTypeAreRemoved() - { - return RunTest(); - } + [Fact] + public Task FieldsOfReturnTypeAreRemoved () + { + return RunTest (); + } - [Fact] - public Task FieldsOfThisAreRemoved() - { - return RunTest(); - } - } + [Fact] + public Task FieldsOfThisAreRemoved () + { + return RunTest (); + } + } } \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs index d3d146edd..58e8ed443 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/InternalCalls/InternalCallsTests.cs @@ -4,44 +4,44 @@ using Xunit; namespace ILLink.RoslynAnalyzer.Tests.Interop { - public sealed class InternalCallsTests : LinkerTestBase - { + public sealed class InternalCallsTests : LinkerTestBase + { protected override string TestSuiteName => "Interop/InternalCalls"; [Fact] - public Task UnusedDefaultConstructorIsRemoved() - { - return RunTest(); - } - - [Fact] - public Task UnusedFieldsOfTypesAreNotRemoved() - { - return RunTest(); - } - - [Fact] - public Task UnusedFieldsOfTypesWhenHasThisAreNotRemoved() - { - return RunTest(); - } - - [Fact] - public Task DefaultConstructorOfReturnTypeIsNotRemoved() - { - return RunTest(); - } - - [Fact] - public Task UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved() - { - return RunTest(); - } - - [Fact] - public Task UnusedFieldsOfTypesPassedByRefAreNotRemoved() - { - return RunTest(); - } - } + public Task UnusedDefaultConstructorIsRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedFieldsOfTypesAreNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedFieldsOfTypesWhenHasThisAreNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task DefaultConstructorOfReturnTypeIsNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved () + { + return RunTest (); + } + + [Fact] + public Task UnusedFieldsOfTypesPassedByRefAreNotRemoved () + { + return RunTest (); + } + } } \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs index 37b0220a8..a07563ec9 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/ComTests.cs @@ -11,31 +11,31 @@ namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke [Fact] public Task DefaultConstructorOfParameterIsRemoved () { - return RunTest(); + return RunTest (); } [Fact] public Task DefaultConstructorOfReturnTypeIsRemoved () { - return RunTest(); + return RunTest (); } [Fact] public Task FieldsOfParameterAreRemoved () { - return RunTest(); + return RunTest (); } [Fact] public Task FieldsOfReturnTypeAreRemoved () { - return RunTest(); + return RunTest (); } [Fact] public Task FieldsOfThisAreRemoved () { - return RunTest(); + return RunTest (); } } } \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs index 6d3bac52c..04e393753 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/IndividualTests.cs @@ -4,14 +4,14 @@ using Xunit; namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke { - public class IndividualTests : LinkerTestBase - { + public class IndividualTests : LinkerTestBase + { protected override string TestSuiteName => "Interop/PInvoke/Individual"; [Fact] - public Task CanOutputPInvokes() - { - return RunTest(); - } - } + public Task CanOutputPInvokes () + { + return RunTest (); + } + } } \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs index 483b4c956..7ee4ae899 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/PInvokeTests.cs @@ -10,39 +10,39 @@ namespace ILLink.RoslynAnalyzer.Tests.Interop [Fact] - public Task UnusedDefaultConstructorIsRemoved() + public Task UnusedDefaultConstructorIsRemoved () { - return RunTest(); + return RunTest (); } [Fact] - public Task UnusedFieldsOfTypesPassedByRefAreNotRemoved() + public Task UnusedFieldsOfTypesPassedByRefAreNotRemoved () { - return RunTest(); + return RunTest (); } [Fact] - public Task DefaultConstructorOfReturnTypeIsNotRemoved() + public Task DefaultConstructorOfReturnTypeIsNotRemoved () { - return RunTest(); + return RunTest (); } [Fact] - public Task UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved() + public Task UnusedDefaultConstructorOfTypePassedByRefIsNotRemoved () { - return RunTest(); + return RunTest (); } [Fact] - public Task UnusedFieldsOfTypesAreNotRemoved() + public Task UnusedFieldsOfTypesAreNotRemoved () { - return RunTest(); + return RunTest (); } [Fact] - public Task UnusedPInvoke() + public Task UnusedPInvoke () { - return RunTest(); + return RunTest (); } } } \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs index 63fb8b99d..a3a1a3f1d 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Interop/PInvoke/Warnings.cs @@ -4,14 +4,14 @@ using Xunit; namespace ILLink.RoslynAnalyzer.Tests.Interop.PInvoke { - public sealed class WarningsTests : LinkerTestBase - { - protected override string TestSuiteName => "Interop/PInvoke/Warnings"; + public sealed class WarningsTests : LinkerTestBase + { + protected override string TestSuiteName => "Interop/PInvoke/Warnings"; - [Fact] - public Task ComPInvokeWarning() - { - return RunTest(); - } - } + [Fact] + public Task ComPInvokeWarning () + { + return RunTest (); + } + } } \ No newline at end of file diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index eb5e0ca3c..44881437d 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -45,9 +45,9 @@ namespace ILLink.RoslynAnalyzer.Tests GetDirectoryPaths (out string rootSourceDir, out string testAssemblyPath); Debug.Assert (Path.GetFileName (rootSourceDir) == MonoLinkerTestsCases); var testPath = Path.Combine (rootSourceDir, suiteName, $"{testName}.cs"); - Assert.True(File.Exists(testPath)); + Assert.True (File.Exists (testPath)); var tree = SyntaxFactory.ParseSyntaxTree ( - SourceText.From (File.OpenRead(testPath), Encoding.UTF8), + SourceText.From (File.OpenRead (testPath), Encoding.UTF8), path: testPath); var testDependenciesSource = TestCase.GetTestDependencies (tree) -- cgit v1.2.3 From 48689614f6a3f1d2e995bdb74750f89cfcb4af06 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 13:28:13 +0000 Subject: Update dependencies from https://github.com/dotnet/arcade build 20211109.3 (#2367) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/msbuild.ps1 | 1 + global.json | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b4c07c7cc..f71b60d76 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -3,14 +3,14 @@ - + https://github.com/dotnet/arcade - a7c57abb74deaee6dac921dd68f9c3c58059ebfb + fecf65bedcee9036b8ba9d8d7feef5413f294914 - + https://github.com/dotnet/arcade - a7c57abb74deaee6dac921dd68f9c3c58059ebfb + fecf65bedcee9036b8ba9d8d7feef5413f294914 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 055884e01..5c82c68b0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -18,7 +18,7 @@ 5.0.0 17.0.0-preview-21267-01 17.0.0-preview-21267-01 - 7.0.0-beta.21555.2 + 7.0.0-beta.21559.3 6.0.0-beta.21271.1 3.10.0-2.final 3.10.0-2.final diff --git a/eng/common/msbuild.ps1 b/eng/common/msbuild.ps1 index eea19cd84..f041e5ddd 100644 --- a/eng/common/msbuild.ps1 +++ b/eng/common/msbuild.ps1 @@ -6,6 +6,7 @@ Param( [switch] $ci, [switch] $prepareMachine, [switch] $excludePrereleaseVS, + [string] $msbuildEngine = $null, [Parameter(ValueFromRemainingArguments=$true)][String[]]$extraArgs ) diff --git a/global.json b/global.json index 50f0cd7d7..e474fb1ed 100644 --- a/global.json +++ b/global.json @@ -3,7 +3,7 @@ "dotnet": "6.0.100-rc.1.21430.12" }, "msbuild-sdks": { - "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21555.2", + "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21559.3", "Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21556.5" } -- cgit v1.2.3 From 1bd0af283d629863b04ba6eb6eb93bc0b662708e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 13:28:21 +0000 Subject: Update dependencies from https://github.com/dotnet/runtime build 20211112.1 (#2368) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f71b60d76..2edca87dc 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -12,9 +12,9 @@ https://github.com/dotnet/arcade fecf65bedcee9036b8ba9d8d7feef5413f294914 - + https://github.com/dotnet/runtime - d40f560efbf4f85ec6d59892a6c4bafa39f66d19 + 35704e44e5d1b158f21512b1c1081a0e025bde3f - 7.0.0-alpha.1.21556.5 + 7.0.0-alpha.1.21562.1 $(MicrosoftNETSdkILPackageVersion) diff --git a/global.json b/global.json index e474fb1ed..868829aa0 100644 --- a/global.json +++ b/global.json @@ -5,6 +5,6 @@ "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21559.3", "Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0", - "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21556.5" + "Microsoft.NET.Sdk.IL": "7.0.0-alpha.1.21562.1" } } -- cgit v1.2.3 From d74c97b5fb356c257caaa546516ca430ed579e24 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Mon, 15 Nov 2021 17:03:33 +0100 Subject: Compiler generated code handling (#2010) * Problem description and existing patterns * Proposed solutions and some discussion of these Co-authored-by: Eric Erhardt --- docs/design/compiler-generated-code-handling.md | 628 ++++++++++++++++++++++++ 1 file changed, 628 insertions(+) create mode 100644 docs/design/compiler-generated-code-handling.md diff --git a/docs/design/compiler-generated-code-handling.md b/docs/design/compiler-generated-code-handling.md new file mode 100644 index 000000000..4ed908db0 --- /dev/null +++ b/docs/design/compiler-generated-code-handling.md @@ -0,0 +1,628 @@ +# Handling of compiler generated code + +Modern compilers provide language features which require lot of fancy code generation by the compiler. Not just pure IL generation, but producing new types, methods and fields. An example is `async`/`await` in C# which turns the body of the method into a separate class which implements a state machine. + +Lot of the trimming logic relies on attributes authored by the developer. These provide hints to the trimmer especially around areas which are otherwise problematic, like reflection. For example see [reflection-flow](reflection-flow.md) for an example of such attribute. + +## Problem + +User authored attributes are not propagated to the compiler generated code. For example (using C# async feature): + +```csharp +[RequiresUnreferencedCode ("--MethodRequiresUnreferencedCode--")] +static void MethodRequiresUnreferencedCode () { } + +[UnconditionalSuppressMessage ("IL2026", "")] +static async void TestBeforeAwait () +{ + MethodRequiresUnreferencedCode (); + await AsyncMethod (); +} +``` + +This code should not produce any warning, because the `IL2026` is suppressed via an attribute. But currently this will produce the `IL2026` warning from a different method: + +```console +ILLink: Trim analysis warning IL2026: SuppressWarningsInAsyncCode.d__1.MoveNext(): Using method 'MethodRequiresUnreferencedCode()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. +``` + +Note that the warning comes from a compiler generated method `MoveNext` on class `d__1`. The `UnconditionalSuppressMessage` attribute is not propagated and so from a trimmer perspective this is completely unrelated code and thus the warning is not suppressed. + +### Method body attributes + +The trimmer currently recognizes two attributes which effectively apply to entire method body: + +#### `RequiresUnreferencedCodeAttribute` + +The `RequiresUnreferencedCodeAttribute` marks the method as incompatible with trimming and at the same time it suppressed trim analysis warnings from the entire method's body. So for example (using C# iterator feature): + +```csharp +[RequiresUnreferencedCode ("Incompatible with trimming")] +static IEnumerable TestBeforeIterator () +{ + MethodRequiresUnreferencedCode (); + yield return 1; +} +``` + +Should not produce a warning. + +#### `UnconditionalSuppressMessageAttribute` + +The `UnconditionalSuppressMessageAttribute` can target lot of scopes, but the smallest one is a method. It can't target specific statements within a method. It is supposed to suppress a specific warning from the method's body, for example: + +```csharp +[UnconditionalSuppressMessage("IL2026", "")] +static async void TestAfterAwait () +{ + await AsyncMethod (); + MethodRequiresUnreferencedCode (); +} +``` + +Should not produce a warning. + +### Data flow analysis + +The trimmer performs data flow analysis within a single method's body, mostly around track the flow of `System.Type` and related instances to be able to detect recursion usage. + +#### `DynamicallyAccessedMembersAttribute` + +The `DynamicallyAccessedMembersAttribute` annotates values (local variables, method parameters, ...) of type `System.Type` to hint the trimmer that the type will have its methods accessed dynamically (through reflection). Such annotation doesn't propagate currently. For example: + +```csharp +static IEnumerable TestParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) +{ + type.GetMethod ("BeforeIteratorMethod"); + yield return 1; + type.GetMethod ("AfterIteratorMethod"); +} +``` + +Should not produce any warnings, because the `type` variable is properly annotated. + +#### Intrinsic data flow + +The trimmer also intrinsically recognizes certain patterns and perform data flow analysis around them. This allows full analysis of certain reflection usage even without annotations. For example, intrinsic handling of the `typeof` keyword: + +```csharp +static IEnumerable TestLocalVariable () +{ + Type type = typeof (TestType); + type.GetMethod ("BeforeIteratorMethod"); + yield return 1; + type.GetMethod ("AfterIteratorMethod"); +} +``` + +### Compiler dependent behavior + +Since the problems are all caused by compiler generated code, the behaviors depend on the specific compiler in use. The main focus of this document is the Roslyn C# compiler right now. Mainly since it's by far the most used compiler for .NET code. That said, we would like to design the solution in such a way that other compilers using similar patterns could also benefit from it. + +It is expected that other compilers (for example the F# compiler) might have other patterns which are also problematic for trimmers. These should be eventually added to the document as well, but may require new solutions not discussed in here yet. + +## A - Roslyn closure rewrite expected behavior + +In order to create a lambda method with captured variables, the Roslyn compiler will generate a closure class which stores the captured values and the lambda method is then generated as a method on that class. Currently compiler doesn't propagate attributes to the generated methods. + +### A1 - `RequiresUnreferencedCode` with lambda + +```csharp +[RequiresUnreferencedCode ("--TestLambdaWithCapture--")] +static void TestLambdaWithCapture (int p) +{ + Action a = () => MethodRequiresUnreferencedCode (p); +} +``` + +Trimmer should suppress trim analysis warnings due to `RequiresUnreferencedCode` even inside the lambda. In C# 10 it will be possible to add an attribute onto the lambda directly. The attribute should be propagated only if it's not already there. +**Open question Q1a**: Should method body attributes propagate to lambdas? Maybe we should rely on C# 10 and explicit attributes only. + +### A2 - `UnconditionalSuppressMessage` with lambda + +```csharp +[UnconditionalSuppressMessage ("IL2026", "")] +static void TestLambdaWithCapture (int p) +{ + Action a = () => MethodRequiresUnreferencedCode (p); +} +``` + +Trimmer should suppress `IL2026` due to the suppression attribute. In C# 10 it will be possible to add an attribute onto the lambda directly. The attribute should be propagated only if it's not already there. +**Open question Q1a**: Should method body attributes propagate to lambdas? Maybe we should rely on C# 10 and explicit attributes only. + +### A3 - Data flow annotations with lambda + +```csharp +static void TestParameterInLambda ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) +{ + Action a = () => { + type.GetMethod ("InLambdaMethod"); + }; +} +``` + +Trimmer should be able to flow the annotation from the parameter into the closure for the lambda and thus avoid warning in this case. + +### A4 - Intrinsic data flow with lambda + +```csharp +static void TestLocalVariableInLambda () +{ + Type type = typeof (TestType); + Action a = () => { + type.GetMethod ("InLambdaMethod"); + }; +} +``` + +Internal data flow tracking should propagate into lambdas. + +### A5 - Generic parameter data flow with lambda + +```csharp +static void TestGenericParameterInLambda<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () +{ + Action a = () => { + typeof (T).GetMethod ("InLocalMethod"); + }; +} +``` + +Annotations should flow with the generic parameter into lambdas. + +### A6 - `RequiresUnreferencedCode` with local function + +```csharp +[RequiresUnreferencedCode ("--TestLocalFunctionWithNoCapture--")] +static void TestLocalFunctionWithNoCapture () +{ + LocalFunction (); + + void LocalFunction() + { + MethodRequiresUnreferencedCode (); + } +} +``` + +The trimmer could propagate the `RequiresUnreferencedCode` to the local function. Unless the function already has that attribute present. +**Question Q1b**: Should method body attributes propagate to local functions? It's possible to add the attribute manually to the local function, so maybe we should simply rely on that. + +### A7 - `UnconditionalSuppressMessage` with local function + +```csharp +[UnconditionalSuppressMessage ("IL2026", "")] +static void TestLocalFunctionWithNoCapture () +{ + LocalFunction (); + + void LocalFunction () + { + MethodRequiresUnreferencedCode (); + } +} +``` + +Similarly to the A5 case, the trimmer could propagate the warning suppression to the local function. Unless the function already has suppressions. +**Question Q1b**: Should method body attributes propagate to local functions? It's possible to add the attribute manually to the local function, so maybe we should simply rely on that. + +### A8 - Data flow annotations with local function + +```csharp +static void TestParameterInLocalFunction ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) +{ + LocalFunction (); + + void LocalFunction () + { + type.GetMethod ("InLocalMethod"); + } +} +``` + +Identical to A3, annotations should propagate into local functions. + +### A9 - Intrinsic data flow with local function + +```csharp +static void TestLocalVariableInLocalFunction () +{ + Type type = typeof (TestType); + LocalFunction (); + + void LocalFunction () + { + type.GetMethod ("InLocalMethod"); + } +} +``` + +Identical to A4 - Internal data flow tracking should propagate into local functions. + +### A10 - Generic parameter data flow with local functions + +```csharp +static void TestGenericParameterInLocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () +{ + LocalFunction (); + + void LocalFunction () + { + typeof (T).GetMethod ("InLocalMethod"); + } +} +``` + +Generic parameter annotations should flow into local methods. + +## B Roslyn iterator rewrites expected behavior + +Specifically the C# compiler will rewrite entire method bodies. Iterators which return enumeration and use `yield return` will rewrite entire method body and move it into a separate class. This has similar problems as closures since it effectively behaves a lot like closure, but has additional challenges due to different syntax. + +### B1 - `RequiresUnreferencedCode` with iterator body + +```csharp +[RequiresUnreferencedCode ("--TestAfterIterator--")] +static IEnumerable TestAfterIterator () +{ + yield return 1; + MethodRequiresUnreferencedCode (); +} +``` + +The attribute should apply to the entire method body and thus suppress trim analysis warnings. Even if the body is spread by the compiler into different methods. + +### B2 - `UnconditionalSuppressMessage` with iterator body + +```csharp +[UnconditionalSuppressMessage ("IL2026", "")] +static IEnumerable TestBeforeIterator () +{ + MethodRequiresUnreferencedCode (); + yield return 1; +} +``` + +The attribute should apply to the entire method body and thus suppress trim analysis warnings. Even if the body is spread by the compiler into different methods. + +### B3 - Data flow annotations in iterator body + +```csharp +static IEnumerable TestParameter ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) +{ + type.GetMethod ("BeforeIteratorMethod"); + yield return 1; + type.GetMethod ("AfterIteratorMethod"); +} +``` + +The data flow annotation from method parameter should flow through the entire body. + +### B4 - Intrinsic data flow in iterator body + +```csharp +static IEnumerable TestLocalVariable () +{ + Type type = typeof (TestType); + type.GetMethod ("BeforeIteratorMethod"); + yield return 1; + type.GetMethod ("AfterIteratorMethod"); +} +``` + +The intrinsic annotations should flow through the entire body. + +### B5 - Generic parameter data flow in iterator body + +```csharp +static IEnumerable TestGenericParameter<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () +{ + typeof (T).GetMethod ("BeforeIteratorMethod"); + yield return 1; + typeof (T).GetMethod ("AfterIteratorMethod"); +} +``` + +Generic parameter annotations should flow through the entire body. + +## C Roslyn async rewrites expected behavior + +Similarly to iterators, C# compiler also rewrites method bodies which use `async`/`await`. This has similar problems as closures since it effectively behaves a lot like closure, but has additional challenges due to different syntax. + +### C1 - `RequiresUnreferencedCode` with async body + +```csharp +[RequiresUnreferencedCode ("--TestAfterAwait--")] +static async void TestAfterAwait () +{ + await AsyncMethod (); + MethodRequiresUnreferencedCode (); +} +``` + +The attribute should apply to the entire method body and thus suppress trim analysis warnings. Even if the body is spread by the compiler into different methods. Very similar to B1. + +### C2 - `UnconditionalSuppressMessage` with iterator body + +```csharp +[UnconditionalSuppressMessage("IL2026", "")] +static async void TestBeforeAwait() +{ + MethodRequiresUnreferencedCode (); + await AsyncMethod (); +} +``` + +The attribute should apply to the entire method body and thus suppress trim analysis warnings. Even if the body is spread by the compiler into different methods. Very similar to B2. + +### C3 = Data flow annotations in async body + +```csharp +static async void TestParameter ([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] Type type) +{ + type.GetMethod ("BeforeAsyncMethod"); + await AsyncMethod (); + type.GetMethod ("AfterAsyncMethod"); +} +``` + +The data flow annotation from method parameter should flow through the entire body. Very similar to B3. + +### C4 - Intrinsic data flow in async body + +```csharp +static async void TestLocalVariable () +{ + Type type = typeof (TestClass); + type.GetMethod ("BeforeAsyncMethod"); + await AsyncMethod (); + type.GetMethod ("AfterAsyncMethod"); +} +``` + +The intrinsic annotations should flow through the entire body. Very similar to B4. + +### C5 - Generic parameter data flow in async body + +```csharp +static async void TestGenericParameter<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> () +{ + typeof (T).GetMethod ("BeforeIteratorMethod"); + await AsyncMethod (); + typeof (T).GetMethod ("AfterIteratorMethod"); +} +``` + +Generic parameter annotations should flow through the entire body. Very similar to B5. + +## D Roslyn closure class and method naming behavior + +When the Roslyn compiler generates a closure and moves the code in the method into a method on the closure trimming tools should have enough information to provide correct information about the source of a warning (if there's any). + +### D1 - Lambda methods + +```csharp +static void TestInLambda () +{ + Action a = () => MethodRequiresUnreferencedCode (); // Warning should point to this line +} +``` + +Given symbols this should produce a warning pointing to the source file, but should not include the method name which looks like `<>c.b__1_0()`. This should produce a warning which looks like: + +```console +Source.cs(3,22): Trim analysis warning IL2026: Using method 'MethodRequiresUnreferencedCode()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. +``` + +Similarly for all other warnings originating from trim analysis. + +**Open question Q2a:** Should we try to display a better name for lambdas if there are no symbols available for the assembly? + +### D2 - Local functions + +```csharp +static void TestInLocalFunction () +{ + LocalFunction (); + + void LocalFunction() + { + MethodRequiresUnreferencedCode (); // Warning should point to this line + } +} +``` + +Just like with lambdas, if there are symbols the warning should point to the source location and not include the compiler generated method name which in this case looks something like `Type.g__LocalFunction|2_0()`. The produced warning should look like this: + +```console +Source.cs(7,9): Using method 'MethodRequiresUnreferencedCode()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. +``` + +**Open question Q2b:** Should we try to display a better name for local functions if there are no symbols available for the assembly? + +### D3 - Iterators + +```csharp +static IEnumerable TestIterator () +{ + MethodRequiresUnreferencedCode (); // Warning should point to this line + yield return 1; +} +``` + +In this case as well, the trimmer should report the warning pointing to the source and avoid including the compiler generated name which looks like `d__3.MoveNext()`. The warning should look like this: + +```console +Source.cs(3,5): Using method 'MethodRequiresUnreferencedCode()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. +``` + +**Open question Q2c:** Should we try to display a better name for iterator methods if there are no symbols available for the assembly? + +### D4 - Async + +```csharp +static async void TestAsync () +{ + MethodRequiresUnreferencedCode (); + await AsyncMethod (); +} +``` + +Just like in the above cases the warning should point to source and not include the compiler generated name, which looks like `d__4.MoveNext()`. The warning should look like: + +```console +Source.cs(3,5): Using method 'MethodRequiresUnreferencedCode()' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. +``` + +**Open question Q2d:** Should we try to display a better name for async methods if there are no symbols available for the assembly? + +## E Reporting user visible names from data flow analysis + +Data flow analysis in the trimmer reports warnings which point to sources of data values, for example method parameters, fields and so on. With closure classes generated by the compiler the warning might be in a spot where the immediate value is read from a field on the closure class, but that field is compiler generated. Ideally the warning would point to the actual source of the value for that field which is visible in user code. + +### E1 - Lambda methods + +```csharp +static void TestWarningInLambda (Type typeParameter) +{ + Action a = () => typeParameter.GetMethod ("InLambdaMethod"); +} +``` + +The above should produce warning blaming `typeParameter` as the source of the unannotated value. + +### E2 - Local functions + +```csharp +static void TestWarningInLocalFunction () +{ + Action a = () => typeof(TInput).GetMethod ("InLambdaMethod"); +} +``` + +In this case the warning should blame `TInput` as the unannotated value. + +### E3 - Iterators + +```csharp +static IEnumerable TestWarning(Type typeParameter) +{ + typeParameter.GetMethod ("InIteratorMethod"); + yield return 1; +} +``` + +This should produce warning blaming `typeParameter`. + +### E4 - Async + +```csharp +static async void TestWarning() +{ + typeof (TInput).GetMethod ("InAsyncMethod"); + await AsyncMethod (); +} +``` + +And this one should blame `TInput`. + +## Recommended solution + +The solution needs to solve two problems: + +* How to propagate warning suppression and `RequiresUnreferencedCode` suppression from +the user method to all of the compiler generated methods/types which are called by that method. +This is called "suppression propagation" below. +* How to implement data flow analysis across the user method's body and all of the compiler generated +methods, types and fields. This is called "data flow analysis" below. + +In both cases the first thing the trimmer needs to figure out is for a given user method +what are all of the compiler generated items which were used to implement that method +in the IL. This can include: + +* New types - for example closure types +* New methods - for example methods on the closure types, or methods on the parent type for local functions +* New fields - fields on the closure types +* New generic parameters - closure types and methods may be generic if the user method is generic + +To correctly handle warning suppression, the trimmer needs to apply the same warning suppressions +on warnings generated due to all of the compiler generated items as if those were coming +directly from the user method's body. + +To correctly handle data flow analysis, the trimmer needs to be able to track values across all of the +compiler generated items as if they implement a single unit. This almost inevitable leads to +cross method data flow analysis. Since that is a very expensive thing to do, being able to confine +it to only the compiler generated code for a given user method is almost necessary. On top of that +the trimmer needs to be able to track values as they traverse local variables, method parameters +and fields on the closure types. + +### Long term solution + +Detecting which compiler generated items are used by any given user method is currently relatively tricky. +There's no definitive marker in the IL which would let the trimmer confidently determine this information. +Good long term solution will need the compilers to produce some kind of marker in the IL so that +static analysis tools can reliably detect all of the compiler generated items. + +This ask can be described as: +For a given user method, ability to determine all of the items (methods, fields, types, IL code) which were +used by the compiler to generate the functionality of the method into an IL assembly. + +This should be things which are directly generated from the user's code. It should NOT include compiler +helpers and other infrastructure which may be needed but is not directly attributable to a user code. + +This should be enough to implement solutions for both suppression propagation and data flow analysis. + +### Possible short term solution + +#### Heuristic based solution + +Without compiler provided markers, there's no existing way to 100% reliably implement the required +functionality in the trimmer. That said, it should be possible to implement a reasonably good +approximation. This approximation will necessarily make assumptions about the compilers used +to produce the analyzed code. So for the purposes of a short term solution, Roslyn CSharp compiler +should be treated as first priority (since it's by far the most common compiler to produce analyzed IL). +Second in row should be the FSharp compiler. + +It is also much simpler to implement suppression propagation, so that should be done first. + +The general idea how to detect compiler generated code for a given user method: + +* Ability to detect compiler generated code. Can be done by detecting identifiers which are invalid +in a given language. For CSharp, the compiler uses `<` and `>` characters in the identifiers +of a compiler generated items. In FSharp this role is served by the `@` character. +* Any compiler generated item (as detected per above) referenced from a user method +will be considered to belong to that user method. + +Pros: + +* Can handle all cases for warning suppressions - async, iterator, lambdas and local functions +* Can work on not just Roslyn generated IL + +Cons: + +* Heuristic - it may get it wrong in which case the trimmer may report less warnings than it should +* Complex implementation mainly due to issues with reflection accessed code. For example if the closure class +is marked only due to reflection access (for example `DynamicallyAccessedMemberType.All`) and the actual +user method is not marked at all then there's no good way to determine the user method to figure out suppression +context. Again can lead to reporting less warnings. + +#### Deterministic partial solution based on attributes + +For state machines the Roslyn compiler currently generates `IteratorStateMachineAttribute`, `AsyncStateMachineAttribute` and `AsyncIteratorStateMachineAttribute` attributes onto the "user method" and the attribute points to the generated state machine type. + +This can be used to completely deterministically figure out the mapping between state machine code and user methods. + +Pros: + +* Deterministic and reliable - as long as Roslyn generates these attributes (which is considered internal behavior) +* Relatively simple implementation in the trimmer for suppressions + +Cons: + +* Partial solution - only works on async and iterator methods, doesn't work on lambdas and local functions + +The recommended solution is to use the deterministic approach via attributes. This solution doesn't have the reflection access problem (which is very problematic). +The fact that it doesn't solve lambdas and local functions has a reasonable workaround. Both can be annotated +manually by the developer by adding attributes to them. This introduces a discrepancy between analyzer +and trimmer (as analyzer would not have this problem), but it's acceptable behavior for .NET 6. \ No newline at end of file -- cgit v1.2.3 From da412ca2035910a8d58f97f0370e2e9a5a3b9805 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Mon, 15 Nov 2021 18:54:02 +0100 Subject: Add a test for https://github.com/dotnet/linker/issues/2358 (#2369) Currently this causes a crash in the linker due to null location scope. --- ...teRemovalAndPreserveAssembly_Lib.Descriptor.xml | 4 ++ ...inkerAttributeRemovalAndPreserveAssembly_Lib.cs | 10 +++++ ...teRemovalAndPreserveAssembly.LinkAttributes.xml | 8 ++++ .../LinkerAttributeRemovalAndPreserveAssembly.cs | 48 ++++++++++++++++++++++ 4 files changed, 70 insertions(+) create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.Descriptor.xml create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.cs create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemovalAndPreserveAssembly.LinkAttributes.xml create mode 100644 test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemovalAndPreserveAssembly.cs diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.Descriptor.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.Descriptor.xml new file mode 100644 index 000000000..4fa3f75f9 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.Descriptor.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.cs new file mode 100644 index 000000000..c61f1562a --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Mono.Linker.Tests.Cases.LinkAttributes.Dependencies +{ + public static class Used + { + public static void Use () { } + } +} diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemovalAndPreserveAssembly.LinkAttributes.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemovalAndPreserveAssembly.LinkAttributes.xml new file mode 100644 index 000000000..b28401f8a --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemovalAndPreserveAssembly.LinkAttributes.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemovalAndPreserveAssembly.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemovalAndPreserveAssembly.cs new file mode 100644 index 000000000..1e0e34a17 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkerAttributeRemovalAndPreserveAssembly.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.LinkAttributes.Dependencies; + +namespace Mono.Linker.Tests.Cases.LinkAttributes +{ + [IgnoreDescriptors (false)] + + // The test verifies that removed attributes which are later on kept due to descriptors correctly warn. + // The setup is: + // - test assembly with the AttributeToRemoveAttribute type + // - link attributes.xml which marks the attribute for removal (applied early, in this case via command line, but could be a embedded in the test assembly) + // - the attribute is used by the test assembly + // - another assembly lib.dll is added and is referenced (after the attribute is used/marked) + // - This new assembly has a descriptor which marks the entire test assembly (note that it marks the TEST assembly) + // - This marking causes the warning, as it's an explicit request to keep the attribute which was supposed to be removed + + [SetupLinkAttributesFile ("LinkerAttributeRemovalAndPreserveAssembly.LinkAttributes.xml")] + + [SetupCompileBefore ( + "lib.dll", + new[] { "Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.cs" })] + // https://github.com/dotnet/linker/issues/2358 - adding the descriptor currently causes nullref in the linker + // resources: new object[] { new string[] { "Dependencies/LinkerAttributeRemovalAndPreserveAssembly_Lib.Descriptor.xml", "ILLink.Descriptors.xml" } })] + + [ExpectedNoWarnings] + + class LinkerAttributeRemovalAndPreserveAssembly + { + public static void Main () + { + TestAttributeRemoval (); + } + + [AttributeToRemoveAttribute] + [Kept] + static void TestAttributeRemoval () + { + Used.Use (); + } + } + + public class AttributeToRemoveAttribute : Attribute { } +} \ No newline at end of file -- cgit v1.2.3 From c90ed0aee46fb24873d95ebaea80a2d11b29a957 Mon Sep 17 00:00:00 2001 From: Vitek Karas Date: Mon, 15 Nov 2021 20:14:29 +0100 Subject: Add a custom flag to disable marking of copy assemblies (#2370) Enabled by `--custom-data DisableMarkingOfCopyAssemblies=true` on the command line. Assumes that ALL assemblies on the input are in "copy" action (it doesn't validate this fact). It disables marking basically fully - linker will go over all assemblies, and process them in "copy" mode (copy the original file over) and will call all the custom steps and so on, but it will do no marking (or very little, depends on descriptors and such which this doesn't disable). This is intentionally non-discoverable feature, to be used only by the mono AOT toolchain. --- src/linker/Linker.Steps/MarkStep.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 524c9195e..4921299ef 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -1387,7 +1387,9 @@ namespace Mono.Linker.Steps MarkExportedTypesTarget.ProcessAssembly (assembly, Context); if (ProcessReferencesStep.IsFullyPreservedAction (Context.Annotations.GetAction (assembly))) { - MarkEntireAssembly (assembly); + if (!Context.TryGetCustomData ("DisableMarkingOfCopyAssemblies", out string? disableMarkingOfCopyAssembliesValue) || + disableMarkingOfCopyAssembliesValue != "true") + MarkEntireAssembly (assembly); return; } -- cgit v1.2.3 From 53c5d48842fe53e05272d163c7f49e54ddcb4b37 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 16 Nov 2021 09:05:54 -0800 Subject: Update to 6.0 SDK and use included dotnet-format (#2371) --- .config/dotnet-tools.json | 12 ---- .editorconfig | 5 ++ global.json | 2 +- lint.cmd | 3 +- lint.sh | 3 +- src/ILLink.Shared/DiagnosticString.cs | 4 +- src/linker/Linker.Steps/BaseSubStep.cs | 1 - .../Linker.Steps/DiscoverCustomOperatorsHandler.cs | 1 - .../Linker.Steps/DiscoverSerializationHandler.cs | 4 -- src/linker/Linker.Steps/MarkSubStepsDispatcher.cs | 1 - src/linker/Linker.Steps/OutputStep.cs | 1 - src/linker/Linker.Steps/SubStepsDispatcher.cs | 1 - src/linker/Linker/AttributeInfo.cs | 1 - src/linker/Linker/EmbeddedXmlInfo.cs | 2 - src/linker/Linker/MemberReferenceExtensions.cs | 3 +- src/linker/Linker/MethodDefinitionExtensions.cs | 3 +- .../CompilationExtensions.cs | 3 - .../RequiresAssemblyFilesAnalyzerTests.cs | 2 - .../RequiresUnreferencedCodeAnalyzerTests.cs | 1 - test/ILLink.RoslynAnalyzer.Tests/TestCase.cs | 3 - .../TestCaseCompilation.cs | 1 - test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs | 3 +- test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs | 4 +- .../UnconditionalSuppressMessageCodeFixTests.cs | 4 -- .../Verifiers/CSharpAnalyzerVerifier`1.cs | 2 - .../Verifiers/CSharpCodeFixVerifier`2.cs | 1 - .../CreateRuntimeRootDescriptorFileTests.cs | 10 ++- test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs | 4 +- test/ILLink.Tasks.Tests/Mock.cs | 4 +- test/Mono.Linker.Tests/Extensions/NiceIO.cs | 6 +- .../Mono.Linker.Tests/TestCases/IndividualTests.cs | 6 +- .../TestCasesRunner/PeVerifier.cs | 1 - .../TestCasesRunner/ResultChecker.cs | 18 +++--- .../TestCasesRunner/TestCaseCompiler.cs | 6 +- .../TestCasesRunner/TestCaseMetadataProvider.cs | 2 +- .../TestReflectionPatternRecorder.cs | 2 +- .../TestCasesRunner/TestRunner.cs | 2 +- test/Mono.Linker.Tests/Tests/CecilVersionCheck.cs | 1 - .../Tests/DocumentationSignatureParserTests.cs | 73 +++++++++++----------- .../Mono.Linker.Tests/Tests/GetDisplayNameTests.cs | 32 +++++----- .../Tests/ParseResponseFileLinesTests.cs | 2 +- 41 files changed, 95 insertions(+), 145 deletions(-) delete mode 100644 .config/dotnet-tools.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json deleted file mode 100644 index 5709726d3..000000000 --- a/.config/dotnet-tools.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": 1, - "isRoot": true, - "tools": { - "dotnet-format": { - "version": "5.0.211103", - "commands": [ - "dotnet-format" - ] - } - } -} diff --git a/.editorconfig b/.editorconfig index ef8a70bec..79b5a9322 100644 --- a/.editorconfig +++ b/.editorconfig @@ -135,6 +135,11 @@ dotnet_diagnostic.CA2201.severity = none # Analyzer crashes with https://github.com/dotnet/roslyn-analyzers/issues/5450 dotnet_diagnostic.CA2252.severity = none +[src/linker/ref/**/*.cs] + +# CA1822: Mark members as static +dotnet_diagnostic.CA1822.severity = none + [external**] dotnet_analyzer_diagnostic.severity = none generated_code = true diff --git a/global.json b/global.json index 868829aa0..80620c636 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "tools": { - "dotnet": "6.0.100-rc.1.21430.12" + "dotnet": "6.0.100" }, "msbuild-sdks": { "Microsoft.DotNet.Arcade.Sdk": "7.0.0-beta.21559.3", diff --git a/lint.cmd b/lint.cmd index 7e17179ce..f4c4466a9 100644 --- a/lint.cmd +++ b/lint.cmd @@ -1,3 +1,2 @@ @echo off -powershell -ExecutionPolicy ByPass -NoProfile -command "Set-Location %~dp0; & """%~dp0eng\dotnet.ps1""" ""tool restore""" -powershell -ExecutionPolicy ByPass -NoProfile -command "Set-Location %~dp0; & """%~dp0eng\dotnet.ps1""" ""tool run dotnet-format -- illink.sln --fix-whitespace --exclude src/analyzer src/tuner external %*""" +powershell -ExecutionPolicy ByPass -NoProfile -command "Set-Location %~dp0; & """%~dp0eng\dotnet.ps1""" ""format illink.sln --exclude src/analyzer src/tuner external %*""" diff --git a/lint.sh b/lint.sh index 0e3815471..570584c04 100755 --- a/lint.sh +++ b/lint.sh @@ -13,5 +13,4 @@ while [[ -h $source ]]; do done scriptroot="$( cd -P "$( dirname "$source" )" && pwd )" -"$scriptroot/eng/dotnet.sh" tool restore -"$scriptroot/eng/dotnet.sh" tool run dotnet-format -- illink.sln --fix-whitespace --exclude src/analyzer src/tuner external $@ +"$scriptroot/eng/dotnet.sh" format illink.sln --exclude src/analyzer src/tuner external $@ diff --git a/src/ILLink.Shared/DiagnosticString.cs b/src/ILLink.Shared/DiagnosticString.cs index e01cc9b5b..3464ef0a2 100644 --- a/src/ILLink.Shared/DiagnosticString.cs +++ b/src/ILLink.Shared/DiagnosticString.cs @@ -1,6 +1,4 @@ -using System; - -namespace ILLink.Shared +namespace ILLink.Shared { public readonly struct DiagnosticString { diff --git a/src/linker/Linker.Steps/BaseSubStep.cs b/src/linker/Linker.Steps/BaseSubStep.cs index 4826c7014..af991fda9 100644 --- a/src/linker/Linker.Steps/BaseSubStep.cs +++ b/src/linker/Linker.Steps/BaseSubStep.cs @@ -1,7 +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; using System.Diagnostics; using Mono.Cecil; diff --git a/src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs b/src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs index 8497a61ea..64561aa6b 100644 --- a/src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs +++ b/src/linker/Linker.Steps/DiscoverCustomOperatorsHandler.cs @@ -1,7 +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; using System.Collections.Generic; using System.Diagnostics; using Mono.Cecil; diff --git a/src/linker/Linker.Steps/DiscoverSerializationHandler.cs b/src/linker/Linker.Steps/DiscoverSerializationHandler.cs index 0b30d6ea4..6ac6da881 100644 --- a/src/linker/Linker.Steps/DiscoverSerializationHandler.cs +++ b/src/linker/Linker.Steps/DiscoverSerializationHandler.cs @@ -2,12 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using Mono.Cecil; -using Mono.Linker.Dataflow; -using Mono.Linker.Steps; namespace Mono.Linker.Steps { diff --git a/src/linker/Linker.Steps/MarkSubStepsDispatcher.cs b/src/linker/Linker.Steps/MarkSubStepsDispatcher.cs index f97004fd0..8f15014f3 100644 --- a/src/linker/Linker.Steps/MarkSubStepsDispatcher.cs +++ b/src/linker/Linker.Steps/MarkSubStepsDispatcher.cs @@ -1,7 +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; using System.Collections.Generic; using System.Diagnostics; diff --git a/src/linker/Linker.Steps/OutputStep.cs b/src/linker/Linker.Steps/OutputStep.cs index b28d52c8d..2fd32880d 100644 --- a/src/linker/Linker.Steps/OutputStep.cs +++ b/src/linker/Linker.Steps/OutputStep.cs @@ -32,7 +32,6 @@ using System.IO; using System.Linq; using System.Runtime.Serialization.Json; using Mono.Cecil; -using Mono.Cecil.Cil; namespace Mono.Linker.Steps { diff --git a/src/linker/Linker.Steps/SubStepsDispatcher.cs b/src/linker/Linker.Steps/SubStepsDispatcher.cs index 3ed5a6e1c..338bbda8b 100644 --- a/src/linker/Linker.Steps/SubStepsDispatcher.cs +++ b/src/linker/Linker.Steps/SubStepsDispatcher.cs @@ -1,7 +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; using System.Collections.Generic; using System.Diagnostics; diff --git a/src/linker/Linker/AttributeInfo.cs b/src/linker/Linker/AttributeInfo.cs index 23b31c433..ea430b2de 100644 --- a/src/linker/Linker/AttributeInfo.cs +++ b/src/linker/Linker/AttributeInfo.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using Mono.Cecil; namespace Mono.Linker diff --git a/src/linker/Linker/EmbeddedXmlInfo.cs b/src/linker/Linker/EmbeddedXmlInfo.cs index 14871394b..815bbb8d2 100644 --- a/src/linker/Linker/EmbeddedXmlInfo.cs +++ b/src/linker/Linker/EmbeddedXmlInfo.cs @@ -2,10 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.IO; using System.Linq; using System.Xml; -using System.Xml.XPath; using Mono.Cecil; using Mono.Linker.Steps; diff --git a/src/linker/Linker/MemberReferenceExtensions.cs b/src/linker/Linker/MemberReferenceExtensions.cs index b24364aaa..14278fdef 100644 --- a/src/linker/Linker/MemberReferenceExtensions.cs +++ b/src/linker/Linker/MemberReferenceExtensions.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics; +using System.Diagnostics; using System.Text; using Mono.Cecil; diff --git a/src/linker/Linker/MethodDefinitionExtensions.cs b/src/linker/Linker/MethodDefinitionExtensions.cs index 165b75138..d8b370422 100644 --- a/src/linker/Linker/MethodDefinitionExtensions.cs +++ b/src/linker/Linker/MethodDefinitionExtensions.cs @@ -1,5 +1,4 @@ -using System; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using Mono.Cecil; namespace Mono.Linker diff --git a/test/ILLink.RoslynAnalyzer.Tests/CompilationExtensions.cs b/test/ILLink.RoslynAnalyzer.Tests/CompilationExtensions.cs index 550a7e8e4..64b3eecbb 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/CompilationExtensions.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/CompilationExtensions.cs @@ -1,14 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Linq; -using System.Text; using System.Threading; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Emit; using Xunit; diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs index 7e27f2782..386279369 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresAssemblyFilesAnalyzerTests.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using ILLink.Shared; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Xunit; diff --git a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs index b54b65f8e..8a834dd0b 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/RequiresUnreferencedCodeAnalyzerTests.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using ILLink.RoslynAnalyzer; using ILLink.Shared; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Testing; diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs index 0f35b908a..055da0792 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCase.cs @@ -1,12 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; -using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs index 4c3db2687..9873c3ac3 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseCompilation.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs index 44881437d..44cdea4a7 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestCaseUtils.cs @@ -12,7 +12,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Xunit; @@ -31,7 +30,7 @@ namespace ILLink.RoslynAnalyzer.Tests .WithNuGetConfigFilePath (Path.Combine (TestCaseUtils.GetRepoRoot (), "NuGet.config")); private static ImmutableArray s_net6Refs; - public async static ValueTask> GetNet6References () + public static async ValueTask> GetNet6References () { if (s_net6Refs.IsDefault) { var refs = await Net6PreviewAssemblies.ResolveAsync (null, default); diff --git a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs index 5da895fce..9297b8fc4 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/TestChecker.cs @@ -63,7 +63,7 @@ namespace ILLink.RoslynAnalyzer.Tests MemberSyntax = memberSyntax; } - bool IsExpectedDiagnostic (AttributeSyntax attribute) + static bool IsExpectedDiagnostic (AttributeSyntax attribute) { switch (attribute.Name.ToString ()) { case "ExpectedWarning": @@ -218,7 +218,7 @@ namespace ILLink.RoslynAnalyzer.Tests } } - missingDiagnosticMessage = $"Could not find text:\n{text}\nIn diagnostics:\n{(string.Join (Environment.NewLine, DiagnosticMessages))}"; + missingDiagnosticMessage = $"Could not find text:\n{text}\nIn diagnostics:\n{string.Join (Environment.NewLine, DiagnosticMessages)}"; return false; } diff --git a/test/ILLink.RoslynAnalyzer.Tests/UnconditionalSuppressMessageCodeFixTests.cs b/test/ILLink.RoslynAnalyzer.Tests/UnconditionalSuppressMessageCodeFixTests.cs index 26a273aff..3e308104f 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/UnconditionalSuppressMessageCodeFixTests.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/UnconditionalSuppressMessageCodeFixTests.cs @@ -2,12 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; -using ILLink.CodeFix; using ILLink.Shared; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis.Text; using Xunit; diff --git a/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs b/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs index 5afc179b8..3d26b627d 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; -using System.IO; using System.Linq; using System.Reflection; using System.Text; @@ -10,7 +9,6 @@ using System.Threading; using System.Threading.Tasks; using ILLink.Shared; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; diff --git a/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpCodeFixVerifier`2.cs b/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpCodeFixVerifier`2.cs index 9fc04e38f..fcef098ea 100644 --- a/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpCodeFixVerifier`2.cs +++ b/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpCodeFixVerifier`2.cs @@ -6,7 +6,6 @@ using System.Threading; using System.Threading.Tasks; using ILLink.Shared; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeFixes; using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Testing; diff --git a/test/ILLink.Tasks.Tests/CreateRuntimeRootDescriptorFileTests.cs b/test/ILLink.Tasks.Tests/CreateRuntimeRootDescriptorFileTests.cs index 19d5e6c86..db3bf83f6 100644 --- a/test/ILLink.Tasks.Tests/CreateRuntimeRootDescriptorFileTests.cs +++ b/test/ILLink.Tasks.Tests/CreateRuntimeRootDescriptorFileTests.cs @@ -3,9 +3,7 @@ using System; using System.IO; -using System.Linq; using System.Xml.Linq; -using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using Xunit; @@ -47,7 +45,7 @@ namespace ILLink.Tasks.Tests File.WriteAllText ("namespace.h", "#define g_TestNS \"TestNS\"" + Environment.NewLine); - File.WriteAllLines ("cortypeinfo.h", new string[] { }); + File.WriteAllLines ("cortypeinfo.h", Array.Empty ()); File.WriteAllLines ("rexcep.h", new string[] { "DEFINE_EXCEPTION(g_TestNS, TestAlwaysException, false, C)", @@ -62,7 +60,7 @@ namespace ILLink.Tasks.Tests XElement existingAssembly = new XElement ("assembly", new XAttribute ("fullname", "testassembly"), new XComment ("Existing content")); XElement existingContent = new XElement ("linker", existingAssembly); - (new XDocument (existingContent)).Save ("Test.ILLink.Descriptors.Combined.xml"); + new XDocument (existingContent).Save ("Test.ILLink.Descriptors.Combined.xml"); var task = new CreateRuntimeRootILLinkDescriptorFile () { NamespaceFilePath = new TaskItem ("namespace.h"), @@ -142,7 +140,7 @@ namespace ILLink.Tasks.Tests File.WriteAllText ("namespace.h", "#define g_TestNS \"TestNS\"" + Environment.NewLine); - File.WriteAllLines ("cortypeinfo.h", new string[] { }); + File.WriteAllLines ("cortypeinfo.h", Array.Empty ()); File.WriteAllLines ("rexcep.h", new string[] { "DEFINE_EXCEPTION(g_TestNS, TestAlwaysException, false, C)", @@ -157,7 +155,7 @@ namespace ILLink.Tasks.Tests XElement existingAssembly = new XElement ("assembly", new XAttribute ("fullname", "testassembly"), new XComment ("Existing content")); XElement existingContent = new XElement ("linker", existingAssembly); - (new XDocument (existingContent)).Save ("Test.ILLink.Descriptors.Combined.xml"); + new XDocument (existingContent).Save ("Test.ILLink.Descriptors.Combined.xml"); var task = new CreateRuntimeRootILLinkDescriptorFile () { NamespaceFilePath = new TaskItem ("namespace.h"), diff --git a/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs b/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs index 216dec205..e6aef3617 100644 --- a/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs +++ b/test/ILLink.Tasks.Tests/ILLink.Tasks.Tests.cs @@ -369,7 +369,7 @@ namespace ILLink.Tasks.Tests using (var driver = task.CreateDriver ()) { var actualWarnAsError = driver.Context.WarnAsError; var actualGeneralWarnAsError = driver.Context.GeneralWarnAsError; - Assert.Equal (warnAsError.Count () + warnNotAsError.Count (), actualWarnAsError.Count); + Assert.Equal (warnAsError.Length + warnNotAsError.Length, actualWarnAsError.Count); Assert.Equal (treatWarningsAsErrors, actualGeneralWarnAsError); if (warnAsError.Length > 0) { foreach (var warningCode in warnAsError) @@ -753,7 +753,7 @@ namespace ILLink.Tasks.Tests public void TestErrorHandling () { var task = new MockTask () { - RootAssemblyNames = new ITaskItem[0] + RootAssemblyNames = Array.Empty () }; task.BuildEngine = new MockBuildEngine (); Assert.False (task.Execute ()); diff --git a/test/ILLink.Tasks.Tests/Mock.cs b/test/ILLink.Tasks.Tests/Mock.cs index dba28887b..2ea9e492c 100644 --- a/test/ILLink.Tasks.Tests/Mock.cs +++ b/test/ILLink.Tasks.Tests/Mock.cs @@ -21,8 +21,8 @@ namespace ILLink.Tasks.Tests public MockTask () { // Ensure that [Required] members are non-null - AssemblyPaths = new ITaskItem[0]; - RootAssemblyNames = new ITaskItem[0]; + AssemblyPaths = Array.Empty (); + RootAssemblyNames = Array.Empty (); ILLinkPath = Path.Combine (Path.GetDirectoryName (Assembly.GetExecutingAssembly ().Location), "illink.dll"); } diff --git a/test/Mono.Linker.Tests/Extensions/NiceIO.cs b/test/Mono.Linker.Tests/Extensions/NiceIO.cs index 8cbf9c5a5..5fbe8982c 100644 --- a/test/Mono.Linker.Tests/Extensions/NiceIO.cs +++ b/test/Mono.Linker.Tests/Extensions/NiceIO.cs @@ -51,7 +51,7 @@ namespace Mono.Linker.Tests.Extensions if (path == "/") { _isRelative = false; - _elements = new string[] { }; + _elements = Array.Empty (); } else { var split = path.Split ('/', '\\'); @@ -94,7 +94,7 @@ namespace Mono.Linker.Tests.Extensions return stack.Count > 0 && stack[stack.Count - 1] != ".."; } - private string ParseDriveLetter (string path, out string driveLetter) + private static string ParseDriveLetter (string path, out string driveLetter) { if (path.Length >= 2 && path[1] == ':') { driveLetter = path[0].ToString (); @@ -433,7 +433,7 @@ namespace Mono.Linker.Tests.Extensions ThrowIfRelative (); ThrowIfRoot (); EnsureParentDirectoryExists (); - File.WriteAllBytes (ToString (), new byte[0]); + File.WriteAllBytes (ToString (), Array.Empty ()); return this; } diff --git a/test/Mono.Linker.Tests/TestCases/IndividualTests.cs b/test/Mono.Linker.Tests/TestCases/IndividualTests.cs index a6fb77cad..ca7754f8e 100644 --- a/test/Mono.Linker.Tests/TestCases/IndividualTests.cs +++ b/test/Mono.Linker.Tests/TestCases/IndividualTests.cs @@ -19,7 +19,7 @@ namespace Mono.Linker.Tests.TestCases [TestFixture] public class IndividualTests { - private NPath TestsDirectory => TestDatabase.TestCasesRootDirectory.Parent.Combine ("Mono.Linker.Tests"); + private static NPath TestsDirectory => TestDatabase.TestCasesRootDirectory.Parent.Combine ("Mono.Linker.Tests"); [Test] public void CanSkipUnresolved () @@ -217,14 +217,14 @@ namespace Mono.Linker.Tests.TestCases Assert.That (secondOutputMvid, Is.EqualTo (firstOutputMvid)); } - protected Guid GetMvid (NPath assemblyPath) + protected static Guid GetMvid (NPath assemblyPath) { using (var assembly = AssemblyDefinition.ReadAssembly (assemblyPath)) { return assembly.MainModule.Mvid; } } - private TestCase CreateIndividualCase (Type testCaseType) + private static TestCase CreateIndividualCase (Type testCaseType) { return TestDatabase.CreateCollector ().CreateIndividualCase (testCaseType); } diff --git a/test/Mono.Linker.Tests/TestCasesRunner/PeVerifier.cs b/test/Mono.Linker.Tests/TestCasesRunner/PeVerifier.cs index f4d4b25df..3c9a222be 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/PeVerifier.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/PeVerifier.cs @@ -5,7 +5,6 @@ using System.Linq; using Mono.Cecil; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.Extensions; -using NUnit.Framework; namespace Mono.Linker.Tests.TestCasesRunner { diff --git a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index 949029edc..8915d13fb 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; using System.Text.RegularExpressions; using Mono.Cecil; using Mono.Cecil.Cil; @@ -395,7 +393,7 @@ namespace Mono.Linker.Tests.TestCasesRunner Assert.Fail ($"Invalid test assertion. No member named `{memberName}` exists on the original type `{originalType}`"); } - void VerifyCopyAssemblyIsKeptUnmodified (NPath outputDirectory, string assemblyName) + static void VerifyCopyAssemblyIsKeptUnmodified (NPath outputDirectory, string assemblyName) { string inputAssemblyPath = Path.Combine (Directory.GetParent (outputDirectory).ToString (), "input", assemblyName); string outputAssemblyPath = Path.Combine (outputDirectory, assemblyName); @@ -602,7 +600,7 @@ namespace Mono.Linker.Tests.TestCasesRunner { var assembly = ResolveLinkedAssembly (inAssemblyAttribute.ConstructorArguments[0].Value.ToString ()); var expectedReferenceNames = ((CustomAttributeArgument[]) inAssemblyAttribute.ConstructorArguments[1].Value).Select (attr => (string) attr.Value).ToList (); - for (int i = 0; i < expectedReferenceNames.Count (); i++) + for (int i = 0; i < expectedReferenceNames.Count; i++) if (expectedReferenceNames[i].EndsWith (".dll")) expectedReferenceNames[i] = expectedReferenceNames[i].Substring (0, expectedReferenceNames[i].LastIndexOf (".")); @@ -651,12 +649,13 @@ namespace Mono.Linker.Tests.TestCasesRunner } } - bool IsProducedByLinker (CustomAttribute attr) + static bool IsProducedByLinker (CustomAttribute attr) { var producedBy = attr.GetPropertyValue ("ProducedBy"); return producedBy is null ? true : ((ProducedBy) producedBy).HasFlag (ProducedBy.Trimmer); } - IEnumerable GetAttributeProviders (AssemblyDefinition assembly) + + static IEnumerable GetAttributeProviders (AssemblyDefinition assembly) { foreach (var testType in assembly.AllDefinedTypes ()) { foreach (var provider in testType.AllMembers ()) @@ -767,8 +766,7 @@ namespace Mono.Linker.Tests.TestCasesRunner return false; } } else if (isCompilerGeneratedCode == true) { - MethodDefinition methodDefinition = mc.Origin?.Provider as MethodDefinition; - if (methodDefinition != null) { + if (mc.Origin?.Provider is MethodDefinition methodDefinition) { if (attrProvider is not IMemberDefinition expectedMember) return false; @@ -946,7 +944,7 @@ namespace Mono.Linker.Tests.TestCasesRunner $"{expectedSourceMember}: Usage of {expectedReflectionMember} unrecognized " + $"{(expectedMessageParts == null ? string.Empty : "and message contains " + string.Join (" ", expectedMessageParts.Select (p => "'" + p + "'")))}"; - Assert.AreEqual (matchedMessages.Count (), matchedPatterns.Count (), + Assert.AreEqual (matchedMessages.Count, matchedPatterns.Count, $"Inconsistency between logged messages and recorded patterns.{Environment.NewLine}{expectedUnrecognizedPatternMessage}{Environment.NewLine}" + $"Matched messages: {Environment.NewLine}{string.Join (Environment.NewLine, matchedMessages.Select (mc => "\t" + mc.Text))}{Environment.NewLine}" + $"Matched unrecognized patterns: {Environment.NewLine}{string.Join (Environment.NewLine, matchedPatterns.Select (p => "\t" + RecognizedReflectionAccessPatternToString (p)))}{Environment.NewLine}"); @@ -1346,7 +1344,7 @@ namespace Mono.Linker.Tests.TestCasesRunner return attr.AttributeType.Resolve ()?.DerivesFrom (nameof (BaseInAssemblyAttribute)) ?? false; } - bool HasAttribute (ICustomAttributeProvider caProvider, string attributeName) + static bool HasAttribute (ICustomAttributeProvider caProvider, string attributeName) { if (caProvider is AssemblyDefinition assembly && assembly.EntryPoint != null) return assembly.EntryPoint.DeclaringType.CustomAttributes diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs index 5d6c8c35a..2607e356e 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseCompiler.cs @@ -36,7 +36,7 @@ namespace Mono.Linker.Tests.TestCasesRunner public NPath CompileTestIn (NPath outputDirectory, string outputName, IEnumerable sourceFiles, string[] commonReferences, string[] mainAssemblyReferences, IEnumerable defines, NPath[] resources, string[] additionalArguments) { var originalCommonReferences = commonReferences.Select (r => r.ToNPath ()).ToArray (); - var originalDefines = defines?.ToArray () ?? new string[0]; + var originalDefines = defines?.ToArray () ?? Array.Empty (); Prepare (outputDirectory); @@ -89,8 +89,8 @@ namespace Mono.Linker.Tests.TestCasesRunner protected virtual CompilerOptions CreateOptionsForSupportingAssembly (SetupCompileInfo setupCompileInfo, NPath outputDirectory, NPath[] sourceFiles, NPath[] references, string[] defines, NPath[] resources) { - var allDefines = defines.Concat (setupCompileInfo.Defines ?? new string[0]).ToArray (); - var allReferences = references.Concat (setupCompileInfo.References?.Select (p => MakeSupportingAssemblyReferencePathAbsolute (outputDirectory, p)) ?? new NPath[0]).ToArray (); + var allDefines = defines.Concat (setupCompileInfo.Defines ?? Array.Empty ()).ToArray (); + var allReferences = references.Concat (setupCompileInfo.References?.Select (p => MakeSupportingAssemblyReferencePathAbsolute (outputDirectory, p)) ?? Array.Empty ()).ToArray (); string[] additionalArguments = string.IsNullOrEmpty (setupCompileInfo.AdditionalArguments) ? null : new[] { setupCompileInfo.AdditionalArguments }; return new CompilerOptions { OutputPath = outputDirectory.Combine (setupCompileInfo.OutputName), diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadataProvider.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadataProvider.cs index 404ecbf0f..fdcde52f7 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadataProvider.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadataProvider.cs @@ -69,7 +69,7 @@ namespace Mono.Linker.Tests.TestCasesRunner if (pos != -1) { string custom_assembly_path = values[0].Substring (pos + 1); if (!Path.IsPathRooted (custom_assembly_path)) - values[0] = values[0].Substring (0, pos + 1) + Path.Combine (inputPath, custom_assembly_path); + values[0] = string.Concat (values[0].AsSpan (0, pos + 1), Path.Combine (inputPath, custom_assembly_path)); } break; case "-a": diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestReflectionPatternRecorder.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestReflectionPatternRecorder.cs index d4b70f1f7..7143952ed 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestReflectionPatternRecorder.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestReflectionPatternRecorder.cs @@ -6,7 +6,7 @@ namespace Mono.Linker.Tests.TestCasesRunner { public class TestReflectionPatternRecorder : IReflectionPatternRecorder { - public IReflectionPatternRecorder PreviousRecorder = null; + public IReflectionPatternRecorder PreviousRecorder; public struct ReflectionAccessPattern { diff --git a/test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs b/test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs index f6ce178d0..e9ead9713 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs @@ -145,7 +145,7 @@ namespace Mono.Linker.Tests.TestCasesRunner return customizations; } - private T GetResultOfTaskThatMakesNUnitAssertions (Task task) + private static T GetResultOfTaskThatMakesNUnitAssertions (Task task) { try { return task.Result; diff --git a/test/Mono.Linker.Tests/Tests/CecilVersionCheck.cs b/test/Mono.Linker.Tests/Tests/CecilVersionCheck.cs index 78fbbbb81..ca7e43d84 100644 --- a/test/Mono.Linker.Tests/Tests/CecilVersionCheck.cs +++ b/test/Mono.Linker.Tests/Tests/CecilVersionCheck.cs @@ -1,4 +1,3 @@ -using System; using System.Linq; using System.Reflection; using NUnit.Framework; diff --git a/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs b/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs index 4ea98ba18..19864eb37 100644 --- a/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs +++ b/test/Mono.Linker.Tests/Tests/DocumentationSignatureParserTests.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Text; using Mono.Cecil; -using Mono.Linker; using Mono.Linker.Tests.Cases.Expectations.Assertions; using Mono.Linker.Tests.TestCasesRunner; using NUnit.Framework; @@ -103,32 +102,32 @@ namespace Mono.Linker.Tests [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32[])")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32[])")] - public void M (int[] a) + public static void M (int[] a) { } [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32,System.Int32,System.Int32)~System.Int32")] - public int M (int a, int b, int c) + public static int M (int a, int b, int c) { return 0; } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MRef(System.Int32@)")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MRef(System.Int32@)")] - public void MRef (ref int a) + public static void MRef (ref int a) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MOut(System.Int32@)")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MOut(System.Int32@)")] - public void MOut (out int a) + public static void MOut (out int a) { a = 5; } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MIn(System.Int32@)")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MIn(System.Int32@)")] - public void MIn (in int a) + public static void MIn (in int a) { } @@ -137,7 +136,7 @@ namespace Mono.Linker.Tests [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MRefReturn")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MRefReturn")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.MRefReturn~System.Int32@")] - public ref int MRefReturn () + public static ref int MRefReturn () { return ref i; } @@ -145,63 +144,63 @@ namespace Mono.Linker.Tests [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M")] [ExpectResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M")] // binds to both. [ExpectResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M()")] // binds to both. - public void M () + public static void M () { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M()")] [ExpectResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M")] [ExpectResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M()")] - public void M (__arglist) + public static void M (__arglist) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32[][])")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32[][])")] - public void M (int[][] a) + public static void M (int[][] a) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32[][0:,0:,0:])")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32[][0:,0:,0:])")] - public void M (int[,,][] a) + public static void M (int[,,][] a) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32[0:,0:])")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32[0:,0:])")] - public void M (int[,] a) + public static void M (int[,] a) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Object)")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Object)")] - public void M (dynamic d) + public static void M (dynamic d) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32*)")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32*)")] - public unsafe void M (int* a) + public static unsafe void M (int* a) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M``1(Mono.Linker.Tests.DocumentationSignatureParserTests.S{Mono.Linker.Tests.DocumentationSignatureParserTests.G{Mono.Linker.Tests.DocumentationSignatureParserTests.A,``0}}**[0:,0:,0:][][][0:,0:]@)")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M``1(Mono.Linker.Tests.DocumentationSignatureParserTests.S{Mono.Linker.Tests.DocumentationSignatureParserTests.G{Mono.Linker.Tests.DocumentationSignatureParserTests.A,``0}}**[0:,0:,0:][][][0:,0:]@)")] - public unsafe void M (ref S>**[,][][][,,] a) + public static unsafe void M (ref S>**[,][][][,,] a) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Collections.Generic.List{System.Int32[]})")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Collections.Generic.List{System.Int32[]})")] - public void M (List a) + public static void M (List a) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32,)")] //[ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.A.M(System.Int32,)")] // there's no way to reference this, since the parsing logic doesn't like it. - public void M (int abo, __arglist) + public static void M (int abo, __arglist) { } @@ -296,7 +295,7 @@ namespace Mono.Linker.Tests { [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.B.Method(Mono.Linker.Tests.DocumentationSignatureParserTests.G{Mono.Linker.Tests.DocumentationSignatureParserTests.A{Mono.Linker.Tests.DocumentationSignatureParserTests.B},System.Collections.Generic.List{Mono.Linker.Tests.DocumentationSignatureParserTests.A}})")] [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.B.Method(Mono.Linker.Tests.DocumentationSignatureParserTests.G{Mono.Linker.Tests.DocumentationSignatureParserTests.A{Mono.Linker.Tests.DocumentationSignatureParserTests.B},System.Collections.Generic.List{Mono.Linker.Tests.DocumentationSignatureParserTests.A}})")] - public void Method (G, List> l) + public static void Method (G, List> l) { } } @@ -336,44 +335,44 @@ namespace Mono.Linker.Tests [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Method")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Method")] - public void Method () + public static void Method () { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Method(System.Int32)")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Method(System.Int32)")] - public void Method (int i) + public static void Method (int i) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.IntMethod")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.IntMethod")] - public int IntMethod () => 0; + public static int IntMethod () => 0; [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Method(Mono.Linker.Tests.DocumentationSignatureParserTests.G{Mono.Linker.Tests.DocumentationSignatureParserTests.A,Mono.Linker.Tests.DocumentationSignatureParserTests.A})")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Method(Mono.Linker.Tests.DocumentationSignatureParserTests.G{Mono.Linker.Tests.DocumentationSignatureParserTests.A,Mono.Linker.Tests.DocumentationSignatureParserTests.A})")] - public void Method (G g) + public static void Method (G g) { } [ExpectGeneratedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Method(Mono.Linker.Tests.DocumentationSignatureParserTests.G{Mono.Linker.Tests.DocumentationSignatureParserTests.A,Mono.Linker.Tests.DocumentationSignatureParserTests.A}.NG{Mono.Linker.Tests.DocumentationSignatureParserTests.A})")] [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Method(Mono.Linker.Tests.DocumentationSignatureParserTests.G{Mono.Linker.Tests.DocumentationSignatureParserTests.A,Mono.Linker.Tests.DocumentationSignatureParserTests.A}.NG{Mono.Linker.Tests.DocumentationSignatureParserTests.A})")] - public void Method (G.NG g) + public static void Method (G.NG g) { } public class Invalid { [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.NoReturnType~")] - public int NoReturnType () => 0; + public static int NoReturnType () => 0; [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.NoParameters(,)")] - public void NoParameters (int a, int b) + public static void NoParameters (int a, int b) { } [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.NoClosingParen(")] - public void NoClosingParen () { } + public static void NoClosingParen () { } [ExpectUnresolvedDocumentationSignature ("T:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Whitespace ")] [ExpectUnresolvedDocumentationSignature (" T:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Whitespace")] @@ -384,12 +383,12 @@ namespace Mono.Linker.Tests public class Whitespace { [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Whitespace.Method(System.Int32, System.Int32)")] - public void Method (int a, int b) + public static void Method (int a, int b) { } [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Whitespace.Method(Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Generic{System.Int32, System.Int32})")] - public void Method (Generic g) + public static void Method (Generic g) { } } @@ -422,18 +421,18 @@ namespace Mono.Linker.Tests } [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.MethodWithGenericInstantiation(Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Generic`1)")] - public void MethodWithGenericInstantiation (Generic g) + public static void MethodWithGenericInstantiation (Generic g) { } [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Method(System.Int32[:,:])")] [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Method(System.Int32[0:,)")] - public void Method (int[,] a) + public static void Method (int[,] a) { } [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.NonGenericMethod(``0)")] - public void NonGenericMethod (int i) + public static void NonGenericMethod (int i) { } @@ -445,7 +444,7 @@ namespace Mono.Linker.Tests } [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.MethodMissingArgumentTypeName(System.)")] - public void MethodMissingArgumentTypeName (int i) + public static void MethodMissingArgumentTypeName (int i) { } @@ -453,7 +452,7 @@ namespace Mono.Linker.Tests public class NoType { [ExpectUnresolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid..Method")] - public void Method () + public static void Method () { } } @@ -466,12 +465,12 @@ namespace Mono.Linker.Tests } [ExpectUnresolvedDocumentationSignature ("T:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.NoParameterType()")] - public void NoParameterType (int i) + public static void NoParameterType (int i) { } [ExpectUnresolvedDocumentationSignature ("T:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.NoParameterType(Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Generic{})")] - public void NoGenericParameterType (Generic g) + public static void NoGenericParameterType (Generic g) { } @@ -503,12 +502,12 @@ namespace Mono.Linker.Tests } [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.NoClosingParenWithParameters(System.Int32")] - public void NoClosingParenWithParameters (int a) + public static void NoClosingParenWithParameters (int a) { } [ExpectExactlyResolvedDocumentationSignature ("M:Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.NoClosingBrace(Mono.Linker.Tests.DocumentationSignatureParserTests.Invalid.Generic{Mono.Linker.Tests.DocumentationSignatureParserTests.A)")] - public void NoClosingBrace (Generic g) + public static void NoClosingBrace (Generic g) { } diff --git a/test/Mono.Linker.Tests/Tests/GetDisplayNameTests.cs b/test/Mono.Linker.Tests/Tests/GetDisplayNameTests.cs index b025aae92..2b3075850 100644 --- a/test/Mono.Linker.Tests/Tests/GetDisplayNameTests.cs +++ b/test/Mono.Linker.Tests/Tests/GetDisplayNameTests.cs @@ -52,53 +52,53 @@ namespace Mono.Linker.Tests } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.SingleDimensionalArrayTypeParameter(Int32[])")] - public void SingleDimensionalArrayTypeParameter (int[] p) + public static void SingleDimensionalArrayTypeParameter (int[] p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.MultiDimensionalArrayTypeParameter(Int32[,])")] - public void MultiDimensionalArrayTypeParameter (int[,] p) + public static void MultiDimensionalArrayTypeParameter (int[,] p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.JaggedArrayTypeParameter(Int32[][,])")] - public void JaggedArrayTypeParameter (int[][,] p) + public static void JaggedArrayTypeParameter (int[][,] p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.JaggedArrayTypeParameter(Int32[,][])")] - public void JaggedArrayTypeParameter (int[,][] p) + public static void JaggedArrayTypeParameter (int[,][] p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.JaggedArrayTypeParameter(Int32[,][,,][,,,])")] - public void JaggedArrayTypeParameter (int[,][,,][,,,] p) + public static void JaggedArrayTypeParameter (int[,][,,][,,,] p) { } // PointerType [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.CommonPointerPointerTypeParameter(Int32*)")] - public unsafe void CommonPointerPointerTypeParameter (int* p) + public static unsafe void CommonPointerPointerTypeParameter (int* p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.PointerToPointerPointerTypeParameter(Int32**)")] - public unsafe void PointerToPointerPointerTypeParameter (int** p) + public static unsafe void PointerToPointerPointerTypeParameter (int** p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.PointerToArrayPointerTypeParameter(Int32*[,,,])")] - public unsafe void PointerToArrayPointerTypeParameter (int*[,,,] p) + public static unsafe void PointerToArrayPointerTypeParameter (int*[,,,] p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.PointerToArrayPointerTypeParameter(Int32*[,][,,])")] - public unsafe void PointerToArrayPointerTypeParameter (int*[,][,,] p) + public static unsafe void PointerToArrayPointerTypeParameter (int*[,][,,] p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.A.PointerTypeToUnknownTypeParameter(Void*)")] - public unsafe void PointerTypeToUnknownTypeParameter (void* p) + public static unsafe void PointerTypeToUnknownTypeParameter (void* p) { } } @@ -167,7 +167,7 @@ namespace Mono.Linker.Tests } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.MethodWithNestedGenericTypeArgumentsNoArgumentsOnLeaf(GetDisplayNameTests.GenericClassOneParameter.B)")] - public void MethodWithNestedGenericTypeArgumentsNoArgumentsOnLeaf (GenericClassOneParameter.B p) { } + public static void MethodWithNestedGenericTypeArgumentsNoArgumentsOnLeaf (GenericClassOneParameter.B p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.GenericClassMultipleParameters")] public class GenericClassMultipleParameters @@ -179,24 +179,24 @@ namespace Mono.Linker.Tests } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.MethodWithGenericTypeArgument(IList>)")] - public void MethodWithGenericTypeArgument (IList> p) + public static void MethodWithGenericTypeArgument (IList> p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.MethodWithGenericTypeArguments(GetDisplayNameTests.GenericClassMultipleParameters)")] - public void MethodWithGenericTypeArguments (GenericClassMultipleParameters p) + public static void MethodWithGenericTypeArguments (GenericClassMultipleParameters p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.MethodWithNestedGenericTypeArguments" + "(GetDisplayNameTests.GenericClassMultipleParameters.NestedGenericClassMultipleParameters)")] - public void MethodWithNestedGenericTypeArguments (GenericClassMultipleParameters.NestedGenericClassMultipleParameters p) + public static void MethodWithNestedGenericTypeArguments (GenericClassMultipleParameters.NestedGenericClassMultipleParameters p) { } [DisplayName ("Mono.Linker.Tests.GetDisplayNameTests.MethodWithPartiallyInstantiatedNestedGenericTypeArguments" + "(GetDisplayNameTests.GenericClassMultipleParameters.NestedGenericClassMultipleParameters)")] - public void MethodWithPartiallyInstantiatedNestedGenericTypeArguments ( + public static void MethodWithPartiallyInstantiatedNestedGenericTypeArguments ( GenericClassMultipleParameters.NestedGenericClassMultipleParameters p) { } @@ -219,7 +219,7 @@ public class GetDisplayNameTestsGlobalScope public class TypeInGlobalScope { [DisplayName ("GetDisplayNameTestsGlobalScope.TypeInGlobalScope.Method()")] - public void Method () + public static void Method () { } } diff --git a/test/Mono.Linker.Tests/Tests/ParseResponseFileLinesTests.cs b/test/Mono.Linker.Tests/Tests/ParseResponseFileLinesTests.cs index e97960359..df06c3ff0 100644 --- a/test/Mono.Linker.Tests/Tests/ParseResponseFileLinesTests.cs +++ b/test/Mono.Linker.Tests/Tests/ParseResponseFileLinesTests.cs @@ -106,7 +106,7 @@ b""", new string[] { @"a b" }); } - private void TestParseResponseFileLines (string v1, string[] v2) + private static void TestParseResponseFileLines (string v1, string[] v2) { var result = new Queue (); using (var reader = new StringReader (v1)) -- cgit v1.2.3