diff options
16 files changed, 517 insertions, 90 deletions
diff --git a/docs/data-formats.md b/docs/data-formats.md index 9c1faf31c..91670c8d9 100644 --- a/docs/data-formats.md +++ b/docs/data-formats.md @@ -314,9 +314,22 @@ Attribute annotation XML can be embedded in an assembly by including it as an em </ItemGroup> ``` -Embedded attribute annotations should only address methods from the containing assembly. +Embedded attribute annotations should only address methods from the containing assembly. Whereas attribute annotations specified on the command line via the [`--link-attributes` parameter](illink-options.md#supplementary-custom-attributes) can alter types and members in any assembly. -Attribute annotations XML can be specified on the command line via the [`--link-attributes` parameter](illink-options.md#supplementary-custom-attributes). +The attribute element requires 'fullname' attribute without it linker will generate a warning and skip the attribute. Optionally you can use the 'assembly' attribute to point to certain assembly to look +for the attribute, if not specified the linker will look up the attribute in any loaded assembly. + +Inside an attribute element in the xml you can further define argument, field and property elements used as an input for the attribute. An attribute can have several arguments, several fields or several properties. When writing custom attribute with multiple arguments you need to write the xml elements in an order-dependent form. That is, the first xml argument element corresponds to the first custom attribute argument, second xml argument element correspond to the second custom attribute argument and so on. When argument type is not specified it's considered to be of `string` type. Any other custom attribute value has to have its type specified for linker to find the correct constructor overload. + +```xml +<attribute fullname="SomeCustomAttribute" assembly="AssemblyName"> + <argument>StringValue</argument> + <argument type="System.Int32">-45</argument> + <argument type="System.DayOfWeek">Sunday</argument> + <field name="fieldName">StringValue</field> + <property name="propertyName" type="System.Byte">200</property> +</attribute> +``` ### Custom attribute on assembly @@ -509,34 +522,14 @@ attributes are applied. </linker> ``` -### Custom attributes elements - -The attribute element requires 'fullname' attribute without it linker will generate a warning and skip -the attribute. Optionally you can use the 'assembly' attribute to point to certain assembly to look -for the attribute, if not specified the linker will look up the attribute in any loaded assembly. -Inside an attribute element in the xml you can define argument, field and property elements. -An attribute could have several arguments, several fields or several properties. When writing -custom attribute with multiple arguments you need to write the xml elements in an order dependent -form. That is, the first xml argument element corresponds to the first custom attribute argument, -second xml argument element correspond to the second custom attribute argument and so on. -For fields and properties, you need to include the name since they are not order dependent. - -```xml -<attribute fullname="SomeCustomAttribute" assembly="AssemblyName"> - <argument>Argument1</argument> - <argument>Argument2</argument> - <argument>Argument3</argument> - <field name="fieldName">SomeValue</field> - <property name="propertyName">SomeValue</property> -</attribute> -``` - -Additionally the attribute element also supports the usage of the feature switch +### Custom attributes with feature ```xml <attribute fullname="SomecustomAttribute" feature="EnableOptionalFeature" featurevalue="false"/> ``` +### Special custom attributes + Also if the attribute is used in a type, a special property can be used to specify that the type is a Custom Attribute and it's instances should be removed by the linker. To do this use `internal="RemoveAttributeInstances"` instead of specifying `fullname` in the attribute as described in the following example: diff --git a/docs/error-codes.md b/docs/error-codes.md index d0802c238..e7faef3ca 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -135,7 +135,27 @@ the error code. For example: #### `IL1040`: Failed to resolve {name} -Metadata element 'name' cannot be resolved. This usually means there is a version mismatch between dependencies. +- Metadata element 'name' cannot be resolved. This usually means there is a version mismatch between dependencies. + +#### `IL1041`: The type '{typeName}' used with attribute value 'value' could not be found + +- The type name used to define custom attribute value could not be resolved. This can mean the assembly reference is missing or that the type does not exist. + +#### `IL1042`: Cannot convert value '{value}' to type '{typeName}' + +- The 'value' specified for the custom attribute value cannot be converted to specified argument type 'typeName'. + +#### `IL1043`: Custom attribute argument for 'type' type requires nested 'argument' node + +- The syntax for custom attribute value for 'type' requires to also specify the underlying attribute type. + +#### `IL1044`: Could not resolve custom attribute type value '{value}' + +- The 'value' specified for the custom attribute of `System.Type` type could not be resolved. + +#### `IL1045`: Unexpected attribute argument type 'type' + +- The type name used with attribute type is not one of the supported types. ---- ## Warning Codes @@ -403,12 +423,12 @@ Metadata element 'name' cannot be resolved. This usually means there is a versio </linker> ``` -#### `IL2022`: Could not find a constructor for type 'attribute type' that has 'number of arguments' arguments +#### `IL2022`: Could not find matching constructor for custom attribute 'attribute-type' arguments -- The XML attribute for attribute type 'attribute type' specifies 'number of arguments' arguments but there's no constructor for 'attribute type' which has that many arguments +- The XML attribute arguments for attribute type 'attribute-type' use values or types which don't match to any constructor on 'attribute-type' ```XML - <!-- IL2022: Could not find a constructor for type 'AttributeWithNoParametersAttribute' that has '1' arguments --> + <!-- IL2022: Could not find matching constructor for custom attribute 'attribute-type' arguments --> <linker> <assembly fullname="MyAssembly"> <type fullname="MyType"> diff --git a/src/linker/Linker.Steps/LinkAttributesParser.cs b/src/linker/Linker.Steps/LinkAttributesParser.cs index 3518976a4..0deb94e25 100644 --- a/src/linker/Linker.Steps/LinkAttributesParser.cs +++ b/src/linker/Linker.Steps/LinkAttributesParser.cs @@ -57,43 +57,84 @@ namespace Mono.Linker.Steps continue; CustomAttribute customAttribute = CreateCustomAttribute (iterator, attributeType); - if (customAttribute != null) + if (customAttribute != null) { + _context.LogMessage ($"Assigning external custom attribute '{FormatCustomAttribute (customAttribute)}' instance to '{provider}'"); attributes.Add (customAttribute); + } } return attributes; + + static string FormatCustomAttribute (CustomAttribute ca) + { + StringBuilder sb = new StringBuilder (); + sb.Append (ca.Constructor.GetDisplayName ()); + sb.Append (" { args: "); + for (int i = 0; i < ca.ConstructorArguments.Count; ++i) { + if (i > 0) + sb.Append (", "); + + var caa = ca.ConstructorArguments[i]; + sb.Append ($"{caa.Type.GetDisplayName ()} {caa.Value}"); + } + sb.Append (" }"); + + return sb.ToString (); + } } CustomAttribute CreateCustomAttribute (XPathNodeIterator iterator, TypeDefinition attributeType) { - string[] attributeArguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)).ToArray (); - var attributeArgumentCount = attributeArguments == null ? 0 : attributeArguments.Length; - MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == attributeArgumentCount); + CustomAttributeArgument[] arguments = ReadCustomAttributeArguments (iterator); + + MethodDefinition constructor = FindBestMatchingConstructor (attributeType, arguments); if (constructor == null) { _context.LogWarning ( - $"Could not find a constructor for type '{attributeType}' that has '{attributeArgumentCount}' arguments", + $"Could not find matching constructor for custom attribute '{attributeType.GetDisplayName ()}' arguments", 2022, _xmlDocumentLocation); return null; } CustomAttribute customAttribute = new CustomAttribute (constructor); - var arguments = ProcessAttributeArguments (constructor, attributeArguments); - if (arguments != null) - foreach (var argument in arguments) - customAttribute.ConstructorArguments.Add (argument); + foreach (var argument in arguments) + customAttribute.ConstructorArguments.Add (argument); - var properties = ProcessAttributeProperties (iterator.Current.SelectChildren ("property", string.Empty), attributeType); - if (properties != null) - foreach (var property in properties) - customAttribute.Properties.Add (property); + ReadCustomAttributeProperties (iterator.Current.SelectChildren ("property", string.Empty), attributeType, customAttribute); return customAttribute; } - List<CustomAttributeNamedArgument> ProcessAttributeProperties (XPathNodeIterator iterator, TypeDefinition attributeType) + static MethodDefinition FindBestMatchingConstructor (TypeDefinition attributeType, CustomAttributeArgument[] args) + { + var methods = attributeType.Methods; + for (int i = 0; i < attributeType.Methods.Count; ++i) { + var m = methods[i]; + if (!m.IsInstanceConstructor ()) + continue; + + var p = m.Parameters; + if (args.Length != p.Count) + continue; + + bool match = true; + for (int ii = 0; match && ii != args.Length; ++ii) { + // + // No candidates betterness, only exact matches are supported + // + if (p[ii].ParameterType.Resolve () != args[ii].Type.Resolve ()) + match = false; + } + + if (match) + return m; + } + + return null; + } + + void ReadCustomAttributeProperties (XPathNodeIterator iterator, TypeDefinition attributeType, CustomAttribute customAttribute) { - List<CustomAttributeNamedArgument> attributeProperties = new List<CustomAttributeNamedArgument> (); while (iterator.MoveNext ()) { string propertyName = GetName (iterator.Current); if (string.IsNullOrEmpty (propertyName)) { @@ -107,40 +148,166 @@ namespace Mono.Linker.Steps continue; } - var propertyValue = iterator.Current.Value; - if (!TryConvertValue (propertyValue, property.PropertyType, out object value)) { - _context.LogWarning ($"Invalid value '{propertyValue}' for property '{propertyName}'", 2053, _xmlDocumentLocation); + var caa = ReadCustomAttributeArgument (iterator); + if (caa is null) continue; - } - attributeProperties.Add (new CustomAttributeNamedArgument (property.Name, - new CustomAttributeArgument (property.PropertyType, value))); + customAttribute.Properties.Add (new CustomAttributeNamedArgument (property.Name, caa.Value)); } + } + + CustomAttributeArgument[] ReadCustomAttributeArguments (XPathNodeIterator iterator) + { + var args = new ArrayBuilder<CustomAttributeArgument> (); - return attributeProperties; + iterator = iterator.Current.SelectChildren ("argument", string.Empty); + while (iterator.MoveNext ()) { + CustomAttributeArgument? caa = ReadCustomAttributeArgument (iterator); + if (caa is not null) + args.Add (caa.Value); + } + + return args.ToArray () ?? Array.Empty<CustomAttributeArgument> (); } - List<CustomAttributeArgument> ProcessAttributeArguments (MethodDefinition attributeConstructor, string[] arguments) + CustomAttributeArgument? ReadCustomAttributeArgument (XPathNodeIterator iterator) { - if (arguments == null) + TypeReference typeref = ResolveArgumentType (iterator); + if (typeref is null) return null; - List<CustomAttributeArgument> attributeArguments = new List<CustomAttributeArgument> (); - for (int i = 0; i < arguments.Length; i++) { - object argValue; - TypeDefinition parameterType = attributeConstructor.Parameters[i].ParameterType.Resolve (); - if (!TryConvertValue (arguments[i], parameterType, out argValue)) { - _context.LogWarning ( - $"Invalid argument value '{arguments[i]}' for parameter type '{parameterType.GetDisplayName ()}' of attribute '{attributeConstructor.DeclaringType.GetDisplayName ()}'", - 2054, - _xmlDocumentLocation); + string svalue = iterator.Current.Value; + + // + // Builds CustomAttributeArgument in the same way as it would be + // represented in the metadata if encoded there. This simplifies + // any custom attributes handling in linker by using same attributes + // value extraction or mathing logic. + // + switch (typeref.MetadataType) { + case MetadataType.Object: + iterator = iterator.Current.SelectChildren ("argument", string.Empty); + if (iterator?.MoveNext () != true) { + _context.LogError ($"Custom attribute argument for 'System.Object' requires nested 'argument' node", 1043); + return null; + } + + var boxedValue = ReadCustomAttributeArgument (iterator); + if (boxedValue is null) + return null; + + return new CustomAttributeArgument (typeref, boxedValue); + + case MetadataType.Char: + case MetadataType.Byte: + case MetadataType.SByte: + case MetadataType.Int16: + case MetadataType.UInt16: + case MetadataType.Int32: + case MetadataType.UInt32: + case MetadataType.UInt64: + case MetadataType.Int64: + case MetadataType.String: + return new CustomAttributeArgument (typeref, ConvertStringValue (svalue, typeref)); + + case MetadataType.ValueType: + var enumType = typeref.Resolve (); + if (enumType?.IsEnum != true) + goto default; + + var enumField = enumType.Fields.Where (f => f.IsStatic && f.Name == svalue).FirstOrDefault (); + object evalue = enumField?.Constant ?? svalue; + + typeref = enumType.GetEnumUnderlyingType (); + return new CustomAttributeArgument (enumType, ConvertStringValue (evalue, typeref)); + + case MetadataType.Class: + if (!typeref.IsTypeOf ("System", "Type")) + goto default; + + TypeReference type = _context.TypeNameResolver.ResolveTypeName (svalue); + if (type == null) { + _context.LogError ($"Could not resolve custom attribute type value '{svalue}'", 1044, _xmlDocumentLocation); return null; } - attributeArguments.Add (new CustomAttributeArgument (parameterType, argValue)); + return new CustomAttributeArgument (typeref, type); + default: + // TODO: Add support for null values + // TODO: Add suppport for arrays + _context.LogError ($"Unexpected attribute argument type '{typeref.GetDisplayName ()}'", 1045); + return null; } - return attributeArguments; + TypeReference ResolveArgumentType (XPathNodeIterator iterator) + { + string typeName = GetAttribute (iterator.Current, "type"); + if (string.IsNullOrEmpty (typeName)) + typeName = "System.String"; + + TypeReference typeref = _context.TypeNameResolver.ResolveTypeName (typeName); + if (typeref == null) { + _context.LogError ($"The type '{typeName}' used with attribute value '{iterator.Current.Value}' could not be found", 1041, _xmlDocumentLocation); + return null; + } + + return typeref; + } + } + + object ConvertStringValue (object value, TypeReference targetType) + { + TypeCode typeCode; + switch (targetType.MetadataType) { + case MetadataType.String: + typeCode = TypeCode.String; + break; + case MetadataType.Char: + typeCode = TypeCode.Char; + break; + case MetadataType.Byte: + typeCode = TypeCode.Byte; + break; + case MetadataType.SByte: + typeCode = TypeCode.SByte; + break; + case MetadataType.Int16: + typeCode = TypeCode.Int16; + break; + case MetadataType.UInt16: + typeCode = TypeCode.UInt16; + break; + case MetadataType.Int32: + typeCode = TypeCode.Int32; + break; + case MetadataType.UInt32: + typeCode = TypeCode.UInt32; + break; + case MetadataType.UInt64: + typeCode = TypeCode.UInt64; + break; + case MetadataType.Int64: + typeCode = TypeCode.Int64; + break; + case MetadataType.Boolean: + typeCode = TypeCode.Boolean; + break; + case MetadataType.Single: + typeCode = TypeCode.Single; + break; + case MetadataType.Double: + typeCode = TypeCode.Double; + break; + default: + throw new NotSupportedException (targetType.ToString ()); + } + + try { + return Convert.ChangeType (value, typeCode); + } catch { + _context.LogError ($"Cannot convert value '{value}' to type '{targetType.GetDisplayName ()}'", 1042); + return null; + } } void ProcessInternalAttribute (ICustomAttributeProvider provider, string internalAttribute) @@ -192,15 +359,6 @@ namespace Mono.Linker.Steps return true; } - static ArrayBuilder<string> GetAttributeChildren (XPathNodeIterator iterator) - { - ArrayBuilder<string> children = new ArrayBuilder<string> (); - while (iterator.MoveNext ()) { - children.Add (iterator.Current.Value); - } - return children; - } - protected override AllowedAssemblies AllowedAssemblySelector { get { if (_resourceAssembly == null) diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.xml b/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.xml index 57889aafd..ea59e779d 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.xml +++ b/test/Mono.Linker.Tests.Cases/DataFlow/SuppressWarningWithLinkAttributes.xml @@ -11,7 +11,7 @@ <argument>0</argument> </attribute> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicParameterlessConstructor</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicParameterlessConstructor</argument> </attribute> </field> </type> diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs index 40bac152b..fa71478a8 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs @@ -13,7 +13,7 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [SkipKeptItemsValidation] [SetupLinkAttributesFile ("XmlAnnotations.xml")] - [ExpectedWarning ("IL2031", "System.DoesNotExistAttribute", FileName = "XmlAnnotations.xml")] + [ExpectedWarning ("IL2031", "Attribute type 'System.DoesNotExistAttribute' could not be found", FileName = "XmlAnnotations.xml")] [LogDoesNotContain ("IL2067: Mono.Linker.Tests.Cases.DataFlow.XmlAnnotations.ReadFromInstanceField():*", true)] class XmlAnnotations { diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml index 2108bcebd..210c702a8 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml @@ -13,51 +13,51 @@ <argument>0</argument> </attribute> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicParameterlessConstructor</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicParameterlessConstructor</argument> </attribute> </field> <method signature="System.Void TwoAnnotatedParameters(System.Type,System.Type)"> <parameter name="type"> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicParameterlessConstructor</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicParameterlessConstructor</argument> </attribute> </parameter> <parameter name="type2"> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicConstructors</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicConstructors</argument> </attribute> </parameter> </method> <method signature="SpacesBetweenParametersWrongArgument (System.Type, System.Boolean)"> <parameter name="type"> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>NonValidArgument</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">0</argument> </attribute> </parameter> </method> <method signature="GenericMethod<T>(T,System.Type)"> <parameter name="type"> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicParameterlessConstructor</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicParameterlessConstructor</argument> </attribute> </parameter> </method> <method name="ReturnConstructorsFailure"> <return> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicParameterlessConstructor</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicParameterlessConstructor</argument> </attribute> </return> </method> <property name="PropertyWithPublicParameterlessConstructor"> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicParameterlessConstructor</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicParameterlessConstructor</argument> </attribute> </property> <type name="NestedType"> <field name="_typeWithPublicParameterlessConstructor"> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicParameterlessConstructor</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicParameterlessConstructor</argument> </attribute> </field> </type> diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.cs index 4bee904fe..b523e34ff 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.cs @@ -22,6 +22,7 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies public static void Main () { DependencyToUnusedMethod (); + DependencyToUnusedType (); } [Kept] @@ -33,5 +34,23 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies static void UnusedMethod () { } + + [Kept] + static void DependencyToUnusedType () + { + } + + class NonUsedType + { + [Kept] + public NonUsedType () + { + } + + [Kept] + public static void PleasePreserveThisMethod () + { + } + } } } diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.mono.Attributes.xml b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.mono.Attributes.xml index cbf1c08ba..eb7285606 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.mono.Attributes.xml +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.mono.Attributes.xml @@ -7,6 +7,12 @@ <argument>UnusedMethod</argument> </attribute> </method> + <method name="DependencyToUnusedType"> + <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute" assembly="Mono.Linker.Tests.Cases.Expectations"> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes, test">All</argument> + <argument type="System.Type">Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyFromAttributeXml/NonUsedType</argument> + </attribute> + </method> </type> </assembly> </linker>
\ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.netcore.Attributes.xml b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.netcore.Attributes.xml index 3d7f8cce5..e6624a8d3 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.netcore.Attributes.xml +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromAttributeXml.netcore.Attributes.xml @@ -7,6 +7,12 @@ <argument>UnusedMethod</argument> </attribute> </method> + <method name="DependencyToUnusedType"> + <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute"> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">All</argument> + <argument type="System.Type">Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyFromAttributeXml/NonUsedType, test</argument> + </attribute> + </method> </type> </assembly> </linker>
\ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.xml index 00916a338..b006fe2c0 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.xml +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/EmbeddedLinkAttributes.xml @@ -3,7 +3,7 @@ <type fullname="Mono.Linker.Tests.Cases.LinkAttributes.EmbeddedLinkAttributes"> <field name="_typeWithPublicParameterlessConstructor"> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicParameterlessConstructor</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicParameterlessConstructor</argument> </attribute> </field> </type> @@ -11,7 +11,7 @@ <type fullname="Mono.Linker.Tests.Cases.LinkAttributes.EmbeddedLinkAttributes"> <field name="_typeWithPublicFields"> <attribute fullname="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute"> - <argument>PublicFields</argument> + <argument type="System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes">PublicFields</argument> </attribute> </field> </type> diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs index 0be400309..dd05d4052 100644 --- a/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/LinkAttributeErrorCases.cs @@ -15,15 +15,12 @@ namespace Mono.Linker.Tests.Cases.LinkAttributes [ExpectedWarning ("IL2030", "NonExistentAssembly1", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2030", "MalformedAssemblyName, thisiswrong", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2031", "NonExistentAttribute", FileName = "LinkAttributeErrorCases.xml")] - [ExpectedWarning ("IL2054", "NonExistentEnumValue", "AttributeWithEnumParameterAttribute", "AttributeEnum", FileName = "LinkAttributeErrorCases.xml")] - [ExpectedWarning ("IL2054", "NotANumber", "AttributeWithIntParameterAttribute", "System.Int32", FileName = "LinkAttributeErrorCases.xml")] - [ExpectedWarning ("IL2022", "AttributeWithNoParametersAttribute", "1", FileName = "LinkAttributeErrorCases.xml")] + [ExpectedWarning ("IL2022", "AttributeWithNoParametersAttribute", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2023", "GetTypeMethod", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2024", "methodParameter", "MethodWithParameter", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2029", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2051", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2052", "NonExistentPropertyName", FileName = "LinkAttributeErrorCases.xml")] - [ExpectedWarning ("IL2053", "StringValue", "IntProperty", FileName = "LinkAttributeErrorCases.xml")] [ExpectedWarning ("IL2100", FileName = "ILLink.LinkAttributes.xml")] [ExpectedWarning ("IL2101", "library", "test", FileName = "ILLink.LinkAttributes.xml")] class LinkAttributeErrorCases diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArguments.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArguments.cs new file mode 100644 index 000000000..c89948c37 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArguments.cs @@ -0,0 +1,123 @@ +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.LinkAttributes +{ + [SetupLinkAttributesFile ("TypedArguments.xml")] + [IgnoreLinkAttributes (false)] + [SetupLinkerArgument ("--verbose")] + + [LogContains ("Assigning external custom attribute 'Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments.ObjectAttribute.ObjectAttribute(Object) { args: System.Object Mono.Cecil.CustomAttributeArgument }' instance to 'System.Object Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments::field1'")] + [LogContains ("Assigning external custom attribute 'Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments.ObjectAttribute.ObjectAttribute(Object) { args: System.Object Mono.Cecil.CustomAttributeArgument }' instance to 'System.Object Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments::field2'")] + [LogContains ("Assigning external custom attribute 'Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments.EnumAttribute.EnumAttribute(TypedArgumentsEnumA) { args: Mono.Linker.Tests.Cases.LinkAttributes.TypedArgumentsEnumA 3 }' instance to 'System.Object Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments::field3'")] + [LogContains ("Assigning external custom attribute 'Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments.ByteAttribute.ByteAttribute(Byte) { args: System.Byte 6 }' instance to 'System.Object Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments::field4'")] + [LogContains ("Assigning external custom attribute 'Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments.StringAttribute.StringAttribute(String) { args: System.String str }' instance to 'System.Object Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments::field5'")] + [LogContains ("Assigning external custom attribute 'Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments.TypeAttribute.TypeAttribute(Type) { args: System.Type System.DateTime }' instance to 'System.Object Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments::field6'")] + class TypedArguments + { + [Kept] + static object field1; + + [Kept] + static object field2; + + [Kept] + static object field3; + + [Kept] + static object field4; + + [Kept] + static object field5; + + [Kept] + static object field6; + + public static void Main () + { + field1 = null; + field2 = null; + field3 = null; + field4 = null; + field5 = null; + field6 = null; + } + + public class ObjectAttribute : Attribute + { + public ObjectAttribute (object objectValue) + { + } + + public ObjectAttribute (string stringValue) + { + } + } + + public class ByteAttribute : Attribute + { + public ByteAttribute (uint intValue) + { + } + + public ByteAttribute (byte byteValue) + { + } + + public ByteAttribute (object objectValue) + { + } + } + + public class EnumAttribute : Attribute + { + public EnumAttribute (int intValue) + { + } + + public EnumAttribute (object objectValue) + { + } + + public EnumAttribute (TypedArgumentsEnumA enumA) + { + } + + public EnumAttribute (TypedArgumentsEnumB enumB) + { + } + } + + public class StringAttribute : Attribute + { + public StringAttribute (string stringValue) + { + } + + public StringAttribute (object objectValue) + { + } + } + + public class TypeAttribute : Attribute + { + public TypeAttribute (string stringValue) + { + } + + public TypeAttribute (Type typeValue) + { + } + } + } + + enum TypedArgumentsEnumA + { + Value = 2 + } + + enum TypedArgumentsEnumB + { + } +} diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArguments.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArguments.xml new file mode 100644 index 000000000..639bb02f8 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArguments.xml @@ -0,0 +1,40 @@ +<linker> + <assembly fullname="test"> + <type fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments"> + <field name="field1"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments/ObjectAttribute"> + <argument type="System.Object"> + <argument type="System.String">StringValue</argument> + </argument> + </attribute> + </field> + <field name="field2"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments/ObjectAttribute"> + <argument type="System.Object"> + <argument type="System.Char">9</argument> + </argument> + </attribute> + </field> + <field name="field3"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments/EnumAttribute"> + <argument type="Mono.Linker.Tests.Cases.LinkAttributes.TypedArgumentsEnumA">3</argument> + </attribute> + </field> + <field name="field4"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments/ByteAttribute"> + <argument type="System.Byte">6</argument> + </attribute> + </field> + <field name="field5"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments/StringAttribute"> + <argument type="System.String">str</argument> + </attribute> + </field> + <field name="field6"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArguments/TypeAttribute"> + <argument type="System.Type">System.DateTime</argument> + </attribute> + </field> + </type> + </assembly> +</linker> diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArgumentsErrors.cs b/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArgumentsErrors.cs new file mode 100644 index 000000000..44513d83e --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArgumentsErrors.cs @@ -0,0 +1,35 @@ +using System; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.LinkAttributes +{ + [SetupLinkAttributesFile ("TypedArgumentsErrors.xml")] + [IgnoreLinkAttributes (false)] + [NoLinkedOutput] + + [LogContains ("The type 'System.NoOBJECT' used with attribute value 'str' could not be found")] + [LogContains ("Cannot convert value 'str' to type 'System.Int32'")] + [LogContains ("Custom attribute argument for 'System.Object' requires nested 'argument' node")] + [LogContains ("The type 'System.Bar' used with attribute value 'str4' could not be found")] + [LogContains ("Could not resolve custom attribute type value 'str5'")] + class TypedArgumentsErrors + { + static object field; + + public static void Main () + { + } + + public class ObjectAttribute : Attribute + { + public ObjectAttribute (object objectValue) + { + } + + public ObjectAttribute (string stringValue) + { + } + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArgumentsErrors.xml b/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArgumentsErrors.xml new file mode 100644 index 000000000..e71703e19 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/LinkAttributes/TypedArgumentsErrors.xml @@ -0,0 +1,31 @@ +<linker> + <assembly fullname="test"> + <type fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArgumentsErrors"> + <field name="field"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArgumentsErrors/ObjectAttribute"> + <argument type="System.NoOBJECT">str</argument> + </attribute> + </field> + <field name="field"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArgumentsErrors/ObjectAttribute"> + <argument type="System.Int32">str</argument> + </attribute> + </field> + <field name="field"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArgumentsErrors/ObjectAttribute"> + <argument type="System.Object">str</argument> + </attribute> + </field> + <field name="field"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArgumentsErrors/ObjectAttribute"> + <argument type="System.Bar">str4</argument> + </attribute> + </field> + <field name="field"> + <attribute fullname="Mono.Linker.Tests.Cases.LinkAttributes.TypedArgumentsErrors/ObjectAttribute"> + <argument type="System.Type">str5</argument> + </attribute> + </field> + </type> + </assembly> +</linker> diff --git a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs index 68e6df6f7..7e3e008d4 100644 --- a/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs +++ b/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresUnreferencedCodeCapability.cs @@ -156,7 +156,6 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability class TestType { } [ExpectedWarning ("IL2026", "--MethodWithDuplicateRequiresAttribute--")] - [LogDoesNotContain ("Message for MethodWithDuplicateRequiresAttribute from link attributes XML")] static void TestDuplicateRequiresAttribute () { MethodWithDuplicateRequiresAttribute (); |