diff options
author | Jeremy Koritzinsky <jekoritz@microsoft.com> | 2021-04-19 23:01:44 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-19 23:01:44 +0300 |
commit | f6ccab59b40c959c10a28f696b3ec8ba0569fe25 (patch) | |
tree | 620c068309c376300451ef6bc56838018887d91f /test/Mono.Linker.Tests.Cases | |
parent | 76bcd90110b1c4d65a53b99761ac00e0f6b06b21 (diff) |
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.
Diffstat (limited to 'test/Mono.Linker.Tests.Cases')
6 files changed, 198 insertions, 37 deletions
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); } @@ -981,6 +1064,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 () { typeof (MakeGenericMethod).GetMethod (nameof (GenericWithNoRequirements), BindingFlags.Static) @@ -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[] { }, diff --git a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs index 866fab24b..7f47ff4a3 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs @@ -238,10 +238,11 @@ namespace Mono.Linker.Tests.Cases.Reflection { } [Kept] + [ExpectedWarning ("IL2060", "Expression::Call")] static void TestWithNoTypeParameters () { - // Linker doesn't check if it's valid to call a generic method without generic parameters, it looks like a non-generic call - // so it will preserve the target method. + // Linker warns since this is a call to a generic method with a mismatching number of generic parameters + // and provided type values for the generic instantiation. Expression.Call (typeof (TestGenericMethods), nameof (GenericMethodCalledAsNonGeneric), Type.EmptyTypes); } @@ -253,18 +254,24 @@ namespace Mono.Linker.Tests.Cases.Reflection } [Kept] - [ExpectedWarning ("IL2060", "Expression::Call")] static void TestMethodWithRequirements () { - // This must warn - as this is dangerous - Expression.Call (typeof (TestGenericMethods), nameof (GenericMethodWithRequirements), new Type[] { GetUnknownType () }); + // This may not warn - as it's safe + Expression.Call (typeof (TestGenericMethods), nameof (GenericMethodWithRequirements), new Type[] { GetUnknownTypeWithRequrements () }); + } + + [Kept] + [ExpectedWarning ("IL2060", "Expression::Call")] + static void TestMethodWithRequirementsUnknownTypeArray (Type[] types) + { + // The passed in types array cannot be analyzed, so a warning is produced. + Expression.Call (typeof (TestGenericMethods), nameof (GenericMethodWithRequirements), types); } [Kept] [ExpectedWarning ("IL2060", "Expression::Call")] static void TestMethodWithRequirementsButNoTypeArguments () { - // Linker could figure out that this is not a problem, but it's not worth the complexity, since this will always throw at runtime Expression.Call (typeof (TestGenericMethods), nameof (GenericMethodWithRequirementsNoArguments), Type.EmptyTypes); } @@ -333,6 +340,7 @@ namespace Mono.Linker.Tests.Cases.Reflection TestWithNoTypeParameters (); TestMethodWithoutRequirements (); TestMethodWithRequirements (); + TestMethodWithRequirementsUnknownTypeArray (null); TestMethodWithRequirementsButNoTypeArguments (); UnknownMethodWithRequirements.TestWithTypeParameters (); UnknownMethodWithRequirements.TestWithoutTypeParameters (); @@ -342,6 +350,11 @@ namespace Mono.Linker.Tests.Cases.Reflection [Kept] static Type GetUnknownType () { return null; } + + [Kept] + [return: KeptAttributeAttribute (typeof (DynamicallyAccessedMembersAttribute))] + [return: DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] + static Type GetUnknownTypeWithRequrements () { return null; } } } } |