From aab8d7d2642ebbfe90b36d308ea824d8c2bb632d Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Tue, 24 Mar 2020 20:14:28 -0700 Subject: [PATCH 1/8] Port existing Expression.* pattern recognition to new intrinsics Commit migrated from https://github.com/dotnet/linker/commit/14c446fea2ea29471398045c87074b592b0dafe2 --- .../src/linker/Linker.Steps/MarkStep.cs | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 500f5db8f24e81..d89db2aac8b61a 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3608,6 +3608,98 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c } break; + // + // static Call (Type, String, Type[], Expression[]) + // + case "Call" when calledMethod.DeclaringType.Name == "Expression" + && calledMethod.Parameters.Count == 4 + && calledMethod.Parameters [0].ParameterType.FullName == "System.Type": { + + reflectionContext.AnalyzingPattern (); + + foreach (var value in methodParams [0].UniqueValues ()) { + if (value is SystemTypeValue systemTypeValue) { + foreach (var stringParam in methodParams [1].UniqueValues ()) { + if (stringParam is KnownStringValue stringValue) { + MarkMethodsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + } else { + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); + } + } + } else if (value == NullValue.Instance) { + reflectionContext.RecordHandledPattern (); + } else if (value is MethodParameterValue methodParameterValue) { + // TODO: Check if parameter is annotated. + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 1st argument which cannot be analyzed"); + } else { + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 1st argument which cannot be analyzed"); + } + } + } + break; + + // + // static Field (Expression, Type, String) + // static Property (Expression, Type, String) + // + case "Field": + case "Property" when calledMethod.DeclaringType.Name == "Expression" + && calledMethod.Parameters.Count == 3 + && calledMethod.Parameters[1].ParameterType.FullName == "System.Type": { + + reflectionContext.AnalyzingPattern (); + + foreach (var value in methodParams [1].UniqueValues ()) { + if (value is SystemTypeValue systemTypeValue) { + // systemTypeValue.TypeRepresented is `declaringType` + foreach (var stringParam in methodParams [2].UniqueValues ()) { + if (stringParam is KnownStringValue stringValue) { + bool staticOnly = methodParams [0].Kind == ValueNodeKind.Null; + if (calledMethod.Name [0] == 'P') { + MarkPropertiesFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, staticOnly); + } else { + MarkFieldsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, staticOnly); + } + } else { + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); + } + } + } else if (value == NullValue.Instance) { + reflectionContext.RecordHandledPattern (); + } else if (value is MethodParameterValue methodParameterValue) { + // TODO: Check if parameter is annotated. + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); + } else { + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); + } + } + } + break; + + // + // static New (Type) + // + case "New" when calledMethod.DeclaringType.Name == "Expression" + && calledMethod.Parameters.Count == 1 + && calledMethod.Parameters [0].ParameterType.FullName == "System.Type": { + + reflectionContext.AnalyzingPattern (); + + foreach (var value in methodParams[0].UniqueValues ()) { + if (value is SystemTypeValue systemTypeValue) { + MarkMethodsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, ".ctor", BindingFlags.Instance, parametersCount: 0); + } else if (value == NullValue.Instance) { + reflectionContext.RecordHandledPattern (); + } else if (value is MethodParameterValue methodParameterValue) { + // TODO: Check if parameter is annotated. + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 1st argument which cannot be analyzed"); + } else { + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 1st argument which cannot be analyzed"); + } + } + } + break; + // // static CreateInstance (System.Type type) // static CreateInstance (System.Type type, bool nonPublic) @@ -3893,6 +3985,58 @@ string GetDynamicallyAccessedMemberKindsDescription (DynamicallyAccessedMemberKi return string.Join (" | ", results.Select (r => r.ToString ())); } + + void MarkPropertiesFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, bool staticOnly = false) + { + bool foundMatch = false; + foreach (var property in declaringType.Properties) { + if (property.Name != name) + continue; + + bool markedAny = false; + + // It is not easy to reliably detect in the IL code whether the getter or setter (or both) are used. + // Be conservative and mark everything for the property. + var getter = property.GetMethod; + if (getter != null && (!staticOnly || staticOnly && getter.IsStatic)) { + reflectionContext.RecordRecognizedPattern (getter, () => _markStep.MarkIndirectlyCalledMethod (getter)); + markedAny = true; + } + + var setter = property.SetMethod; + if (setter != null && (!staticOnly || staticOnly && setter.IsStatic)) { + reflectionContext.RecordRecognizedPattern (setter, () => _markStep.MarkIndirectlyCalledMethod (setter)); + markedAny = true; + } + + if (markedAny) { + foundMatch = true; + reflectionContext.RecordRecognizedPattern (property, () => _markStep.MarkProperty (property)); + } + } + + if (!foundMatch) + reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve property `{name}` on type `{declaringType.FullName}`."); + } + + void MarkFieldsFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, bool staticOnly = false) + { + bool foundMatch = false; + foreach (var field in declaringType.Fields) { + if (field.Name != name) + continue; + + if (staticOnly && !field.IsStatic) + continue; + + foundMatch = true; + reflectionContext.RecordRecognizedPattern (field, () => _markStep.MarkField (field)); + break; + } + + if (!foundMatch) + reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve field `{name}` on type `{declaringType.FullName}`."); + } } } From 1dda3809be12e669d868f818558630751f5ce535 Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Wed, 25 Mar 2020 15:30:00 -0700 Subject: [PATCH 2/8] Extend current tests for for Expression.New, Expression.Field and Expression.Property Commit migrated from https://github.com/dotnet/linker/commit/2db0996737743fbcbd1540e468de4d073297d008 --- .../src/linker/Linker.Steps/MarkStep.cs | 3 + .../Reflection/ExpressionFieldString.cs | 55 +++++++++++++++-- .../Reflection/ExpressionNewType.cs | 54 ++++++++++++++++- .../Reflection/ExpressionPropertyString.cs | 59 +++++++++++++++++-- 4 files changed, 159 insertions(+), 12 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index d89db2aac8b61a..02dc4faf887f44 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3660,6 +3660,9 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c } else { MarkFieldsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, staticOnly); } + } else if (stringParam is MethodParameterValue methodParameterValue) { + // TODO: Check if parameter is annotated. + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); } else { reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs index f8afd5ec53cf60..4bb828ab3348dc 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs @@ -1,4 +1,5 @@ using Mono.Linker.Tests.Cases.Expectations.Assertions; +using System; using System.Linq.Expressions; using Mono.Linker.Tests.Cases.Expectations.Metadata; @@ -9,10 +10,12 @@ public class ExpressionFieldString { public static void Main () { - var e1 = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic1"); - var e2 = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic2"); - - var e3 = Expression.Field (Expression.Parameter (typeof(int), "somename"), typeof (ExpressionFieldString), "TestName1"); + Branch_SystemTypeValueNode_KnownStringValue_NonStatic (); + Branch_SystemTypeValueNode_KnownStringValue_SaticOnly (); + Branch_SystemTypeValueNode_UnknownStringValue (); + Branch_NullValueNode (); + Branch_MethodParameterValueNode (typeof (ExpressionFieldString), "Foo"); + Branch_UnrecognizedPatterns (); } [Kept] @@ -22,5 +25,49 @@ public static void Main () [Kept] private int TestName1; + + [Kept] + static string UnknownString () + { + return "unknownstring"; + } + + [Kept] + static void Branch_SystemTypeValueNode_KnownStringValue_NonStatic () + { + var expr = Expression.Field (Expression.Parameter (typeof (int), "somename"), typeof (ExpressionFieldString), "TestName1"); + } + + [Kept] + static void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () + { + var expr = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic1"); + expr = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic2"); + } + + [Kept] + static void Branch_SystemTypeValueNode_UnknownStringValue () + { + var expr = Expression.Field (null, typeof (ExpressionFieldString), UnknownString ()); + } + + [Kept] + static void Branch_NullValueNode () + { + var expr = Expression.Field (null, UnknownString () == "unknownstring" ? null : typeof (ExpressionFieldString), "TestName1"); + } + + [Kept] + static void Branch_MethodParameterValueNode (Type T, string S) + { + var expr = Expression.Field (null, T, "TestName1"); + expr = Expression.Field (null, typeof (ExpressionFieldString), S); + } + + [Kept] + static void Branch_UnrecognizedPatterns () + { + var expr = Expression.Field (null, Type.GetType ("Foo"), "TestName1"); + } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs index 3987c432e2036b..eee3be4f16b16d 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs @@ -3,6 +3,7 @@ using System; using System.Linq; using Mono.Linker.Tests.Cases.Expectations.Metadata; +using System.Runtime.CompilerServices; namespace Mono.Linker.Tests.Cases.Reflection { @@ -11,7 +12,28 @@ public class ExpressionNewType { public static void Main () { - var expr = Expression.New (typeof (T1)); + Branch_SystemTypeValueNode (); + Branch_NullValueNode (); + Branch_MethodParameterValueNode (typeof (T1)); + Branch_UnrecognizedPatterns (); + } + + [Kept] + static Type GetType () + { + return typeof (T1); + } + + [Kept] + static int Helper1 () + { + return 5; + } + + [Kept] + static int Helper2 () + { + return 7; } [Kept] @@ -20,8 +42,36 @@ class T1 [Kept] internal T1 () { - } } + + class T2 + { + } + + [Kept] + static void Branch_SystemTypeValueNode () + { + var expr = Expression.New (typeof (T1)); + } + + [Kept] + static void Branch_NullValueNode () + { + var expr = Expression.New (Helper1 () + Helper2 () == 12 ? null : typeof (T1)); + } + + [Kept] + static void Branch_MethodParameterValueNode (Type T) + { + var expr = Expression.New (T); + } + + [Kept] + static void Branch_UnrecognizedPatterns () + { + var expr = Expression.New (Type.GetType ("T1")); + expr = Expression.New (GetType ()); + } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs index d049e96903e2d4..953a465f830103 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs @@ -1,4 +1,5 @@ using Mono.Linker.Tests.Cases.Expectations.Assertions; +using System; using System.Linq.Expressions; using Mono.Linker.Tests.Cases.Expectations.Metadata; @@ -12,12 +13,14 @@ public class ExpressionPropertyString public static void Main () { // So that this test works with or without unreachable bodies - new Foo (); - - var e1 = Expression.Property (null, typeof (Foo), "TestOnlyStatic1"); - var e2 = Expression.Property (null, typeof (Foo), "TestOnlyStatic2"); + var Foo = new Foo (); - var e3 = Expression.Property (Expression.Parameter (typeof(int), "somename"), typeof (Foo), "TestName1"); + Foo.Branch_SystemTypeValueNode_KnownStringValue_NonStatic (); + Foo.Branch_SystemTypeValueNode_KnownStringValue_SaticOnly (); + Foo.Branch_SystemTypeValueNode_UnknownStringValue (); + Foo.Branch_NullValueNode (); + Foo.Branch_MethodParameterValueNode (typeof (Foo), "Foo"); + Foo.Branch_UnrecognizedPatterns (); } [KeptMember (".ctor()")] @@ -32,6 +35,50 @@ class Foo [Kept] [KeptBackingField] private int TestName1 { [Kept] get; } + + [Kept] + private string UnknownString () + { + return "unknownstring"; + } + + [Kept] + public void Branch_SystemTypeValueNode_KnownStringValue_NonStatic () + { + var expr = Expression.Property (Expression.Parameter (typeof (int), "somename"), typeof (Foo), "TestName1"); + } + + [Kept] + public void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () + { + var expr = Expression.Property (null, typeof (Foo), "TestOnlyStatic1"); + expr = Expression.Property (null, typeof (Foo), "TestOnlyStatic2"); + } + + [Kept] + public void Branch_SystemTypeValueNode_UnknownStringValue () + { + var expr = Expression.Property (null, typeof (Foo), UnknownString ()); + } + + [Kept] + public void Branch_NullValueNode () + { + var expr = Expression.Property (null, UnknownString () == "unknownstring" ? null : typeof (Foo), "TestName1"); + } + + [Kept] + public void Branch_MethodParameterValueNode (Type T, string S) + { + var expr = Expression.Property (null, T, "TestName1"); + expr = Expression.Property (null, typeof (Foo), S); + } + + [Kept] + public void Branch_UnrecognizedPatterns () + { + var expr = Expression.Property (null, Type.GetType ("Foo"), "TestName1"); + } } } -} +} \ No newline at end of file From b5593ced92a0c0ffe6750431425d49c62eab2d1f Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Thu, 26 Mar 2020 11:33:04 -0700 Subject: [PATCH 3/8] Use UnrecognizedReflectionAccessPattern attribute where appropriate. Commit migrated from https://github.com/dotnet/linker/commit/5716c7aa2defebd1fba61a140c1af4d17cca9db6 --- .../Reflection/ExpressionFieldString.cs | 8 ++++++++ .../Reflection/ExpressionNewType.cs | 3 +++ .../Reflection/ExpressionPropertyString.cs | 8 ++++++++ 3 files changed, 19 insertions(+) diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs index 4bb828ab3348dc..71bf4ede57263f 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs @@ -45,18 +45,24 @@ static void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () expr = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic2"); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] static void Branch_SystemTypeValueNode_UnknownStringValue () { var expr = Expression.Field (null, typeof (ExpressionFieldString), UnknownString ()); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] static void Branch_NullValueNode () { var expr = Expression.Field (null, UnknownString () == "unknownstring" ? null : typeof (ExpressionFieldString), "TestName1"); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] static void Branch_MethodParameterValueNode (Type T, string S) { @@ -64,6 +70,8 @@ static void Branch_MethodParameterValueNode (Type T, string S) expr = Expression.Field (null, typeof (ExpressionFieldString), S); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] static void Branch_UnrecognizedPatterns () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs index eee3be4f16b16d..26176586440dc0 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs @@ -55,18 +55,21 @@ static void Branch_SystemTypeValueNode () var expr = Expression.New (typeof (T1)); } + [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [Kept] static void Branch_NullValueNode () { var expr = Expression.New (Helper1 () + Helper2 () == 12 ? null : typeof (T1)); } + [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [Kept] static void Branch_MethodParameterValueNode (Type T) { var expr = Expression.New (T); } + [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New) , new Type [] { typeof (Type) })] [Kept] static void Branch_UnrecognizedPatterns () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs index 953a465f830103..53140787f4d235 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs @@ -55,18 +55,24 @@ public void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () expr = Expression.Property (null, typeof (Foo), "TestOnlyStatic2"); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] public void Branch_SystemTypeValueNode_UnknownStringValue () { var expr = Expression.Property (null, typeof (Foo), UnknownString ()); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] public void Branch_NullValueNode () { var expr = Expression.Property (null, UnknownString () == "unknownstring" ? null : typeof (Foo), "TestName1"); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] public void Branch_MethodParameterValueNode (Type T, string S) { @@ -74,6 +80,8 @@ public void Branch_MethodParameterValueNode (Type T, string S) expr = Expression.Property (null, typeof (Foo), S); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] public void Branch_UnrecognizedPatterns () { From 07b47731964af686ca4ed9c692b6fe8151883e58 Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Fri, 27 Mar 2020 20:21:58 -0700 Subject: [PATCH 4/8] Remove old pattern matching for Expression.* and enhance existing tests Commit migrated from https://github.com/dotnet/linker/commit/70f5dad5aedf0b778484c36b4f994c0ba15b97d9 --- .../src/linker/Linker.Steps/MarkStep.cs | 151 ++---------------- .../Reflection/ExpressionCallString.cs | 50 ++++-- .../ExpressionCallStringAndLocals.cs | 16 +- .../Reflection/ExpressionFieldString.cs | 4 +- .../Reflection/ExpressionNewType.cs | 3 +- .../Reflection/ExpressionPropertyString.cs | 4 +- 6 files changed, 68 insertions(+), 160 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 02dc4faf887f44..ccb86a6b7de8de 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -2821,140 +2821,12 @@ public void Process (ref ReflectionPatternContext reflectionContext) break; // - // System.Linq.Expressions.Expression + // System.Reflection.RuntimeReflectionExtensions // - case "Expression" when methodCalledType.Namespace == "System.Linq.Expressions": + case "RuntimeReflectionExtensions" when methodCalledType.Namespace == "System.Reflection": Instruction second_argument; TypeDefinition declaringType; - if (!methodCalled.IsStatic) - break; - - switch (methodCalled.Name) { - - // - // static Call (Type, String, Type[], Expression[]) - // - case "Call": { - reflectionContext.AnalyzingPattern (); - - var first_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 4); - if (first_arg_instr < 0) { - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed"); - break; - } - - var first_arg = _instructions [first_arg_instr]; - if (first_arg.OpCode == OpCodes.Ldtoken) - first_arg_instr++; - - declaringType = FindReflectionTypeForLookup (_instructions, first_arg_instr); - if (declaringType == null) { - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 1st argument which cannot be analyzed"); - break; - } - - var second_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 3); - second_argument = _instructions [second_arg_instr]; - if (second_argument.OpCode != OpCodes.Ldstr) { - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 2nd argument which cannot be analyzed"); - break; - } - - var name = (string)second_argument.Operand; - - MarkMethodsFromReflectionCall (ref reflectionContext, declaringType, name, null, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - } - - break; - - // - // static Property(Expression, Type, String) - // static Field (Expression, Type, String) - // - case "Property": - case "Field": { - reflectionContext.AnalyzingPattern (); - - var second_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 2); - if (second_arg_instr < 0) { - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed"); - break; - } - - var second_arg = _instructions [second_arg_instr]; - if (second_arg.OpCode == OpCodes.Ldtoken) - second_arg_instr++; - - declaringType = FindReflectionTypeForLookup (_instructions, second_arg_instr); - if (declaringType == null) { - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 2nd argument which cannot be analyzed"); - break; - } - - var third_arg_inst = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 1); - var third_argument = _instructions [third_arg_inst]; - if (third_argument.OpCode != OpCodes.Ldstr) { - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with the 3rd argument which cannot be analyzed"); - break; - } - - var name = (string)third_argument.Operand; - - // - // The first argument can be any expression but we are looking only for simple null - // which we can convert to static only field lookup - // - var first_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 3); - bool staticOnly = false; - - if (first_arg_instr >= 0) { - var first_arg = _instructions [first_arg_instr]; - if (first_arg.OpCode == OpCodes.Ldnull) - staticOnly = true; - } - - if (methodCalled.Name [0] == 'P') - MarkPropertiesFromReflectionCall (ref reflectionContext, declaringType, name, staticOnly); - else - MarkFieldsFromReflectionCall (ref reflectionContext, declaringType, name, staticOnly); - } - - break; - - // - // static New (Type) - // - case "New": { - reflectionContext.AnalyzingPattern (); - - var first_arg_instr = GetInstructionAtStackDepth (_instructions, instructionIndex - 1, 1); - if (first_arg_instr < 0) { - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' couldn't be decomposed"); - break; - } - - var first_arg = _instructions [first_arg_instr]; - if (first_arg.OpCode == OpCodes.Ldtoken) - first_arg_instr++; - - declaringType = FindReflectionTypeForLookup (_instructions, first_arg_instr); - if (declaringType == null) { - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{methodCalled.FullName}' inside '{_methodCalling.FullName}' was detected with 1st argument which cannot be analyzed"); - break; - } - - MarkMethodsFromReflectionCall (ref reflectionContext, declaringType, ".ctor", 0, BindingFlags.Instance, parametersCount: 0); - } - break; - } - - break; - - // - // System.Reflection.RuntimeReflectionExtensions - // - case "RuntimeReflectionExtensions" when methodCalledType.Namespace == "System.Reflection": switch (methodCalled.Name) { // // static GetRuntimeField (this Type type, string name) @@ -3622,13 +3494,18 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c foreach (var stringParam in methodParams [1].UniqueValues ()) { if (stringParam is KnownStringValue stringValue) { MarkMethodsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + } else if (stringParam is NullValue) { + reflectionContext.RecordHandledPattern (); + } else if (stringParam is MethodParameterValue) { + // TODO: Check if parameter is annotated. + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); } else { reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); } } } else if (value == NullValue.Instance) { reflectionContext.RecordHandledPattern (); - } else if (value is MethodParameterValue methodParameterValue) { + } else if (value is MethodParameterValue) { // TODO: Check if parameter is annotated. reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 1st argument which cannot be analyzed"); } else { @@ -3642,10 +3519,10 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c // static Field (Expression, Type, String) // static Property (Expression, Type, String) // - case "Field": - case "Property" when calledMethod.DeclaringType.Name == "Expression" + case var fieldOrProperty when ((fieldOrProperty == "Field" || fieldOrProperty == "Property") + && calledMethod.DeclaringType.Name == "Expression" && calledMethod.Parameters.Count == 3 - && calledMethod.Parameters[1].ParameterType.FullName == "System.Type": { + && calledMethod.Parameters [1].ParameterType.FullName == "System.Type"): { reflectionContext.AnalyzingPattern (); @@ -3660,7 +3537,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c } else { MarkFieldsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, staticOnly); } - } else if (stringParam is MethodParameterValue methodParameterValue) { + } else if (stringParam is MethodParameterValue) { // TODO: Check if parameter is annotated. reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); } else { @@ -3669,7 +3546,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c } } else if (value == NullValue.Instance) { reflectionContext.RecordHandledPattern (); - } else if (value is MethodParameterValue methodParameterValue) { + } else if (value is MethodParameterValue) { // TODO: Check if parameter is annotated. reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); } else { @@ -3693,7 +3570,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c MarkMethodsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, ".ctor", BindingFlags.Instance, parametersCount: 0); } else if (value == NullValue.Instance) { reflectionContext.RecordHandledPattern (); - } else if (value is MethodParameterValue methodParameterValue) { + } else if (value is MethodParameterValue) { // TODO: Check if parameter is annotated. reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 1st argument which cannot be analyzed"); } else { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs index 2a835c20f49971..b8c8da98d537ea 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs @@ -11,17 +11,24 @@ namespace Mono.Linker.Tests.Cases.Reflection public class ExpressionCallString { public static void Main () + { + Branch_SystemTypeValueNode_KnownStringValue (); + Branch_SystemTypeValueNode_NullValueNode (); + Branch_NullValueNode (); + Branch_MethodParameterValueNode (typeof (ExpressionCallString), "Foo"); + Branch_UnrecognizedPatterns (); + } + + [Kept] + static void Branch_SystemTypeValueNode_KnownStringValue () { TestByName (); TestByNameWithParameters (); - TestNullName (); TestNonExistingName (); - TestNullType (); - TestDataFlowType (); } [RecognizedReflectionAccessPattern ( - typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type[]), typeof (Expression []) }, + typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) }, typeof (ExpressionCallString), nameof (OnlyCalledViaExpression), new Type [0])] [Kept] static void TestByName () @@ -32,7 +39,7 @@ static void TestByName () [RecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) }, - typeof (ExpressionCallString), nameof (Count) + "", new string [] { "T" } )] + typeof (ExpressionCallString), nameof (Count) + "", new string [] { "T" })] [Kept] static void TestByNameWithParameters () { @@ -40,10 +47,8 @@ static void TestByNameWithParameters () var e2 = Expression.Call (typeof (ExpressionCallString), "Count", new Type [] { source.ElementType }, source.Expression); } - [UnrecognizedReflectionAccessPattern ( - typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] [Kept] - static void TestNullName () + static void Branch_SystemTypeValueNode_NullValueNode () { var expr = Expression.Call (typeof (ExpressionCallString), null, Type.EmptyTypes); } @@ -56,10 +61,8 @@ static void TestNonExistingName () var expr = Expression.Call (typeof (ExpressionCallString), "NonExisting", Type.EmptyTypes); } - [UnrecognizedReflectionAccessPattern ( - typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] [Kept] - static void TestNullType () + static void Branch_NullValueNode () { var expr = Expression.Call ((Type)null, "OnlyCalledViaExpression", Type.EmptyTypes); } @@ -73,11 +76,34 @@ static Type FindType () [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] [Kept] - static void TestDataFlowType () + static void Branch_UnrecognizedPatterns () { var expr = Expression.Call (FindType (), "OnlyCalledViaExpression", Type.EmptyTypes); } + [Kept] + static void Branch_MethodParameterValueNode (Type T, string s) + { + TestNonExistingTypeParameter (T); + TestNonExistingNameParameter (s); + } + + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] + [Kept] + static void TestNonExistingTypeParameter (Type T) + { + var expr = Expression.Call (T, "Foo", Type.EmptyTypes); + } + + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] + [Kept] + static void TestNonExistingNameParameter (string s) + { + var expr = Expression.Call (typeof (ExpressionCallString), s, Type.EmptyTypes); + } + [Kept] private static int OnlyCalledViaExpression () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallStringAndLocals.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallStringAndLocals.cs index 470b244c6f5542..b41a023da2c417 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallStringAndLocals.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallStringAndLocals.cs @@ -8,11 +8,7 @@ namespace Mono.Linker.Tests.Cases.Reflection { public class ExpressionCallStringAndLocals { public static void Main () { - var t1 = typeof (ExpressionCallStringAndLocals); - var t2 = t1; - - var expr = Expression.Call (t2, "OnlyCalledViaExpression", Type.EmptyTypes); - Console.WriteLine (expr.Method); + Branch_SystemTypeValueNode_KnownStringValue (); } [Kept] @@ -20,5 +16,15 @@ private static int OnlyCalledViaExpression () { return 42; } + + [Kept] + static void Branch_SystemTypeValueNode_KnownStringValue () + { + var t1 = typeof (ExpressionCallStringAndLocals); + var t2 = t1; + + var expr = Expression.Call (t2, "OnlyCalledViaExpression", Type.EmptyTypes); + Console.WriteLine (expr.Method); + } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs index 71bf4ede57263f..0876c02fdfcfa5 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs @@ -64,10 +64,10 @@ static void Branch_NullValueNode () [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] - static void Branch_MethodParameterValueNode (Type T, string S) + static void Branch_MethodParameterValueNode (Type T, string s) { var expr = Expression.Field (null, T, "TestName1"); - expr = Expression.Field (null, typeof (ExpressionFieldString), S); + expr = Expression.Field (null, typeof (ExpressionFieldString), s); } [UnrecognizedReflectionAccessPattern ( diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs index 26176586440dc0..94ec1b102365d4 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs @@ -55,7 +55,6 @@ static void Branch_SystemTypeValueNode () var expr = Expression.New (typeof (T1)); } - [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [Kept] static void Branch_NullValueNode () { @@ -69,7 +68,7 @@ static void Branch_MethodParameterValueNode (Type T) var expr = Expression.New (T); } - [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New) , new Type [] { typeof (Type) })] + [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [Kept] static void Branch_UnrecognizedPatterns () { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs index 53140787f4d235..d8efc3c1d45c1a 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs @@ -74,10 +74,10 @@ public void Branch_NullValueNode () [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] - public void Branch_MethodParameterValueNode (Type T, string S) + public void Branch_MethodParameterValueNode (Type T, string s) { var expr = Expression.Property (null, T, "TestName1"); - expr = Expression.Property (null, typeof (Foo), S); + expr = Expression.Property (null, typeof (Foo), s); } [UnrecognizedReflectionAccessPattern ( From 500fe4541ee0f8b5d8d11d69ba6b8694ca82499e Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Wed, 1 Apr 2020 23:05:06 -0700 Subject: [PATCH 5/8] Update tests Commit migrated from https://github.com/dotnet/linker/commit/7b6b245d972c9732b76312ff9753bed7bc75938c --- .../src/linker/Linker.Steps/MarkStep.cs | 6 +- .../Reflection/ExpressionCallString.cs | 81 +++++++++++++++---- .../Reflection/ExpressionFieldString.cs | 72 +++++++++++++++-- .../Reflection/ExpressionNewType.cs | 58 +++++++------ .../Reflection/ExpressionPropertyString.cs | 73 ++++++++++++++++- 5 files changed, 238 insertions(+), 52 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index ccb86a6b7de8de..e25dba452772c3 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3484,6 +3484,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c // static Call (Type, String, Type[], Expression[]) // case "Call" when calledMethod.DeclaringType.Name == "Expression" + && calledMethod.DeclaringType.Namespace == "System.Linq.Expressions" && calledMethod.Parameters.Count == 4 && calledMethod.Parameters [0].ParameterType.FullName == "System.Type": { @@ -3498,7 +3499,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c reflectionContext.RecordHandledPattern (); } else if (stringParam is MethodParameterValue) { // TODO: Check if parameter is annotated. - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); + reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); } else { reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); } @@ -3520,6 +3521,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c // static Property (Expression, Type, String) // case var fieldOrProperty when ((fieldOrProperty == "Field" || fieldOrProperty == "Property") + && calledMethod.DeclaringType.Namespace == "System.Linq.Expressions" && calledMethod.DeclaringType.Name == "Expression" && calledMethod.Parameters.Count == 3 && calledMethod.Parameters [1].ParameterType.FullName == "System.Type"): { @@ -3528,7 +3530,6 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c foreach (var value in methodParams [1].UniqueValues ()) { if (value is SystemTypeValue systemTypeValue) { - // systemTypeValue.TypeRepresented is `declaringType` foreach (var stringParam in methodParams [2].UniqueValues ()) { if (stringParam is KnownStringValue stringValue) { bool staticOnly = methodParams [0].Kind == ValueNodeKind.Null; @@ -3560,6 +3561,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c // static New (Type) // case "New" when calledMethod.DeclaringType.Name == "Expression" + && calledMethod.DeclaringType.Namespace == "System.Linq.Expressions" && calledMethod.Parameters.Count == 1 && calledMethod.Parameters [0].ParameterType.FullName == "System.Type": { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs index b8c8da98d537ea..e5eec7b3575b2c 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs @@ -22,19 +22,60 @@ public static void Main () [Kept] static void Branch_SystemTypeValueNode_KnownStringValue () { - TestByName (); + TestByName (0); + TestByName (1); + TestByType (0); + TestByType (1); TestByNameWithParameters (); TestNonExistingName (); } [RecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) }, - typeof (ExpressionCallString), nameof (OnlyCalledViaExpression), new Type [0])] + typeof (ExpressionCallString), nameof (A), new Type [0])] + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) }, + typeof (ExpressionCallString), nameof (B), new Type [0])] + [Kept] + static void TestByName (int i) + { + string MethodName = string.Empty; + switch (i) { + case 0: + MethodName = "A"; + break; + case 1: + MethodName = "B"; + break; + default: + break; + } + + Expression.Call (typeof (ExpressionCallString), MethodName, Type.EmptyTypes); + } + + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) }, + typeof (C), "Foo", new Type [0])] + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) }, + typeof (D), "Foo", new Type [0])] [Kept] - static void TestByName () + static void TestByType (int i) { - var expr = Expression.Call (typeof (ExpressionCallString), "OnlyCalledViaExpression", Type.EmptyTypes); - Console.WriteLine (expr.Method); + Type T = (Type)null; + switch (i) { + case 0: + T = typeof (C); + break; + case 1: + T = typeof (D); + break; + default: + break; + } + + Expression.Call (T, "Foo", Type.EmptyTypes); } [RecognizedReflectionAccessPattern ( @@ -44,13 +85,13 @@ static void TestByName () static void TestByNameWithParameters () { IQueryable source = null; - var e2 = Expression.Call (typeof (ExpressionCallString), "Count", new Type [] { source.ElementType }, source.Expression); + Expression.Call (typeof (ExpressionCallString), "Count", new Type [] { source.ElementType }, source.Expression); } [Kept] static void Branch_SystemTypeValueNode_NullValueNode () { - var expr = Expression.Call (typeof (ExpressionCallString), null, Type.EmptyTypes); + Expression.Call (typeof (ExpressionCallString), null, Type.EmptyTypes); } [UnrecognizedReflectionAccessPattern ( @@ -58,13 +99,13 @@ static void Branch_SystemTypeValueNode_NullValueNode () [Kept] static void TestNonExistingName () { - var expr = Expression.Call (typeof (ExpressionCallString), "NonExisting", Type.EmptyTypes); + Expression.Call (typeof (ExpressionCallString), "NonExisting", Type.EmptyTypes); } [Kept] static void Branch_NullValueNode () { - var expr = Expression.Call ((Type)null, "OnlyCalledViaExpression", Type.EmptyTypes); + Expression.Call ((Type)null, "OnlyCalledViaExpression", Type.EmptyTypes); } [Kept] @@ -78,7 +119,7 @@ static Type FindType () [Kept] static void Branch_UnrecognizedPatterns () { - var expr = Expression.Call (FindType (), "OnlyCalledViaExpression", Type.EmptyTypes); + Expression.Call (FindType (), "OnlyCalledViaExpression", Type.EmptyTypes); } [Kept] @@ -93,7 +134,7 @@ static void Branch_MethodParameterValueNode (Type T, string s) [Kept] static void TestNonExistingTypeParameter (Type T) { - var expr = Expression.Call (T, "Foo", Type.EmptyTypes); + Expression.Call (T, "Foo", Type.EmptyTypes); } [UnrecognizedReflectionAccessPattern ( @@ -101,19 +142,27 @@ static void TestNonExistingTypeParameter (Type T) [Kept] static void TestNonExistingNameParameter (string s) { - var expr = Expression.Call (typeof (ExpressionCallString), s, Type.EmptyTypes); + Expression.Call (typeof (ExpressionCallString), s, Type.EmptyTypes); } [Kept] - private static int OnlyCalledViaExpression () + static void A () { } + + [Kept] + static void B () { } + + [Kept] + class C { - return 42; + [Kept] + static void Foo () { } } [Kept] - private static int OnlyCalledViaExpression (T arg) + class D { - return 2; + [Kept] + static void Foo () { } } [Kept] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs index 0876c02fdfcfa5..2e2181259ec599 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs @@ -26,6 +26,29 @@ public static void Main () [Kept] private int TestName1; + [Kept] + private int TestName2; + + private int TestName3; + + private int TestName4; + + private int TestName5; + + [Kept] + class A + { + [Kept] + static int Foo; + } + + [Kept] + class B + { + [Kept] + static int Foo; + } + [Kept] static string UnknownString () { @@ -35,7 +58,46 @@ static string UnknownString () [Kept] static void Branch_SystemTypeValueNode_KnownStringValue_NonStatic () { - var expr = Expression.Field (Expression.Parameter (typeof (int), "somename"), typeof (ExpressionFieldString), "TestName1"); + TestFieldName (0); + TestFieldName (1); + TestType (0); + TestType (1); + } + + [Kept] + static void TestFieldName (int i) + { + string FieldName = string.Empty; + switch (i) { + case 0: + FieldName = "TestName1"; + break; + case 1: + FieldName = "TestName2"; + break; + default: + break; + } + + Expression.Field (Expression.Parameter (typeof (int), "somename"), typeof (ExpressionFieldString), FieldName); + } + + [Kept] + static void TestType (int i) + { + Type T = (Type)null; + switch (i) { + case 0: + T = typeof (A); + break; + case 1: + T = typeof (B); + break; + default: + break; + } + + Expression.Field (null, T, "Foo"); } [Kept] @@ -53,12 +115,10 @@ static void Branch_SystemTypeValueNode_UnknownStringValue () var expr = Expression.Field (null, typeof (ExpressionFieldString), UnknownString ()); } - [UnrecognizedReflectionAccessPattern ( - typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] static void Branch_NullValueNode () { - var expr = Expression.Field (null, UnknownString () == "unknownstring" ? null : typeof (ExpressionFieldString), "TestName1"); + var expr = Expression.Field (null, (Type)null, "TestName3"); } [UnrecognizedReflectionAccessPattern ( @@ -66,7 +126,7 @@ static void Branch_NullValueNode () [Kept] static void Branch_MethodParameterValueNode (Type T, string s) { - var expr = Expression.Field (null, T, "TestName1"); + var expr = Expression.Field (null, T, "TestName4"); expr = Expression.Field (null, typeof (ExpressionFieldString), s); } @@ -75,7 +135,7 @@ static void Branch_MethodParameterValueNode (Type T, string s) [Kept] static void Branch_UnrecognizedPatterns () { - var expr = Expression.Field (null, Type.GetType ("Foo"), "TestName1"); + var expr = Expression.Field (null, Type.GetType ("Foo"), "TestName5"); } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs index 94ec1b102365d4..fbde31c6f218bd 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs @@ -12,68 +12,78 @@ public class ExpressionNewType { public static void Main () { - Branch_SystemTypeValueNode (); + Branch_SystemTypeValueNode (0); + Branch_SystemTypeValueNode (1); Branch_NullValueNode (); - Branch_MethodParameterValueNode (typeof (T1)); + Branch_MethodParameterValueNode (typeof (C)); Branch_UnrecognizedPatterns (); } [Kept] - static Type GetType () + class A { - return typeof (T1); + [Kept] + A () { } } [Kept] - static int Helper1 () + class B { - return 5; + [Kept] + B () { } } [Kept] - static int Helper2 () - { - return 7; - } + class C { } [Kept] - class T1 - { - [Kept] - internal T1 () - { - } - } + class D { } - class T2 + class RemovedType { } + + [Kept] + static Type GetType () { + return typeof (D); } [Kept] - static void Branch_SystemTypeValueNode () + static void Branch_SystemTypeValueNode (int i) { - var expr = Expression.New (typeof (T1)); + Type T = (Type)null; + switch (i) { + case 0: + T = typeof (A); + break; + case 1: + T = typeof (B); + break; + default: + break; + } + + Expression.New (T); } [Kept] static void Branch_NullValueNode () { - var expr = Expression.New (Helper1 () + Helper2 () == 12 ? null : typeof (T1)); + Expression.New (5 + 7 == 12 ? null : typeof (RemovedType)); } [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [Kept] static void Branch_MethodParameterValueNode (Type T) { - var expr = Expression.New (T); + Expression.New (T); } [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [Kept] static void Branch_UnrecognizedPatterns () { - var expr = Expression.New (Type.GetType ("T1")); - expr = Expression.New (GetType ()); + Expression.New (Type.GetType ("RemovedType")); + Expression.New (GetType ()); } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs index d8efc3c1d45c1a..af31e2d9ecf1ae 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs @@ -36,6 +36,32 @@ class Foo [KeptBackingField] private int TestName1 { [Kept] get; } + [Kept] + [KeptBackingField] + private int TestName2 { [Kept] get; } + + private int TestName3 { get; } + + private int TestName4 { get; } + + private int TestName5 { get; } + + [Kept] + class A + { + [Kept] + [KeptBackingField] + static int Foo { [Kept] get; } + } + + [Kept] + class B + { + [Kept] + [KeptBackingField] + static int Foo { [Kept] get; } + } + [Kept] private string UnknownString () { @@ -45,7 +71,46 @@ private string UnknownString () [Kept] public void Branch_SystemTypeValueNode_KnownStringValue_NonStatic () { - var expr = Expression.Property (Expression.Parameter (typeof (int), "somename"), typeof (Foo), "TestName1"); + TestPropertyName (0); + TestPropertyName (1); + TestType (0); + TestType (1); + } + + [Kept] + static void TestPropertyName (int i) + { + string PropertyName = string.Empty; + switch (i) { + case 0: + PropertyName = "TestName1"; + break; + case 1: + PropertyName = "TestName2"; + break; + default: + break; + } + + Expression.Property (Expression.Parameter (typeof (int), "somename"), typeof (Foo), PropertyName); + } + + [Kept] + static void TestType (int i) + { + Type T = (Type)null; + switch (i) { + case 0: + T = typeof (A); + break; + case 1: + T = typeof (B); + break; + default: + break; + } + + Expression.Property (null, T, "Foo"); } [Kept] @@ -68,7 +133,7 @@ public void Branch_SystemTypeValueNode_UnknownStringValue () [Kept] public void Branch_NullValueNode () { - var expr = Expression.Property (null, UnknownString () == "unknownstring" ? null : typeof (Foo), "TestName1"); + var expr = Expression.Property (null, (Type)null, "TestName3"); } [UnrecognizedReflectionAccessPattern ( @@ -76,7 +141,7 @@ public void Branch_NullValueNode () [Kept] public void Branch_MethodParameterValueNode (Type T, string s) { - var expr = Expression.Property (null, T, "TestName1"); + var expr = Expression.Property (null, T, "TestName4"); expr = Expression.Property (null, typeof (Foo), s); } @@ -85,7 +150,7 @@ public void Branch_MethodParameterValueNode (Type T, string s) [Kept] public void Branch_UnrecognizedPatterns () { - var expr = Expression.Property (null, Type.GetType ("Foo"), "TestName1"); + var expr = Expression.Property (null, Type.GetType ("Foo"), "TestName5"); } } } From c01ef4a79b5abcab5a15b365779c4adb27e44c70 Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Thu, 2 Apr 2020 14:38:04 -0700 Subject: [PATCH 6/8] Annotate all patterns Commit migrated from https://github.com/dotnet/linker/commit/94da2095c38ed1d0a46869f34a8a0cefa7115613 --- .../src/linker/Linker.Steps/MarkStep.cs | 108 +++++++------- ...ognizedReflectionAccessPatternAttribute.cs | 2 +- .../Reflection/ExpressionCallString.cs | 68 +++++---- .../Reflection/ExpressionFieldString.cs | 128 +++++++++++------ .../Reflection/ExpressionNewType.cs | 73 ++++++---- .../Reflection/ExpressionPropertyString.cs | 135 +++++++++++------- .../TestCasesRunner/TestCaseMetadaProvider.cs | 37 ++--- 7 files changed, 322 insertions(+), 229 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index e25dba452772c3..a01e10274d94dd 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3538,6 +3538,8 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c } else { MarkFieldsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, staticOnly); } + } else if (stringParam is NullValue) { + reflectionContext.RecordHandledPattern (); } else if (stringParam is MethodParameterValue) { // TODO: Check if parameter is annotated. reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); @@ -3788,6 +3790,60 @@ void MarkMethodsFromReflectionCall (ref ReflectionPatternContext reflectionConte } } + void MarkPropertiesFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, bool staticOnly = false) + { + bool foundMatch = false; + foreach (var property in declaringType.Properties) { + if (property.Name != name) + continue; + + bool markedAny = false; + var methodCalling = reflectionContext.MethodCalling; + + // It is not easy to reliably detect in the IL code whether the getter or setter (or both) are used. + // Be conservative and mark everything for the property. + var getter = property.GetMethod; + if (getter != null && (!staticOnly || staticOnly && getter.IsStatic)) { + reflectionContext.RecordRecognizedPattern (getter, () => _markStep.MarkIndirectlyCalledMethod (getter, new DependencyInfo (DependencyKind.AccessedViaReflection, methodCalling))); + markedAny = true; + } + + var setter = property.SetMethod; + if (setter != null && (!staticOnly || staticOnly && setter.IsStatic)) { + reflectionContext.RecordRecognizedPattern (setter, () => _markStep.MarkIndirectlyCalledMethod (setter, new DependencyInfo (DependencyKind.AccessedViaReflection, methodCalling))); + markedAny = true; + } + + if (markedAny) { + foundMatch = true; + reflectionContext.RecordRecognizedPattern (property, () => _markStep.MarkProperty (property, new DependencyInfo (DependencyKind.AccessedViaReflection, methodCalling))); + } + } + + if (!foundMatch) + reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve property `{name}` on type `{declaringType.FullName}`."); + } + + void MarkFieldsFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, bool staticOnly = false) + { + bool foundMatch = false; + var methodCalling = reflectionContext.MethodCalling; + foreach (var field in declaringType.Fields) { + if (field.Name != name) + continue; + + if (staticOnly && !field.IsStatic) + continue; + + foundMatch = true; + reflectionContext.RecordRecognizedPattern (field, () => _markStep.MarkField (field, new DependencyInfo (DependencyKind.AccessedViaReflection, methodCalling))); + break; + } + + if (!foundMatch) + reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve field `{name}` on type `{declaringType.FullName}`."); + } + string GetValueDescriptionForErrorMessage (ValueNode value) { switch (value) { @@ -3867,58 +3923,6 @@ string GetDynamicallyAccessedMemberKindsDescription (DynamicallyAccessedMemberKi return string.Join (" | ", results.Select (r => r.ToString ())); } - - void MarkPropertiesFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, bool staticOnly = false) - { - bool foundMatch = false; - foreach (var property in declaringType.Properties) { - if (property.Name != name) - continue; - - bool markedAny = false; - - // It is not easy to reliably detect in the IL code whether the getter or setter (or both) are used. - // Be conservative and mark everything for the property. - var getter = property.GetMethod; - if (getter != null && (!staticOnly || staticOnly && getter.IsStatic)) { - reflectionContext.RecordRecognizedPattern (getter, () => _markStep.MarkIndirectlyCalledMethod (getter)); - markedAny = true; - } - - var setter = property.SetMethod; - if (setter != null && (!staticOnly || staticOnly && setter.IsStatic)) { - reflectionContext.RecordRecognizedPattern (setter, () => _markStep.MarkIndirectlyCalledMethod (setter)); - markedAny = true; - } - - if (markedAny) { - foundMatch = true; - reflectionContext.RecordRecognizedPattern (property, () => _markStep.MarkProperty (property)); - } - } - - if (!foundMatch) - reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve property `{name}` on type `{declaringType.FullName}`."); - } - - void MarkFieldsFromReflectionCall (ref ReflectionPatternContext reflectionContext, TypeDefinition declaringType, string name, bool staticOnly = false) - { - bool foundMatch = false; - foreach (var field in declaringType.Fields) { - if (field.Name != name) - continue; - - if (staticOnly && !field.IsStatic) - continue; - - foundMatch = true; - reflectionContext.RecordRecognizedPattern (field, () => _markStep.MarkField (field)); - break; - } - - if (!foundMatch) - reflectionContext.RecordUnrecognizedPattern ($"Reflection call '{reflectionContext.MethodCalled.FullName}' inside '{reflectionContext.MethodCalling.FullName}' could not resolve field `{name}` on type `{declaringType.FullName}`."); - } } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/RecognizedReflectionAccessPatternAttribute.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/RecognizedReflectionAccessPatternAttribute.cs index f7e54e71ffce3d..1edaed3f24018f 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/RecognizedReflectionAccessPatternAttribute.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases.Expectations/Assertions/RecognizedReflectionAccessPatternAttribute.cs @@ -28,7 +28,7 @@ public RecognizedReflectionAccessPatternAttribute (Type reflectionMethodType, st } public RecognizedReflectionAccessPatternAttribute (Type reflectionMethodType, string reflectionMethodName, Type [] reflectionMethodParameters, - Type accessedItemType, string accessedItemName, string [] accessedItemParameters) + Type accessedItemType, string accessedItemName, string [] accessedItemParameters = null) { if (reflectionMethodType == null) throw new ArgumentException ("Value cannot be null or empty.", nameof (reflectionMethodType)); diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs index e5eec7b3575b2c..0d9dd5037d81b1 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs @@ -30,6 +30,26 @@ static void Branch_SystemTypeValueNode_KnownStringValue () TestNonExistingName (); } + [Kept] + static void Branch_SystemTypeValueNode_NullValueNode () + { + Expression.Call (typeof (ExpressionCallString), null, Type.EmptyTypes); + } + + [Kept] + static void Branch_NullValueNode () + { + Expression.Call ((Type)null, "OnlyCalledViaExpression", Type.EmptyTypes); + } + + [Kept] + static void Branch_MethodParameterValueNode (Type T, string s) + { + TestNonExistingTypeParameter (T); + TestNonExistingNameParameter (s); + } + + #region RecognizedReflectionAccessPatterns [RecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) }, typeof (ExpressionCallString), nameof (A), new Type [0])] @@ -39,7 +59,7 @@ static void Branch_SystemTypeValueNode_KnownStringValue () [Kept] static void TestByName (int i) { - string MethodName = string.Empty; + string MethodName = null; switch (i) { case 0: MethodName = "A"; @@ -51,7 +71,7 @@ static void TestByName (int i) break; } - Expression.Call (typeof (ExpressionCallString), MethodName, Type.EmptyTypes); + Expression.Call (typeof (ExpressionCallString), MethodName, null); } [RecognizedReflectionAccessPattern ( @@ -87,33 +107,9 @@ static void TestByNameWithParameters () IQueryable source = null; Expression.Call (typeof (ExpressionCallString), "Count", new Type [] { source.ElementType }, source.Expression); } + #endregion - [Kept] - static void Branch_SystemTypeValueNode_NullValueNode () - { - Expression.Call (typeof (ExpressionCallString), null, Type.EmptyTypes); - } - - [UnrecognizedReflectionAccessPattern ( - typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] - [Kept] - static void TestNonExistingName () - { - Expression.Call (typeof (ExpressionCallString), "NonExisting", Type.EmptyTypes); - } - - [Kept] - static void Branch_NullValueNode () - { - Expression.Call ((Type)null, "OnlyCalledViaExpression", Type.EmptyTypes); - } - - [Kept] - static Type FindType () - { - return typeof (ExpressionCallString); - } - + #region UnrecognizedReflectionAccessPatterns [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] [Kept] @@ -122,11 +118,12 @@ static void Branch_UnrecognizedPatterns () Expression.Call (FindType (), "OnlyCalledViaExpression", Type.EmptyTypes); } + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] [Kept] - static void Branch_MethodParameterValueNode (Type T, string s) + static void TestNonExistingName () { - TestNonExistingTypeParameter (T); - TestNonExistingNameParameter (s); + Expression.Call (typeof (ExpressionCallString), "NonExisting", Type.EmptyTypes); } [UnrecognizedReflectionAccessPattern ( @@ -144,6 +141,14 @@ static void TestNonExistingNameParameter (string s) { Expression.Call (typeof (ExpressionCallString), s, Type.EmptyTypes); } + #endregion + + #region Helpers + [Kept] + static Type FindType () + { + return typeof (ExpressionCallString); + } [Kept] static void A () { } @@ -170,5 +175,6 @@ protected static T Count (T t) { return default (T); } + #endregion } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs index 2e2181259ec599..fe31e9ae599fa8 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs @@ -12,68 +12,54 @@ public static void Main () { Branch_SystemTypeValueNode_KnownStringValue_NonStatic (); Branch_SystemTypeValueNode_KnownStringValue_SaticOnly (); - Branch_SystemTypeValueNode_UnknownStringValue (); Branch_NullValueNode (); + Branch_SystemTypeValueNode_UnknownStringValue (); Branch_MethodParameterValueNode (typeof (ExpressionFieldString), "Foo"); Branch_UnrecognizedPatterns (); } [Kept] - private static int TestOnlyStatic1; - - private int TestOnlyStatic2; - - [Kept] - private int TestName1; - - [Kept] - private int TestName2; - - private int TestName3; - - private int TestName4; - - private int TestName5; - - [Kept] - class A - { - [Kept] - static int Foo; - } - - [Kept] - class B + static void Branch_SystemTypeValueNode_KnownStringValue_NonStatic () { - [Kept] - static int Foo; + TestFieldName (0); + TestFieldName (1); + TestType (0); + TestType (1); + StaticFieldExpected (); } [Kept] - static string UnknownString () + static void Branch_NullValueNode () { - return "unknownstring"; + var expr = Expression.Field (null, (Type)null, "TestName1"); } + #region RecognizedReflectionAccessPatterns + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (ExpressionFieldString), nameof (TestOnlyStatic1))] [Kept] - static void Branch_SystemTypeValueNode_KnownStringValue_NonStatic () + static void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () { - TestFieldName (0); - TestFieldName (1); - TestType (0); - TestType (1); + var expr = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic1"); } + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (ExpressionFieldString), nameof (TestName2))] + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (ExpressionFieldString), nameof (TestName3))] [Kept] static void TestFieldName (int i) { - string FieldName = string.Empty; + string FieldName = null; switch (i) { case 0: - FieldName = "TestName1"; + FieldName = "TestName2"; break; case 1: - FieldName = "TestName2"; + FieldName = "TestName3"; break; default: break; @@ -82,6 +68,12 @@ static void TestFieldName (int i) Expression.Field (Expression.Parameter (typeof (int), "somename"), typeof (ExpressionFieldString), FieldName); } + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (A), "Foo")] + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (B), "Foo")] [Kept] static void TestType (int i) { @@ -99,14 +91,18 @@ static void TestType (int i) Expression.Field (null, T, "Foo"); } + #endregion + #region UnrecognizedReflectionAccessPatterns + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] - static void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () + static void StaticFieldExpected () { - var expr = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic1"); - expr = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic2"); + var expr = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic2"); } + [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] @@ -115,12 +111,8 @@ static void Branch_SystemTypeValueNode_UnknownStringValue () var expr = Expression.Field (null, typeof (ExpressionFieldString), UnknownString ()); } - [Kept] - static void Branch_NullValueNode () - { - var expr = Expression.Field (null, (Type)null, "TestName3"); - } - + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] @@ -130,6 +122,8 @@ static void Branch_MethodParameterValueNode (Type T, string s) expr = Expression.Field (null, typeof (ExpressionFieldString), s); } + [UnrecognizedReflectionAccessPattern ( + typeof (Type), nameof (Type.GetType), new Type [] { typeof (string) })] [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] @@ -137,5 +131,45 @@ static void Branch_UnrecognizedPatterns () { var expr = Expression.Field (null, Type.GetType ("Foo"), "TestName5"); } + #endregion + + #region Helpers + [Kept] + private static int TestOnlyStatic1; + + private int TestOnlyStatic2; + + private int TestName1; + + [Kept] + private int TestName2; + + [Kept] + private int TestName3; + + private int TestName4; + + private int TestName5; + + [Kept] + class A + { + [Kept] + static int Foo; + } + + [Kept] + class B + { + [Kept] + static int Foo; + } + + [Kept] + static string UnknownString () + { + return "unknownstring"; + } + #endregion } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs index fbde31c6f218bd..522e6ea32136a9 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionNewType.cs @@ -20,33 +20,16 @@ public static void Main () } [Kept] - class A - { - [Kept] - A () { } - } - - [Kept] - class B - { - [Kept] - B () { } - } - - [Kept] - class C { } - - [Kept] - class D { } - - class RemovedType { } - - [Kept] - static Type GetType () + static void Branch_NullValueNode () { - return typeof (D); + Expression.New (5 + 7 == 12 ? null : typeof (RemovedType)); } + #region RecognizedReflectionAccessPatterns + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) }, typeof (A), ".ctor", new Type [0])] + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) }, typeof (B), ".ctor", new Type [0])] [Kept] static void Branch_SystemTypeValueNode (int i) { @@ -64,13 +47,9 @@ static void Branch_SystemTypeValueNode (int i) Expression.New (T); } + #endregion - [Kept] - static void Branch_NullValueNode () - { - Expression.New (5 + 7 == 12 ? null : typeof (RemovedType)); - } - + #region UnrecognizedReflectionAccessPatterns [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [Kept] static void Branch_MethodParameterValueNode (Type T) @@ -78,6 +57,9 @@ static void Branch_MethodParameterValueNode (Type T) Expression.New (T); } + [UnrecognizedReflectionAccessPattern ( + typeof (Type), nameof (Type.GetType), new Type [] { typeof (string) })] + [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [UnrecognizedReflectionAccessPattern (typeof (Expression), nameof (Expression.New), new Type [] { typeof (Type) })] [Kept] static void Branch_UnrecognizedPatterns () @@ -85,5 +67,36 @@ static void Branch_UnrecognizedPatterns () Expression.New (Type.GetType ("RemovedType")); Expression.New (GetType ()); } + #endregion + + #region Helpers + [Kept] + class A + { + [Kept] + A () { } + } + + [Kept] + class B + { + [Kept] + B () { } + } + + [Kept] + class C { } + + [Kept] + class D { } + + class RemovedType { } + + [Kept] + static Type GetType () + { + return typeof (D); + } + #endregion } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs index af31e2d9ecf1ae..45ab976b585647 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs @@ -27,66 +27,47 @@ public static void Main () class Foo { [Kept] - [KeptBackingField] - private static int TestOnlyStatic1 { [Kept] get; [Kept] set; } - - private int TestOnlyStatic2 { get; } - - [Kept] - [KeptBackingField] - private int TestName1 { [Kept] get; } - - [Kept] - [KeptBackingField] - private int TestName2 { [Kept] get; } - - private int TestName3 { get; } - - private int TestName4 { get; } - - private int TestName5 { get; } - - [Kept] - class A - { - [Kept] - [KeptBackingField] - static int Foo { [Kept] get; } - } - - [Kept] - class B + public void Branch_SystemTypeValueNode_KnownStringValue_NonStatic () { - [Kept] - [KeptBackingField] - static int Foo { [Kept] get; } + TestPropertyName (0); + TestPropertyName (1); + TestByType (0); + TestByType (1); + StaticPropertyExpected (); } [Kept] - private string UnknownString () + public void Branch_NullValueNode () { - return "unknownstring"; + var expr = Expression.Property (null, (Type)null, "TestName1"); } + #region RecognizedReflectionAccessPattern + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (Foo), nameof (TestOnlyStatic1))] [Kept] - public void Branch_SystemTypeValueNode_KnownStringValue_NonStatic () + public void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () { - TestPropertyName (0); - TestPropertyName (1); - TestType (0); - TestType (1); + var expr = Expression.Property (null, typeof (Foo), "TestOnlyStatic1"); } + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (Foo), nameof (TestName2))] + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (Foo), nameof (TestName3))] [Kept] static void TestPropertyName (int i) { - string PropertyName = string.Empty; + string PropertyName = null; switch (i) { case 0: - PropertyName = "TestName1"; + PropertyName = "TestName2"; break; case 1: - PropertyName = "TestName2"; + PropertyName = "TestName3"; break; default: break; @@ -95,8 +76,14 @@ static void TestPropertyName (int i) Expression.Property (Expression.Parameter (typeof (int), "somename"), typeof (Foo), PropertyName); } + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (A), "Foo")] + [RecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, + typeof (B), "Foo")] [Kept] - static void TestType (int i) + static void TestByType (int i) { Type T = (Type)null; switch (i) { @@ -112,12 +99,15 @@ static void TestType (int i) Expression.Property (null, T, "Foo"); } + #endregion + #region UnrecognizedReflectionAccessPatterns + [UnrecognizedReflectionAccessPattern ( + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] - public void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () + public void StaticPropertyExpected () { - var expr = Expression.Property (null, typeof (Foo), "TestOnlyStatic1"); - expr = Expression.Property (null, typeof (Foo), "TestOnlyStatic2"); + var expr = Expression.Property (null, typeof (Foo), "TestOnlyStatic2"); } [UnrecognizedReflectionAccessPattern ( @@ -130,12 +120,6 @@ public void Branch_SystemTypeValueNode_UnknownStringValue () [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] - [Kept] - public void Branch_NullValueNode () - { - var expr = Expression.Property (null, (Type)null, "TestName3"); - } - [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] @@ -145,6 +129,8 @@ public void Branch_MethodParameterValueNode (Type T, string s) expr = Expression.Property (null, typeof (Foo), s); } + [UnrecognizedReflectionAccessPattern ( + typeof (Type), nameof (Type.GetType), new Type [] { typeof (string) })] [UnrecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [Kept] @@ -152,6 +138,51 @@ public void Branch_UnrecognizedPatterns () { var expr = Expression.Property (null, Type.GetType ("Foo"), "TestName5"); } + #endregion + + #region Helpers + [Kept] + class A + { + [Kept] + [KeptBackingField] + static int Foo { [Kept] get; } + } + + [Kept] + class B + { + [Kept] + [KeptBackingField] + static int Foo { [Kept] get; } + } + + [Kept] + [KeptBackingField] + private static int TestOnlyStatic1 { [Kept] get; [Kept] set; } + + private int TestOnlyStatic2 { get; } + + private int TestName1 { get; } + + [Kept] + [KeptBackingField] + private int TestName2 { [Kept] get; } + + [Kept] + [KeptBackingField] + private int TestName3 { [Kept] get; } + + private int TestName4 { get; } + + private int TestName5 { get; } + + [Kept] + private string UnknownString () + { + return "unknownstring"; + } + #endregion } } } \ No newline at end of file diff --git a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs index 5e2964897933d6..edda8ac2f407b2 100644 --- a/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs +++ b/src/tools/illink/test/Mono.Linker.Tests/TestCasesRunner/TestCaseMetadaProvider.cs @@ -86,22 +86,7 @@ public virtual void CustomizeLinker (LinkerDriver linker, LinkerCustomizations c }; } - if (_testCaseTypeDefinition.CustomAttributes.Any (attr => - attr.AttributeType.Name == nameof (VerifyAllReflectionAccessPatternsAreValidatedAttribute)) - || _testCaseTypeDefinition.AllMethods ().Any (method => method.CustomAttributes.Any (attr => - attr.AttributeType.Name == nameof (RecognizedReflectionAccessPatternAttribute) || - attr.AttributeType.Name == nameof (UnrecognizedReflectionAccessPatternAttribute)))) { - customizations.ReflectionPatternRecorder = new TestReflectionPatternRecorder (); - customizations.CustomizeContext += context => { - context.ReflectionPatternRecorder = customizations.ReflectionPatternRecorder; - }; - } else if (_testCaseTypeDefinition.HasNestedTypes - && _testCaseTypeDefinition.NestedTypes.Any (nestedType => - nestedType.CustomAttributes.Any (attr => - attr.AttributeType.Name == nameof (VerifyAllReflectionAccessPatternsAreValidatedAttribute) - || _testCaseTypeDefinition.AllMethods ().Any (method => method.CustomAttributes.Any (attr => - attr.AttributeType.Name == nameof (RecognizedReflectionAccessPatternAttribute) || - attr.AttributeType.Name == nameof (UnrecognizedReflectionAccessPatternAttribute)))))) { + if (ValidatesReflectionAccessPatterns(_testCaseTypeDefinition)) { customizations.ReflectionPatternRecorder = new TestReflectionPatternRecorder (); customizations.CustomizeContext += context => { context.ReflectionPatternRecorder = customizations.ReflectionPatternRecorder; @@ -109,6 +94,26 @@ public virtual void CustomizeLinker (LinkerDriver linker, LinkerCustomizations c } } + private bool ValidatesReflectionAccessPatterns (TypeDefinition testCaseTypeDefinition) + { + if (testCaseTypeDefinition.HasNestedTypes) { + var nestedTypes = new Queue (testCaseTypeDefinition.NestedTypes.ToList ()); + while (nestedTypes.Count > 0) { + if (ValidatesReflectionAccessPatterns (nestedTypes.Dequeue ())) + return true; + } + } + + if (testCaseTypeDefinition.CustomAttributes.Any (attr => + attr.AttributeType.Name == nameof (VerifyAllReflectionAccessPatternsAreValidatedAttribute)) + || testCaseTypeDefinition.AllMethods ().Any (method => method.CustomAttributes.Any (attr => + attr.AttributeType.Name == nameof (RecognizedReflectionAccessPatternAttribute) || + attr.AttributeType.Name == nameof (UnrecognizedReflectionAccessPatternAttribute)))) + return true; + + return false; + } + #if NETCOREAPP public static IEnumerable GetTrustedPlatformAssemblies () { From 28be4b9c4fc93b00046f8848a3f1697094f6fd7f Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Fri, 3 Apr 2020 11:38:23 -0700 Subject: [PATCH 7/8] Update mark logic for Expression.* Commit migrated from https://github.com/dotnet/linker/commit/427ac40d9ad2e8ea761431fca3142ac948aa6100 --- .../src/linker/Linker.Steps/MarkStep.cs | 38 ++++++------------- .../Reflection/ExpressionCallString.cs | 5 ++- .../Reflection/ExpressionFieldString.cs | 2 + .../Reflection/ExpressionPropertyString.cs | 2 + 4 files changed, 18 insertions(+), 29 deletions(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index ebbce5bd44c6c1..69b42d95ab2675 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -2823,9 +2823,6 @@ public void Process (ref ReflectionPatternContext reflectionContext) // System.Reflection.RuntimeReflectionExtensions // case "RuntimeReflectionExtensions" when methodCalledType.Namespace == "System.Reflection": - Instruction second_argument; - TypeDefinition declaringType; - switch (methodCalled.Name) { // // static GetRuntimeField (this Type type, string name) @@ -3492,16 +3489,12 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c foreach (var value in methodParams [0].UniqueValues ()) { if (value is SystemTypeValue systemTypeValue) { foreach (var stringParam in methodParams [1].UniqueValues ()) { - if (stringParam is KnownStringValue stringValue) { + // TODO: Change this as needed after deciding whether or not we are to keep + // all methods on a type that was accessed via reflection. + if (stringParam is KnownStringValue stringValue) MarkMethodsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - } else if (stringParam is NullValue) { - reflectionContext.RecordHandledPattern (); - } else if (stringParam is MethodParameterValue) { - // TODO: Check if parameter is annotated. - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); - } else { + else reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 2nd argument which cannot be analyzed"); - } } } else if (value == NullValue.Instance) { reflectionContext.RecordHandledPattern (); @@ -3532,16 +3525,12 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c foreach (var stringParam in methodParams [2].UniqueValues ()) { if (stringParam is KnownStringValue stringValue) { bool staticOnly = methodParams [0].Kind == ValueNodeKind.Null; - if (calledMethod.Name [0] == 'P') { + // TODO: Change this as needed after deciding if we are to keep all fields/properties on a type + // that is accessed via reflection. For now, let's only keep the field/property that is retrieved. + if (calledMethod.Name [0] == 'P') MarkPropertiesFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, staticOnly); - } else { + else MarkFieldsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, stringValue.Contents, staticOnly); - } - } else if (stringParam is NullValue) { - reflectionContext.RecordHandledPattern (); - } else if (stringParam is MethodParameterValue) { - // TODO: Check if parameter is annotated. - reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); } else { reflectionContext.RecordUnrecognizedPattern ($"Expression call '{calledMethod.FullName}' inside '{callingMethodBody.Method.FullName}' was detected with 3rd argument which cannot be analyzed"); } @@ -3569,16 +3558,11 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c reflectionContext.AnalyzingPattern(); - foreach (var value in methodParams[0].UniqueValues()) - { + foreach (var value in methodParams [0].UniqueValues ()) { if (value is SystemTypeValue systemTypeValue) - { - MarkMethodsFromReflectionCall(ref reflectionContext, systemTypeValue.TypeRepresented, ".ctor", BindingFlags.Instance, parametersCount: 0); - } + MarkMethodsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, ".ctor", BindingFlags.Instance, parametersCount: 0); else - { - RequireDynamicallyAccessedMembers(ref reflectionContext, DynamicallyAccessedMemberKinds.DefaultConstructor, value, calledMethod.Parameters[0]); - } + RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberKinds.DefaultConstructor, value, calledMethod.Parameters [0]); } } break; diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs index 374dd1e5da7abe..41d9a82f83afbd 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionCallString.cs @@ -31,8 +31,6 @@ static void Branch_SystemTypeValueNode_KnownStringValue () TestByType (1); TestByNameWithParameters (); TestNonExistingName (); - TestNullType (); - TestDataFlowType (); } [Kept] @@ -55,6 +53,8 @@ static void Branch_MethodParameterValueNode (Type T, string s) } #region RecognizedReflectionAccessPatterns + [UnrecognizedReflectionAccessPattern ( // Expression.Call (Type, null, Type []); + typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) })] [RecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Call), new Type [] { typeof (Type), typeof (string), typeof (Type []), typeof (Expression []) }, typeof (ExpressionCallString), nameof (A), new Type [0])] @@ -212,5 +212,6 @@ protected static void ProtectedOnBase () class ADerived : ABase { } + #endregion } } diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs index c93097b4573f46..d7564a27c1145f 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionFieldString.cs @@ -47,6 +47,8 @@ static void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () var expr = Expression.Field (null, typeof (ExpressionFieldString), "TestOnlyStatic1"); } + [UnrecognizedReflectionAccessPattern ( // Expression.Field (Expression, Type, null); + typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [RecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Field), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, typeof (ExpressionFieldString), nameof (TestName2))] diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs index 44381b983817de..daebe109395bd7 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/Reflection/ExpressionPropertyString.cs @@ -55,6 +55,8 @@ public void Branch_SystemTypeValueNode_KnownStringValue_SaticOnly () var expr = Expression.Property (null, typeof (Foo), "TestOnlyStatic1"); } + [UnrecognizedReflectionAccessPattern ( // Expression.Property (Expression, Type, null); + typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) })] [RecognizedReflectionAccessPattern ( typeof (Expression), nameof (Expression.Property), new Type [] { typeof (Expression), typeof (Type), typeof (string) }, typeof (Foo), nameof (TestName2))] From 0aa68a83ed49690eb7bd59ae3f87ac8757e89d77 Mon Sep 17 00:00:00 2001 From: Mateo Torres Ruiz Date: Mon, 6 Apr 2020 10:23:24 -0700 Subject: [PATCH 8/8] Add Public and NonPublic to the Expression.New binding flags Commit migrated from https://github.com/dotnet/linker/commit/2f568e0a7717a1183841f6d3ba58970fd8a3dcec --- src/tools/illink/src/linker/Linker.Steps/MarkStep.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index 69b42d95ab2675..df2f1988a42895 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -3560,7 +3560,7 @@ public override bool HandleCall (MethodBody callingMethodBody, MethodReference c foreach (var value in methodParams [0].UniqueValues ()) { if (value is SystemTypeValue systemTypeValue) - MarkMethodsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, ".ctor", BindingFlags.Instance, parametersCount: 0); + MarkMethodsFromReflectionCall (ref reflectionContext, systemTypeValue.TypeRepresented, ".ctor", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, parametersCount: 0); else RequireDynamicallyAccessedMembers (ref reflectionContext, DynamicallyAccessedMemberKinds.DefaultConstructor, value, calledMethod.Parameters [0]); }