diff options
author | Marek Safar <marek.safar@gmail.com> | 2019-10-04 19:31:40 +0300 |
---|---|---|
committer | Marek Safar <marek.safar@gmail.com> | 2019-10-07 12:39:34 +0300 |
commit | ab3667782f32459bd44bcea906b4a16b151a4b5a (patch) | |
tree | 3d13bf4d8db81cc0b86762db0e9290a190ae885d | |
parent | e8fea0e48e63e3e5706246b28efd6ef935c5c58c (diff) |
Add simple detection for custom TypeConvertors
Contributes to #153
6 files changed, 163 insertions, 27 deletions
diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index f91f7a9c1..8a067acf4 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -1141,19 +1141,24 @@ namespace Mono.Linker.Steps { return; foreach (CustomAttribute attribute in type.CustomAttributes) { - switch (attribute.Constructor.DeclaringType.FullName) { - case "System.Xml.Serialization.XmlSchemaProviderAttribute": + var attrType = attribute.Constructor.DeclaringType; + switch (attrType.Name) { + case "XmlSchemaProviderAttribute" when attrType.Namespace == "System.Xml.Serialization": MarkXmlSchemaProvider (type, attribute); break; - case "System.Diagnostics.DebuggerDisplayAttribute": + case "DebuggerDisplayAttribute" when attrType.Namespace == "System.Diagnostics": MarkTypeWithDebuggerDisplayAttribute (type, attribute); break; - case "System.Diagnostics.DebuggerTypeProxyAttribute": + case "DebuggerTypeProxyAttribute" when attrType.Namespace == "System.Diagnostics": MarkTypeWithDebuggerTypeProxyAttribute (type, attribute); break; - case "System.Diagnostics.Tracing.EventDataAttribute": + case "EventDataAttribute" when attrType.Namespace == "System.Diagnostics.Tracing": MarkMethodsIf (type.Methods, IsPublicInstancePropertyMethod); break; + case "TypeConverterAttribute" when attrType.Namespace == "System.ComponentModel": + // The attribute can be applied anywhere but in reality it's always associated with type + MarkTypeConverterDependency (attribute); + break; } } } @@ -1181,6 +1186,30 @@ namespace Mono.Linker.Steps { MarkNamedMethod (type, method_name); } + void MarkTypeConverterDependency (CustomAttribute attribute) + { + var args = attribute.ConstructorArguments; + if (args.Count < 1) + return; + + TypeDefinition tdef = null; + switch (attribute.ConstructorArguments [0].Value) { + case string s: + tdef = ResolveFullyQualifiedTypeName (s); + break; + case TypeReference type: + tdef = type.Resolve (); + break; + } + + if (tdef == null) + return; + + MarkMethodsIf (tdef.Methods, l => + l.IsDefaultConstructor () || + l.Parameters.Count == 1 && l.Parameters [0].ParameterType.IsTypeOf ("System", "Type")); + } + void MarkTypeWithDebuggerDisplayAttribute (TypeDefinition type, CustomAttribute attribute) { if (_context.KeepMembersForDebugger) { @@ -1540,6 +1569,25 @@ namespace Mono.Linker.Steps { return td; } + TypeDefinition ResolveFullyQualifiedTypeName (string name) + { + if (!TypeNameParser.TryParseTypeAssemblyQualifiedName (name, out string typeName, out string assemblyName)) + return null; + + foreach (var assemblyDefinition in _context.GetAssemblies ()) { + if (assemblyName != null && assemblyDefinition.Name.Name != assemblyName) + continue; + + var foundType = assemblyDefinition.MainModule.GetType (typeName); + if (foundType == null) + continue; + + return foundType; + } + + return null; + } + protected TypeReference GetOriginalType (TypeReference type) { while (type is TypeSpecification) { @@ -2369,21 +2417,7 @@ namespace Mono.Linker.Steps { continue; } - var name = (string)first_arg.Operand; - - if (!TypeNameParser.TryParseTypeAssemblyQualifiedName (name, out string typeName, out string assemblyName)) - continue; - - TypeDefinition foundType = null; - foreach (var assemblyDefinition in _context.GetAssemblies ()) { - if (assemblyName != null && assemblyDefinition.Name.Name != assemblyName) - continue; - - foundType = assemblyDefinition.MainModule.GetType (typeName); - if (foundType != null) - break; - } - + TypeDefinition foundType = ResolveFullyQualifiedTypeName ((string) first_arg.Operand); if (foundType == null) continue; diff --git a/src/linker/Linker/TypeReferenceExtensions.cs b/src/linker/Linker/TypeReferenceExtensions.cs index 13d9db7aa..ae271a0d4 100644 --- a/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/linker/Linker/TypeReferenceExtensions.cs @@ -231,5 +231,11 @@ namespace Mono.Linker throw new NotImplementedException (); } + + public static bool IsTypeOf (this TypeReference type, string ns, string name) + { + return type.Name == name + && type.Namespace == ns; + } } } diff --git a/test/Mono.Linker.Tests.Cases/ComponentModel/CustomTypeConvertor.cs b/test/Mono.Linker.Tests.Cases/ComponentModel/CustomTypeConvertor.cs new file mode 100644 index 000000000..4f94ed07e --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/ComponentModel/CustomTypeConvertor.cs @@ -0,0 +1,68 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.ComponentModel +{ + [TypeConverter (typeof (Custom1))] + + [Kept] + [KeptAttributeAttribute (typeof (TypeConverterAttribute))] + class CustomDataType + { + [Kept] + [KeptBaseType (typeof (TypeConverter))] + class Custom1 : TypeConverter + { + [Kept] + public Custom1 (Type type) + { + } + + [Kept] + public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) + { + return "test"; + } + } + } + + [TypeConverter ("Mono.Linker.Tests.Cases.ComponentModel.CustomDataType_2/Custom2")] + + [Kept] + [KeptAttributeAttribute (typeof (TypeConverterAttribute))] + class CustomDataType_2 + { + [Kept] + [KeptBaseType (typeof (TypeConverter))] + class Custom2 : TypeConverter + { + [Kept] + public Custom2 () + { + } + + [Kept] + public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) + { + return "test"; + } + } + } + + [Reference ("System.dll")] + public class CustomTypeConvertor + { + public static void Main () + { + var tc1 = TypeDescriptor.GetConverter (typeof (CustomDataType)); + var res1 = tc1.ConvertFromString ("from"); + + var tc2 = TypeDescriptor.GetConverter (typeof (CustomDataType_2)); + var res2 = tc2.ConvertFromString ("from"); + + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs b/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs index 93c7eeb5c..07a01b1ae 100644 --- a/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs +++ b/test/Mono.Linker.Tests.Cases/Reflection/TypeUsedViaReflection.cs @@ -11,7 +11,7 @@ namespace Mono.Linker.Tests.Cases.Reflection { TestEmptyString (); TestFullString (); TestGenericString (); - TestFullStringConst(); + TestFullStringConst (); TestTypeAsmName (); TestType (); TestPointer (); @@ -21,6 +21,7 @@ namespace Mono.Linker.Tests.Cases.Reflection { TestMultiDimensionalArray (); TestMultiDimensionalArrayFullString (); TestMultiDimensionalArrayAsmName (); + TestDeeplyNested (); } [Kept] @@ -61,10 +62,10 @@ namespace Mono.Linker.Tests.Cases.Reflection { public class FullConst { } [Kept] - public static void TestFullStringConst() + public static void TestFullStringConst () { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+FullConst, test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; - var typeKept = Type.GetType(reflectionTypeKeptString, false); + var typeKept = Type.GetType (reflectionTypeKeptString, false); } [Kept] @@ -118,7 +119,7 @@ namespace Mono.Linker.Tests.Cases.Reflection { } [Kept] - public class ArrayOfArray{ } + public class ArrayOfArray { } [Kept] public static void TestArrayOfArray () @@ -129,7 +130,7 @@ namespace Mono.Linker.Tests.Cases.Reflection { [Kept] - public class MultiDimensionalArray{ } + public class MultiDimensionalArray { } [Kept] public static void TestMultiDimensionalArray () @@ -157,5 +158,21 @@ namespace Mono.Linker.Tests.Cases.Reflection { const string reflectionTypeKeptString = "Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+MultiDimensionalArrayAsmName[,], test"; var typeKept = Type.GetType (reflectionTypeKeptString, false); } + + [Kept] + class Nested1 { + [Kept] + class N2 { + [Kept] + class N3 { + } + } + } + + [Kept] + static void TestDeeplyNested () + { + var typeKept = Type.GetType ("Mono.Linker.Tests.Cases.Reflection.TypeUsedViaReflection+Nested1+N2+N3"); + } } } diff --git a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs index 874f555d3..893b55508 100644 --- a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs +++ b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs @@ -75,7 +75,12 @@ namespace Mono.Linker.Tests.TestCases { return NUnitCasesBySuiteName ("Reflection"); } - + + public static IEnumerable<TestCaseData> ComponentModelTests () + { + return NUnitCasesBySuiteName ("ComponentModel"); + } + public static IEnumerable<TestCaseData> SymbolsTests () { return NUnitCasesBySuiteName ("Symbols"); diff --git a/test/Mono.Linker.Tests/TestCases/TestSuites.cs b/test/Mono.Linker.Tests/TestCases/TestSuites.cs index 90d2f2e69..b3aa7ad50 100644 --- a/test/Mono.Linker.Tests/TestCases/TestSuites.cs +++ b/test/Mono.Linker.Tests/TestCases/TestSuites.cs @@ -90,7 +90,13 @@ namespace Mono.Linker.Tests.TestCases { Run (testCase); } - + + [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.ComponentModelTests))] + public void ComponentModelTests (TestCase testCase) + { + Run (testCase); + } + [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.PreserveDependenciesTests))] public void PreserveDependenciesTests (TestCase testCase) { |