From f6ccab59b40c959c10a28f696b3ec8ba0569fe25 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 19 Apr 2021 13:01:44 -0700 Subject: Support running a basic analysis of generic instantiations created through reflection. (#1955) Enable a basic analysis for arrays of `System.Type` passed to `Type.MakeGenericType` and `MethodInfo.MakeGenericMethod`. This analysis works for arrays created within the method with a constant size where all array elements are known. This allows for common usages of `Type.MakeGenericType` and `MethodInfo.MakeGenericMethod` that let the compiler implicitly create an array for them (since the parameter is `params`) to get basic analysis. Also enable analysis for ldelem when it's a known array with a known value at a given known index. In combination with #1930, we could also enable this validation for `Expression.Call` on generic types. --- .../DataFlow/FieldDataFlow.cs | 5 + .../DataFlow/GenericParameterDataFlow.cs | 190 +++++++++++++++++---- .../DataFlow/MethodParametersDataFlow.cs | 5 + .../DataFlow/MethodReturnParameterDataFlow.cs | 5 + .../DataFlow/MethodThisDataFlow.cs | 5 + 5 files changed, 179 insertions(+), 31 deletions(-) (limited to 'test/Mono.Linker.Tests.Cases/DataFlow') diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs index 6965f80ef..380b72a70 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/FieldDataFlow.cs @@ -148,7 +148,12 @@ namespace Mono.Linker.Tests.Cases.DataFlow { var array = new object[1]; array[0] = this.GetType (); + MakeArrayValuesUnknown (array); TypeStore._staticTypeWithPublicParameterlessConstructor = (Type) array[0]; + + static void MakeArrayValuesUnknown (object[] array) + { + } } private static void RequirePublicParameterlessConstructor ( diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs index 08bb958cd..27d487a3e 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/GenericParameterDataFlow.cs @@ -735,6 +735,9 @@ namespace Mono.Linker.Tests.Cases.DataFlow { TestNullType (); TestUnknownInput (null); + TestWithUnknownTypeArray (null); + TestWithArrayUnknownIndexSet (0); + TestWithArrayUnknownLengthSet (1); TestNoArguments (); TestWithRequirements (); @@ -768,6 +771,31 @@ namespace Mono.Linker.Tests.Cases.DataFlow inputType.MakeGenericType (typeof (TestType)); } + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, + messageCode: "IL2055")] + static void TestWithUnknownTypeArray (Type[] types) + { + typeof (GenericWithPublicFieldsArgument<>).MakeGenericType (types); + } + + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, + messageCode: "IL2055")] + static void TestWithArrayUnknownIndexSet (int indexToSet) + { + Type[] types = new Type[1]; + types[indexToSet] = typeof (TestType); + typeof (GenericWithPublicFieldsArgument<>).MakeGenericType (types); + } + + [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, + messageCode: "IL2055")] + static void TestWithArrayUnknownLengthSet (int arrayLen) + { + Type[] types = new Type[arrayLen]; + types[0] = typeof (TestType); + typeof (GenericWithPublicFieldsArgument<>).MakeGenericType (types); + } + [RecognizedReflectionAccessPattern] static void TestNoArguments () { @@ -778,8 +806,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, - messageCode: "IL2055")] + [RecognizedReflectionAccessPattern] static void TestWithRequirements () { // Currently this is not analyzable since we don't track array elements. @@ -787,16 +814,14 @@ namespace Mono.Linker.Tests.Cases.DataFlow typeof (GenericWithPublicFieldsArgument<>).MakeGenericType (typeof (TestType)); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, - messageCode: "IL2055")] + [RecognizedReflectionAccessPattern] static void TestWithRequirementsFromParam ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type) { typeof (GenericWithPublicFieldsArgument<>).MakeGenericType (type); } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, - messageCode: "IL2055")] + [RecognizedReflectionAccessPattern] static void TestWithRequirementsFromGenericParam< [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T> () { @@ -823,8 +848,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, - messageCode: "IL2055")] + [RecognizedReflectionAccessPattern] static void TestWithMultipleArgumentsWithRequirements () { typeof (GenericWithMultipleArgumentsWithRequirements<,>).MakeGenericType (typeof (TestType), typeof (TestType)); @@ -836,8 +860,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, - messageCode: "IL2055")] + [RecognizedReflectionAccessPattern] static void TestWithNewConstraint () { typeof (GenericWithNewConstraint<>).MakeGenericType (typeof (TestType)); @@ -847,8 +870,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, - messageCode: "IL2055")] + [RecognizedReflectionAccessPattern] static void TestWithStructConstraint () { typeof (GenericWithStructConstraint<>).MakeGenericType (typeof (TestType)); @@ -858,8 +880,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } - [UnrecognizedReflectionAccessPattern (typeof (Type), nameof (Type.MakeGenericType), new Type[] { typeof (Type[]) }, - messageCode: "IL2055")] + [RecognizedReflectionAccessPattern] static void TestWithUnmanagedConstraint () { typeof (GenericWithUnmanagedConstraint<>).MakeGenericType (typeof (TestType)); @@ -881,8 +902,13 @@ namespace Mono.Linker.Tests.Cases.DataFlow public static void Test () { TestNullMethod (); - TestUnknownInput (null); + TestUnknownMethod (null); TestUnknownMethodButNoTypeArguments (null); + TestWithUnknownTypeArray (null); + TestWithArrayUnknownIndexSet (0); + TestWithArrayUnknownIndexSetByRef (0); + TestWithArrayUnknownLengthSet (1); + TestWithArrayPassedToAnotherMethod (); TestWithNoArguments (); TestWithRequirements (); @@ -891,6 +917,11 @@ namespace Mono.Linker.Tests.Cases.DataFlow TestWithRequirementsViaRuntimeMethod (); TestWithRequirementsButNoTypeArguments (); + TestWithMultipleKnownGenericParameters (); + TestWithOneUnknownGenericParameter (null); + TestWithPartiallyInitializedGenericTypeArray (); + TestWithConditionalGenericTypeSet (true); + TestWithNoRequirements (); TestWithNoRequirementsFromParam (null); TestWithNoRequirementsViaRuntimeMethod (); @@ -911,7 +942,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, messageCode: "IL2060")] - static void TestUnknownInput (MethodInfo mi) + static void TestUnknownMethod (MethodInfo mi) { mi.MakeGenericMethod (typeof (TestType)); } @@ -924,6 +955,61 @@ namespace Mono.Linker.Tests.Cases.DataFlow mi.MakeGenericMethod (Type.EmptyTypes); } + [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, + messageCode: "IL2060")] + static void TestWithUnknownTypeArray (Type[] types) + { + typeof (MakeGenericMethod).GetMethod (nameof (GenericWithRequirements), BindingFlags.Static) + .MakeGenericMethod (types); + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, + messageCode: "IL2060")] + static void TestWithArrayUnknownIndexSet (int indexToSet) + { + Type[] types = new Type[1]; + types[indexToSet] = typeof (TestType); + typeof (MakeGenericMethod).GetMethod (nameof (GenericWithRequirements), BindingFlags.Static) + .MakeGenericMethod (types); + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, + messageCode: "IL2060")] + static void TestWithArrayUnknownIndexSetByRef (int indexToSet) + { + Type[] types = new Type[1]; + types[0] = typeof (TestType); + ref Type t = ref types[indexToSet]; + t = typeof (TestType); + typeof (MakeGenericMethod).GetMethod (nameof (GenericWithRequirements), BindingFlags.Static) + .MakeGenericMethod (types); + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, + messageCode: "IL2060")] + static void TestWithArrayUnknownLengthSet (int arrayLen) + { + Type[] types = new Type[arrayLen]; + types[0] = typeof (TestType); + typeof (MakeGenericMethod).GetMethod (nameof (GenericWithRequirements), BindingFlags.Static) + .MakeGenericMethod (types); + } + + static void MethodThatTakesArrayParameter (Type[] types) + { + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, + messageCode: "IL2060")] + static void TestWithArrayPassedToAnotherMethod () + { + Type[] types = new Type[1]; + types[0] = typeof (TestType); + MethodThatTakesArrayParameter (types); + typeof (MakeGenericMethod).GetMethod (nameof (GenericWithRequirements), BindingFlags.Static) + .MakeGenericMethod (types); + } + [RecognizedReflectionAccessPattern] static void TestWithNoArguments () { @@ -935,16 +1021,14 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } - [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, - messageCode: "IL2060")] + [RecognizedReflectionAccessPattern] static void TestWithRequirements () { typeof (MakeGenericMethod).GetMethod (nameof (GenericWithRequirements), BindingFlags.Static) .MakeGenericMethod (typeof (TestType)); } - [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, - messageCode: "IL2060")] + [RecognizedReflectionAccessPattern] static void TestWithRequirementsFromParam ( [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] Type type) { @@ -959,8 +1043,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow .MakeGenericMethod (typeof (T)); } - [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, - messageCode: "IL2060")] + + [RecognizedReflectionAccessPattern] static void TestWithRequirementsViaRuntimeMethod () { typeof (MakeGenericMethod).GetRuntimeMethod (nameof (GenericWithRequirements), Type.EmptyTypes) @@ -971,7 +1055,6 @@ namespace Mono.Linker.Tests.Cases.DataFlow messageCode: "IL2060")] static void TestWithRequirementsButNoTypeArguments () { - // Linker could figure out that this is not a problem, but it's not worth the complexity, since this will always throw at runtime typeof (MakeGenericMethod).GetMethod (nameof (GenericWithRequirements), BindingFlags.Static) .MakeGenericMethod (Type.EmptyTypes); } @@ -980,6 +1063,54 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } + [RecognizedReflectionAccessPattern] + static void TestWithMultipleKnownGenericParameters () + { + typeof (MakeGenericMethod).GetMethod (nameof (GenericMultipleParameters), BindingFlags.Static) + .MakeGenericMethod (typeof (TestType), typeof (TestType), typeof (TestType)); + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, + messageCode: "IL2060")] + static void TestWithOneUnknownGenericParameter (Type[] types) + { + typeof (MakeGenericMethod).GetMethod (nameof (GenericMultipleParameters), BindingFlags.Static) + .MakeGenericMethod (typeof (TestType), typeof (TestStruct), types[0]); + } + + [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, + messageCode: "IL2060")] + static void TestWithPartiallyInitializedGenericTypeArray () + { + Type[] types = new Type[3]; + types[0] = typeof (TestType); + types[1] = typeof (TestStruct); + typeof (MakeGenericMethod).GetMethod (nameof (GenericMultipleParameters), BindingFlags.Static) + .MakeGenericMethod (types); + } + + [RecognizedReflectionAccessPattern] + static void TestWithConditionalGenericTypeSet (bool thirdParameterIsStruct) + { + Type[] types = new Type[3]; + types[0] = typeof (TestType); + types[1] = typeof (TestStruct); + if (thirdParameterIsStruct) { + types[2] = typeof (TestStruct); + } else { + types[2] = typeof (TestType); + } + typeof (MakeGenericMethod).GetMethod (nameof (GenericMultipleParameters), BindingFlags.Static) + .MakeGenericMethod (types); + } + + public static void GenericMultipleParameters< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] T, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] U, + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicFields)] V> () + { + } + [RecognizedReflectionAccessPattern] static void TestWithNoRequirements () { @@ -1005,8 +1136,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } - [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, - messageCode: "IL2060")] + + [RecognizedReflectionAccessPattern] static void TestWithMultipleArgumentsWithRequirements () { typeof (MakeGenericMethod).GetMethod (nameof (GenericWithMultipleArgumentsWithRequirements), BindingFlags.Static | BindingFlags.NonPublic) @@ -1019,8 +1150,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { } - [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, - messageCode: "IL2060")] + [RecognizedReflectionAccessPattern] static void TestWithNewConstraint () { typeof (MakeGenericMethod).GetMethod (nameof (GenericWithNewConstraint), BindingFlags.Static | BindingFlags.NonPublic) @@ -1032,8 +1162,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow var t = new T (); } - [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, - messageCode: "IL2060")] + [RecognizedReflectionAccessPattern] static void TestWithStructConstraint () { typeof (MakeGenericMethod).GetMethod (nameof (GenericWithStructConstraint), BindingFlags.Static | BindingFlags.NonPublic) @@ -1045,8 +1174,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow var t = new T (); } - [UnrecognizedReflectionAccessPattern (typeof (MethodInfo), nameof (MethodInfo.MakeGenericMethod), new Type[] { typeof (Type[]) }, - messageCode: "IL2060")] + [RecognizedReflectionAccessPattern] static void TestWithUnmanagedConstraint () { typeof (MakeGenericMethod).GetMethod (nameof (GenericWithUnmanagedConstraint), BindingFlags.Static | BindingFlags.NonPublic) diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs index 2897c4705..fe11b6b03 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodParametersDataFlow.cs @@ -161,7 +161,12 @@ namespace Mono.Linker.Tests.Cases.DataFlow { var array = new object[1]; array[0] = this.GetType (); + MakeArrayValuesUnknown (array); RequirePublicParameterlessConstructor ((Type) array[0]); + + static void MakeArrayValuesUnknown (object[] array) + { + } } [RecognizedReflectionAccessPattern] diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs index f66a25e74..c0925a264 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodReturnParameterDataFlow.cs @@ -126,7 +126,12 @@ namespace Mono.Linker.Tests.Cases.DataFlow { var array = new object[1]; array[0] = this.GetType (); + MakeArrayValuesUnknown (array); return (Type) array[0]; + + static void MakeArrayValuesUnknown (object[] array) + { + } } [UnrecognizedReflectionAccessPattern (typeof (MethodReturnParameterDataFlow), nameof (RequirePublicConstructors), new Type[] { typeof (Type) }, messageCode: "IL2072")] diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs b/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs index 9dc4813b8..a8bfbed1f 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/MethodThisDataFlow.cs @@ -100,7 +100,12 @@ namespace Mono.Linker.Tests.Cases.DataFlow { var array = new object[1]; array[0] = array.GetType (); + MakeArrayValuesUnknown (array); ((MethodThisDataFlowTypeTest) array[0]).RequireThisNonPublicMethods (); + + static void MakeArrayValuesUnknown (object[] array) + { + } } [UnrecognizedReflectionAccessPattern (typeof (MethodThisDataFlowTypeTest), nameof (MethodThisDataFlowTypeTest.RequireThisPublicMethods), new Type[] { }, -- cgit v1.2.3