From 37a62f102a1af2b256a17e353db4884c82a3fc07 Mon Sep 17 00:00:00 2001 From: Tlakollo Date: Tue, 26 May 2020 23:03:16 -0700 Subject: [PATCH 1/6] - Change XmlFlowAnnotationSource to expose CustomAttributes - Use ICustomAttributeProvider to simplify when asking for information about annotations - Use of assembly in the attribute is now mandatory - Assembly name now could be * either in the assembly element or in the assembly property inside the attribute element, leaving no assembly name is not supported - Added new error codes, swaped non used codes for new error codes - Changed documentation to reflect the way of use --- docs/data-formats.md | 50 ++- docs/error-codes.md | 30 +- .../AggregateFlowAnnotationSource.cs | 46 -- .../AttributeFlowAnnotationSource.cs | 70 --- .../Linker.Dataflow/CustomAttributeSource.cs | 54 +++ src/linker/Linker.Dataflow/FlowAnnotations.cs | 43 +- .../Linker.Dataflow/IFlowAnnotationSource.cs | 25 -- .../XmlFlowAnnotationSource.cs | 406 ++++++++++-------- src/linker/Linker.Steps/MarkStep.cs | 14 +- .../DataFlow/XmlAnnotations.cs | 5 +- .../DataFlow/XmlAnnotations.xml | 18 +- 11 files changed, 391 insertions(+), 370 deletions(-) delete mode 100644 src/linker/Linker.Dataflow/AggregateFlowAnnotationSource.cs delete mode 100644 src/linker/Linker.Dataflow/AttributeFlowAnnotationSource.cs create mode 100644 src/linker/Linker.Dataflow/CustomAttributeSource.cs delete mode 100644 src/linker/Linker.Dataflow/IFlowAnnotationSource.cs diff --git a/docs/data-formats.md b/docs/data-formats.md index 0e20fd4d1dbe..78fd4b06b3b5 100644 --- a/docs/data-formats.md +++ b/docs/data-formats.md @@ -229,7 +229,7 @@ are applied. ```xml - + Argument @@ -244,7 +244,7 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + Argument @@ -259,7 +259,7 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor @@ -275,7 +275,7 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor @@ -291,7 +291,7 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor @@ -308,21 +308,21 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor - + PublicConstructors - + DefaultConstructor @@ -332,6 +332,24 @@ This allows to add a custom attribute to a class, interface, delegate, struct or ``` +### DynamicallyAccessedMembers attribute in implicit this parameter + +In the case of the implicit "this" parameter the way to include a custom attribute is to include an attribute +directly on the method element + +```xml + + + + + + DefaultConstructor + + + + + + ### Custom attribute in multiple method parameters ```xml @@ -340,17 +358,17 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor - + DefaultConstructor - + PublicConstructors @@ -368,7 +386,7 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor @@ -391,7 +409,7 @@ attributes are applied. - + PublicConstructors @@ -403,6 +421,8 @@ attributes are applied. ### Custom attributes elements +The attribute element requires fullname and assembly attributes without them it will generate +a warning and skip the attribute. 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 @@ -411,11 +431,11 @@ second xml argument element correspond to the second custom attribute argument a For fields and properties, you need to include the name since they are not order dependent. ```xml - + Argument1 Argument2 Argument3 SomeValue SomeValue -``` +``` \ No newline at end of file diff --git a/docs/error-codes.md b/docs/error-codes.md index 559712ab2111..2a129932738a 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -135,17 +135,17 @@ error and warning codes. - The 'XML document location' defined the set accessor of property 'property' on type 'type', but the accessor was not found. -#### `IL2020`: DynamicallyAccessedMembers attribute was specified but no argument was proportioned +#### `IL2020`: Argument 'xml argument' specified in 'XML Document location' could not be transformed to a currently supported metadatatype in the xml -- The XML descriptor has a DynamicallyAccessedMembers attribute but the argument 'argument' does not match any of the existing DynamicallyAccessedMemberTypes +- There is no way to convert the 'xml argument' string to the constructor parameter type. The constructor parameter type is not supported. -#### `IL2021`: Could not parse argument 'argument' specified in 'XML document location' as a DynamicallyAccessedMemberTypes +#### `IL2021`: Could not parse argument 'argument' specified in 'XML document location' as a 'type' -- The XML descriptor has a DynamicallyAccessedMembers attribute but the argument 'argument' does not match any of the existing DynamicallyAccessedMemberTypes +- The XML descriptor has a 'type' attribute but the argument 'argument' does not match any of the existing enum 'type' values -#### `IL2022`: DynamicallyAccessedMembers attribute was specified but there is more than one argument +#### `IL2022`: Could not find a constructor for type 'attribute type' that receives 'number of arguments' arguments as parameter -- The XML descriptor has more than one argument for a single DynamicallyAccessedMembers attribute, there can only be one argument in order to parse it +- The 'attribute type' 'number of arguments' doesnt match with the number of arguments in any of the constructor function described in 'attribute type' #### `IL2023`: There is more than one return parameter specified for 'method' in 'XML document location' @@ -169,4 +169,20 @@ error and warning codes. #### `IL2028`: Attribute 'attribute' on 'method' doesn't have a required constructor argument. -- The linker found an instance of attribute 'attribute' on 'method' but it lacks a required constructor argument. Linker will ignore this attribute. \ No newline at end of file +- The linker found an instance of attribute 'attribute' on 'method' but it lacks a required constructor argument. Linker will ignore this attribute. + +#### `IL2029`: There is no xml attribute 'fullname' in xml element '{attributeFullName}' + +- The linker found an instance of attribute 'attribute' on 'method' but it lacks a required constructor argument. Linker will ignore this attribute. + +#### `IL2030`: There is no xml attribute 'assembly' in xml element 'attribute element' + +- The linker found an 'attribute element' on the xml file but it didnt contain an 'assembly' attribute + +#### `IL2031`: Could not resolve assembly 'assembly' in attribute 'attribute' specified in the 'XML document location' + +- The assembly 'assembly' described as a attribute property of 'attribute' could not be resolved in 'XML document location' + +#### `IL2032`: Attribute type 'attribute type' could not be found + +- The described 'attribute type' could not be found in the assemblies \ No newline at end of file diff --git a/src/linker/Linker.Dataflow/AggregateFlowAnnotationSource.cs b/src/linker/Linker.Dataflow/AggregateFlowAnnotationSource.cs deleted file mode 100644 index 906beb77de50..000000000000 --- a/src/linker/Linker.Dataflow/AggregateFlowAnnotationSource.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using Mono.Cecil; - -namespace Mono.Linker.Dataflow -{ - class AggregateFlowAnnotationSource : IFlowAnnotationSource - { - private readonly List _sources; - - public AggregateFlowAnnotationSource (IEnumerable sources) - { - _sources = new List (sources); - } - - public DynamicallyAccessedMemberTypes GetFieldAnnotation (FieldDefinition field) - { - return _sources.Aggregate (DynamicallyAccessedMemberTypes.None, (r, s) => r | s.GetFieldAnnotation (field)); - } - - public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition method, int index) - { - return _sources.Aggregate (DynamicallyAccessedMemberTypes.None, (r, s) => r | s.GetParameterAnnotation (method, index)); - } - - public DynamicallyAccessedMemberTypes GetPropertyAnnotation (PropertyDefinition property) - { - return _sources.Aggregate (DynamicallyAccessedMemberTypes.None, (r, s) => r | s.GetPropertyAnnotation (property)); - } - - public DynamicallyAccessedMemberTypes GetReturnParameterAnnotation (MethodDefinition method) - { - return _sources.Aggregate (DynamicallyAccessedMemberTypes.None, (r, s) => r | s.GetReturnParameterAnnotation (method)); - } - - public DynamicallyAccessedMemberTypes GetThisParameterAnnotation (MethodDefinition method) - { - return _sources.Aggregate (DynamicallyAccessedMemberTypes.None, (r, s) => r | s.GetThisParameterAnnotation (method)); - } - } -} diff --git a/src/linker/Linker.Dataflow/AttributeFlowAnnotationSource.cs b/src/linker/Linker.Dataflow/AttributeFlowAnnotationSource.cs deleted file mode 100644 index 273538d28b3d..000000000000 --- a/src/linker/Linker.Dataflow/AttributeFlowAnnotationSource.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using Mono.Cecil; - -namespace Mono.Linker.Dataflow -{ - class AttributeFlowAnnotationSource : IFlowAnnotationSource - { - public DynamicallyAccessedMemberTypes GetFieldAnnotation (FieldDefinition field) - { - return Get (field); - } - - public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition method, int index) - { - return Get (method.Parameters[index]); - } - - public DynamicallyAccessedMemberTypes GetPropertyAnnotation (PropertyDefinition property) - { - return Get (property); - } - - public DynamicallyAccessedMemberTypes GetReturnParameterAnnotation (MethodDefinition method) - { - return Get (method.MethodReturnType); - } - - public DynamicallyAccessedMemberTypes GetThisParameterAnnotation (MethodDefinition method) - { - // We take the annotation from the attribute on the method itself for "this" - return Get (method); - } - - static bool IsDynamicallyAccessedMembersAttribute (CustomAttribute attribute) - { - var attributeType = attribute.AttributeType; - return attributeType.Name == "DynamicallyAccessedMembersAttribute" && attributeType.Namespace == "System.Diagnostics.CodeAnalysis"; - } - - static DynamicallyAccessedMemberTypes GetFromAttribute (CustomAttribute attribute) - { - Debug.Assert (IsDynamicallyAccessedMembersAttribute (attribute)); - - if (attribute.HasConstructorArguments) { - return (DynamicallyAccessedMemberTypes) (int) attribute.ConstructorArguments[0].Value; - } - - return DynamicallyAccessedMemberTypes.None; - } - - static DynamicallyAccessedMemberTypes Get (ICustomAttributeProvider attributeProvider) - { - if (!attributeProvider.HasCustomAttributes) - return DynamicallyAccessedMemberTypes.None; - - foreach (var attribute in attributeProvider.CustomAttributes) { - if (IsDynamicallyAccessedMembersAttribute (attribute)) { - return GetFromAttribute (attribute); - } - } - - return DynamicallyAccessedMemberTypes.None; - } - } -} diff --git a/src/linker/Linker.Dataflow/CustomAttributeSource.cs b/src/linker/Linker.Dataflow/CustomAttributeSource.cs new file mode 100644 index 000000000000..516fe55cfc30 --- /dev/null +++ b/src/linker/Linker.Dataflow/CustomAttributeSource.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using Mono.Cecil; +using System.Collections.ObjectModel; +using System.Linq; + +namespace Mono.Linker.Dataflow +{ + class CustomAttributeSource + { + private readonly XmlFlowAnnotationSource[] _sources; + + public CustomAttributeSource (LinkContext _context) + { + Collection annotationSources = new Collection (); + if (_context.AttributeDefinitions != null && _context.AttributeDefinitions.Count > 0) { + foreach (string a in _context.AttributeDefinitions) { + XmlFlowAnnotationSource xmlAnnotations = new XmlFlowAnnotationSource (_context); + xmlAnnotations.ParseXml (a); + annotationSources.Add (xmlAnnotations); + } + } + _sources = annotationSources.ToArray (); + } + + public IEnumerable GetCustomAttributes (ICustomAttributeProvider provider) + { + IEnumerable aggregateAttributes = null; + foreach (var source in _sources) { + if (source.HasCustomAttributes (provider)) + aggregateAttributes = aggregateAttributes == null ? source.GetCustomAttributes (provider) : aggregateAttributes.Concat (source.GetCustomAttributes (provider)); + } + if (provider.HasCustomAttributes) + aggregateAttributes = aggregateAttributes == null ? provider.CustomAttributes : aggregateAttributes.Concat (provider.CustomAttributes); + return aggregateAttributes ?? Enumerable.Empty(); + } + + public bool HasCustomAttributes (ICustomAttributeProvider provider) + { + foreach (var source in _sources) { + if (source.HasCustomAttributes (provider)) { + return true; + } + } + if (provider.HasCustomAttributes) { + return true; + } + return false; + } + } +} diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs index 73c634d02039..0e90672d1be8 100644 --- a/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -13,12 +13,20 @@ namespace Mono.Linker.Dataflow class FlowAnnotations { - readonly IFlowAnnotationSource _source; + readonly LinkContext _context; + readonly CustomAttributeSource _source; readonly Dictionary _annotations = new Dictionary (); - public FlowAnnotations (IFlowAnnotationSource annotationSource) + public FlowAnnotations (LinkContext context, CustomAttributeSource annotationSource) { _source = annotationSource; + _context = context; + } + + public bool IsDynamicallyAccessedMembersAttribute (CustomAttribute attribute) + { + var attributeType = attribute.AttributeType; + return attributeType.Name == "DynamicallyAccessedMembersAttribute" && attributeType.Namespace == "System.Diagnostics.CodeAnalysis"; } public bool RequiresDataFlowAnalysis (MethodDefinition method) @@ -45,6 +53,25 @@ public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition m return DynamicallyAccessedMemberTypes.None; } + public DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (CustomAttributeSource source, ICustomAttributeProvider provider) + { + if (source.HasCustomAttributes (provider)) { + foreach (var attribute in source.GetCustomAttributes (provider)) { + if (IsDynamicallyAccessedMembersAttribute (attribute)) { + if (attribute.ConstructorArguments.Count == 0) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but no argument was proportioned", 2020)); + } else if (attribute.ConstructorArguments.Count == 1) { + var arguments = attribute.ConstructorArguments.ToArray (); + return (DynamicallyAccessedMemberTypes) arguments[0].Value; + } else { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but there is more than one argument", 2022)); + } + } + } + } + return DynamicallyAccessedMemberTypes.None; + } + public DynamicallyAccessedMemberTypes GetReturnParameterAnnotation (MethodDefinition method) { if (GetAnnotations (method.DeclaringType).TryGetAnnotation (method, out var annotation)) { @@ -83,7 +110,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (!IsTypeInterestingForDataflow (field.FieldType)) continue; - DynamicallyAccessedMemberTypes annotation = _source.GetFieldAnnotation (field); + DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, field); if (annotation == DynamicallyAccessedMemberTypes.None) { continue; } @@ -101,11 +128,13 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) // We convert indices from metadata space to IL space here. // IL space assigns index 0 to the `this` parameter on instance methods. + + int offset; if (method.HasImplicitThis ()) { offset = 1; if (IsTypeInterestingForDataflow (method.DeclaringType)) { - DynamicallyAccessedMemberTypes ta = _source.GetThisParameterAnnotation (method); + DynamicallyAccessedMemberTypes ta = GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, method); if (ta != DynamicallyAccessedMemberTypes.None) { paramAnnotations = new DynamicallyAccessedMemberTypes[method.Parameters.Count + offset]; paramAnnotations[0] = ta; @@ -120,7 +149,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) continue; } - DynamicallyAccessedMemberTypes pa = _source.GetParameterAnnotation (method, i); + DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, method.Parameters[i]); if (pa == DynamicallyAccessedMemberTypes.None) { continue; } @@ -132,7 +161,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) } DynamicallyAccessedMemberTypes returnAnnotation = IsTypeInterestingForDataflow (method.ReturnType) ? - _source.GetReturnParameterAnnotation (method) : DynamicallyAccessedMemberTypes.None; + GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, method.MethodReturnType) : DynamicallyAccessedMemberTypes.None; if (returnAnnotation != DynamicallyAccessedMemberTypes.None || paramAnnotations != null) { annotatedMethods.Add (new MethodAnnotations (method, paramAnnotations, returnAnnotation)); } @@ -160,7 +189,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) continue; } - DynamicallyAccessedMemberTypes annotation = _source.GetPropertyAnnotation (property); + DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, property); if (annotation == DynamicallyAccessedMemberTypes.None) { continue; } diff --git a/src/linker/Linker.Dataflow/IFlowAnnotationSource.cs b/src/linker/Linker.Dataflow/IFlowAnnotationSource.cs deleted file mode 100644 index 0177f14def07..000000000000 --- a/src/linker/Linker.Dataflow/IFlowAnnotationSource.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Diagnostics.CodeAnalysis; -using Mono.Cecil; - -namespace Mono.Linker.Dataflow -{ - interface IFlowAnnotationSource - { - DynamicallyAccessedMemberTypes GetPropertyAnnotation (PropertyDefinition property); - - // Index refers to the index in the formal parameter list (i.e. there's no index for `this` on instance methods) - DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition method, int index); - - DynamicallyAccessedMemberTypes GetReturnParameterAnnotation (MethodDefinition method); - - // Should return annotation which applies to the "this" parameter of the method - // Note that this does not apply to the "this" parameter on extension methods, it's the this on instance methods. - DynamicallyAccessedMemberTypes GetThisParameterAnnotation (MethodDefinition method); - - DynamicallyAccessedMemberTypes GetFieldAnnotation (FieldDefinition field); - } -} diff --git a/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs b/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs index 20dec1cf6940..5db7d2479e66 100644 --- a/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs +++ b/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs @@ -4,20 +4,19 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; +using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Xml.XPath; using Mono.Cecil; +using Mono.Cecil.Rocks; namespace Mono.Linker.Dataflow { - class XmlFlowAnnotationSource : IFlowAnnotationSource + class XmlFlowAnnotationSource { - readonly Dictionary _methods = new Dictionary (); - readonly Dictionary _properties = new Dictionary (); - readonly Dictionary _fields = new Dictionary (); + readonly Dictionary> _attributes = new Dictionary> (); readonly LinkContext _context; XPathDocument _document; @@ -28,80 +27,121 @@ public XmlFlowAnnotationSource (LinkContext context) _context = context; } - public DynamicallyAccessedMemberTypes GetFieldAnnotation (FieldDefinition field) + public IEnumerable GetCustomAttributes (ICustomAttributeProvider provider) { - return _fields.TryGetValue (field, out var ann) ? ann : DynamicallyAccessedMemberTypes.None; + return _attributes.TryGetValue (provider, out var ann) ? ann : null; } - public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition method, int index) + public bool HasCustomAttributes (ICustomAttributeProvider provider) { - DynamicallyAccessedMemberTypes parameterAnnotation = DynamicallyAccessedMemberTypes.None; + return _attributes.ContainsKey (provider); + } - if (_methods.TryGetValue (method, out var ann) && ann.ParameterAnnotations != null) { - string paramName = method.Parameters[index].Name; + IEnumerable ProcessAttributes (XPathNavigator nav) + { + XPathNodeIterator iterator = nav.SelectChildren ("attribute", string.Empty); + var attributes = new List (); + while (iterator.MoveNext ()) { + AssemblyDefinition assembly; + TypeDefinition attributeType; - bool firstAppearance = true; - foreach (var (ParamName, Annotation) in ann.ParameterAnnotations) { - if (ParamName == paramName && firstAppearance) { - firstAppearance = false; - parameterAnnotation = Annotation; - } else if (ParamName == paramName && !firstAppearance) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"There are duplicate parameter names for '{paramName}' inside '{method.Name}' in '{_xmlDocumentLocation}'", 2024, _xmlDocumentLocation)); + string attributeFullName = GetFullName (iterator.Current); + if (attributeFullName == String.Empty) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute element does not contain attribute 'fullname'", 2029)); + continue; + } + string concatAttribute; + concatAttribute = attributeFullName.EndsWith ("Attribute") ? attributeFullName : String.Concat (attributeFullName, "Attribute"); + string assemblyName = GetAttribute (iterator.Current, "assembly"); + if (assemblyName == String.Empty) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute element doest not contain attribute 'assembly' in xml element '{attributeFullName}'", 2030)); + continue; + } else if (assemblyName == "*") + attributeType = GetTypeFromName (concatAttribute); + else { + try { + assembly = GetAssembly (_context, AssemblyNameReference.Parse (assemblyName)); + } catch (Exception) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve assembly '{assemblyName}' in attribute '{attributeFullName}' specified in the '{_xmlDocumentLocation}'", 2031)); + continue; } + attributeType = assembly.FindType (concatAttribute); + } + if (attributeType == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute type '{attributeFullName}' could not be found", 2032)); + continue; } - } - return parameterAnnotation; - } + ArrayBuilder arguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)); + MethodDefinition constructor = attributeType.GetConstructors ().FirstOrDefault (c => c.Parameters.Count == arguments.Count); + if (constructor == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find a constructor for type '{attributeType}' that receives '{arguments.Count}' arguments as parameter", 2022)); + continue; + } + string[] xmlArguments = arguments.ToArray (); + bool recognizedArgument = true; - public DynamicallyAccessedMemberTypes GetPropertyAnnotation (PropertyDefinition property) - { - return _properties.TryGetValue (property, out var ann) ? ann : DynamicallyAccessedMemberTypes.None; - } + CustomAttribute attribute = new CustomAttribute (constructor); + for (int i = 0; i < xmlArguments.Length; i++) { + object argumentValue = null; - public DynamicallyAccessedMemberTypes GetReturnParameterAnnotation (MethodDefinition method) - { - return _methods.TryGetValue (method, out var ann) ? ann.ReturnAnnotation : DynamicallyAccessedMemberTypes.None; + if (constructor.Parameters[i].ParameterType.Resolve ().IsEnum) { + foreach (var field in constructor.Parameters[i].ParameterType.Resolve ().Fields) { + if (field.IsStatic && field.Name == xmlArguments[i]) { + argumentValue = Convert.ToInt32 (field.Constant); + break; + } + } + if (argumentValue == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not parse argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' as a {constructor.Parameters[i].ParameterType.FullName}", 2021)); + recognizedArgument = false; + } + } else { + switch (constructor.Parameters[i].ParameterType.MetadataType) { + case MetadataType.String: + argumentValue = xmlArguments[i]; + break; + case MetadataType.Int32: + argumentValue = int.Parse (xmlArguments[i]); + break; + default: + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to a currently supported metadatatype in the xml", 2020)); + recognizedArgument = false; + break; + } + } + attribute.ConstructorArguments.Add (new CustomAttributeArgument (constructor.Parameters[i].ParameterType, argumentValue)); + } + if (recognizedArgument) + attributes.Add (attribute); + } + return attributes; } - public DynamicallyAccessedMemberTypes GetThisParameterAnnotation (MethodDefinition method) + public TypeDefinition GetTypeFromName (string fullName) { - if (_methods.TryGetValue (method, out var ann) && ann.ParameterAnnotations != null) { - foreach (var (ParamName, Annotation) in ann.ParameterAnnotations) - if (ParamName == "this") - return Annotation; - } + TypeDefinition attributeType; + foreach (AssemblyDefinition asm in _context.GetAssemblies ()) { + attributeType = asm.FindType (fullName); + if (attributeType != null) + return attributeType; - return DynamicallyAccessedMemberTypes.None; + foreach (AssemblyDefinition refasm in _context.ResolveReferences (asm)) { + attributeType = refasm.FindType (fullName); + if (attributeType != null) + return attributeType; + } + } + return null; } - static DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (ArrayBuilder attributes, LinkContext _context, string _xmlDocumentLocation) + ArrayBuilder GetAttributeChildren (XPathNodeIterator iterator) { - foreach (var attribute in attributes.ToArray ()) { - if (attribute.attributeName == "System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembers") { - if (attribute.arguments.Count == 0) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"DynamicallyAccessedMembers attribute was specified but no argument was proportioned", - 2020, _xmlDocumentLocation)); - } else if (attribute.arguments.Count == 1) { - DynamicallyAccessedMemberTypes result; - foreach (var argument in attribute.arguments.ToArray ()) { - if (argument == string.Empty) - break; - if (Enum.TryParse (argument, false, out result)) { - return result; - } else { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Could not parse argument '{argument}' specified in '{_xmlDocumentLocation}' as a DynamicallyAccessedMemberTypes", 2021, _xmlDocumentLocation)); - } - } - } else { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"DynamicallyAccessedMembers attribute was specified but there is more than one argument", 2022, _xmlDocumentLocation)); - } - } + ArrayBuilder childs = new ArrayBuilder (); + while (iterator.MoveNext ()) { + childs.Add (iterator.Current.Value); } - return DynamicallyAccessedMemberTypes.None; + return childs; } public void ParseXml (string document) @@ -124,45 +164,31 @@ public void ParseXml (string document) private void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator) { while (iterator.MoveNext ()) { - if (!ShouldProcessElement (iterator.Current)) { + if (!ShouldProcessElement (iterator.Current)) return; - } - AssemblyDefinition assembly = GetAssembly (context, GetAssemblyName (iterator.Current)); + if (GetFullName (iterator.Current) == "*") { + foreach (AssemblyDefinition assemblyIterator in context.GetAssemblies ()) { + ProcessTypes (assemblyIterator, iterator); + } + } else { + AssemblyDefinition assembly = GetAssembly (context, GetAssemblyName (iterator.Current)); - if (assembly == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Could not resolve assembly {GetAssemblyName (iterator.Current).Name} specified in {_xmlDocumentLocation}", 2007, _xmlDocumentLocation)); - continue; + if (assembly == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve assembly {GetAssemblyName (iterator.Current).Name} specified in {_xmlDocumentLocation}", 2007)); + continue; + } + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[assembly] = attributes; + ProcessTypes (assembly, iterator); } - ProcessTypes (assembly, iterator.Current.SelectChildren ("type", string.Empty)); - } - } - - ArrayBuilder ProcessAttributes (XPathNodeIterator iterator) - { - iterator = iterator.Current.SelectChildren ("attribute", string.Empty); - var attributes = new ArrayBuilder (); - while (iterator.MoveNext ()) { - string attributeName = GetFullName (iterator.Current); - ArrayBuilder arguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)); - - attributes.Add (new Attribute (attributeName, arguments)); } - return attributes; - } - - ArrayBuilder GetAttributeChildren (XPathNodeIterator iterator) - { - ArrayBuilder childs = new ArrayBuilder (); - while (iterator.MoveNext ()) { - childs.Add (iterator.Current.Value); - } - return childs; } void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator) { + iterator = iterator.Current.SelectChildren ("type", string.Empty); while (iterator.MoveNext ()) { XPathNavigator nav = iterator.Current; @@ -191,7 +217,7 @@ void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator) } if (type == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not resolve type '{fullname}' specified in {_xmlDocumentLocation}", 2008, _xmlDocumentLocation)); + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve type '{fullname}' specified in {_xmlDocumentLocation}", 2008)); continue; } @@ -233,6 +259,9 @@ void ProcessTypePattern (string fullname, AssemblyDefinition assembly, XPathNavi void ProcessType (TypeDefinition type, XPathNavigator nav) { + IEnumerable attributes = ProcessAttributes (nav); + if (attributes.Count () > 0) + _attributes[type] = attributes; ProcessTypeChildren (type, nav); if (!type.HasNestedTypes) @@ -242,7 +271,7 @@ void ProcessType (TypeDefinition type, XPathNavigator nav) while (iterator.MoveNext ()) { foreach (TypeDefinition nested in type.NestedTypes) { if (nested.Name == GetAttribute (iterator.Current, "name") && ShouldProcessElement (iterator.Current)) - ProcessTypeChildren (nested, iterator.Current); + ProcessType (nested, iterator.Current); } } } @@ -253,6 +282,7 @@ void ProcessTypeChildren (TypeDefinition type, XPathNavigator nav) ProcessSelectedFields (nav, type); ProcessSelectedMethods (nav, type); ProcessSelectedProperties (nav, type); + ProcessSelectedEvents (nav, type); } } @@ -317,18 +347,36 @@ void ProcessSelectedProperties (XPathNavigator nav, TypeDefinition type) } } + void ProcessSelectedEvents (XPathNavigator nav, TypeDefinition type) + { + XPathNodeIterator events = nav.SelectChildren ("event", string.Empty); + if (events.Count == 0) + return; + while (events.MoveNext ()) { + if (!ShouldProcessElement (events.Current)) { + return; + } + + string value = GetSignature (events.Current); + if (!String.IsNullOrEmpty (value)) + ProcessEventSignature (type, value, events); + + value = GetAttribute (events.Current, "name"); + if (!String.IsNullOrEmpty (value)) + ProcessEventName (type, value, events); + } + } + void ProcessFieldSignature (TypeDefinition type, string signature, XPathNodeIterator iterator) { FieldDefinition field = GetField (type, signature); if (field == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Could not find field '{signature}' in type '{type.FullName}' specified in { _xmlDocumentLocation}", 2016, _xmlDocumentLocation)); + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find field '{signature}' in type '{type.FullName}' specified in { _xmlDocumentLocation}", 2016)); return; } - ArrayBuilder attributes = ProcessAttributes (iterator); - DynamicallyAccessedMemberTypes fieldAnnotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (attributes, _context, _xmlDocumentLocation); - if (fieldAnnotation != DynamicallyAccessedMemberTypes.None) - _fields[field] = fieldAnnotation; + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[field] = attributes; } void ProcessFieldName (TypeDefinition type, string name, XPathNodeIterator iterator) @@ -338,10 +386,9 @@ void ProcessFieldName (TypeDefinition type, string name, XPathNodeIterator itera foreach (FieldDefinition field in type.Fields) { if (field.Name == name) { - ArrayBuilder attributes = ProcessAttributes (iterator); - DynamicallyAccessedMemberTypes fieldAnnotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (attributes, _context, _xmlDocumentLocation); - if (fieldAnnotation != DynamicallyAccessedMemberTypes.None) - _fields[field] = fieldAnnotation; + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[field] = attributes; } } } @@ -362,66 +409,54 @@ void ProcessMethodSignature (TypeDefinition type, string signature, XPathNodeIte { MethodDefinition method = GetMethod (type, signature); if (method == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Could not find method '{signature}' in type '{type.FullName}' specified in '{_xmlDocumentLocation}'", 2009, _xmlDocumentLocation)); + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find method '{signature}' in type '{type.FullName}' specified in '{_xmlDocumentLocation}'", 2009)); return; } - ProcessMethodChildren (type, method, iterator); + ProcessMethod (type, method, iterator); } - void ProcessMethodChildren (TypeDefinition type, MethodDefinition method, XPathNodeIterator iterator) + void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNodeIterator iterator) { - ArrayBuilder attributes = ProcessAttributes (iterator); - ArrayBuilder<(string, ArrayBuilder)> parameterAnnotations = ProcessParameters (type, - method, iterator.Current.SelectChildren ("parameter", string.Empty)); - ArrayBuilder> returnParameterAnnotations = ProcessReturnParameters (type, - method, iterator.Current.SelectChildren ("return", string.Empty)); - - var parameterAnnotation = new ArrayBuilder<(string ParamName, DynamicallyAccessedMemberTypes Annotation)> (); - DynamicallyAccessedMemberTypes returnAnnotation = 0; - - if (parameterAnnotations.Count > 0) { - foreach (var parameter in parameterAnnotations.ToArray ()) { - DynamicallyAccessedMemberTypes paramAnnotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (parameter.Item2, _context, _xmlDocumentLocation); - if (paramAnnotation != 0) - parameterAnnotation.Add ((parameter.Item1, paramAnnotation)); - } - } - - if (returnParameterAnnotations.Count == 1) { - foreach (var returnparameter in returnParameterAnnotations.ToArray ()) { - DynamicallyAccessedMemberTypes returnparamAnnotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (returnparameter, _context, _xmlDocumentLocation); - if (returnparamAnnotation != 0) - returnAnnotation = returnparamAnnotation; - } - } else { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"There is more than one return parameter specified for '{method.Name}' in '{_xmlDocumentLocation}'", 2023, _xmlDocumentLocation)); - } - if (returnAnnotation != 0 || parameterAnnotation.Count > 0) - _methods[method] = new AnnotatedMethod (returnAnnotation, parameterAnnotation.ToArray ()); - + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[method] = attributes; + ProcessReturnParameters (type, method, iterator); + ProcessParameters (type, method, iterator); } - ArrayBuilder<(string, ArrayBuilder)> ProcessParameters (TypeDefinition type, - MethodDefinition method, XPathNodeIterator iterator) + void ProcessParameters (TypeDefinition type, MethodDefinition method, XPathNodeIterator iterator) { - var methodParameters = new ArrayBuilder<(string, ArrayBuilder)> (); + iterator = iterator.Current.SelectChildren ("parameter", string.Empty); while (iterator.MoveNext ()) { - methodParameters.Add ((GetAttribute (iterator.Current, "name"), ProcessAttributes (iterator))); + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) { + string paramName = GetAttribute (iterator.Current, "name"); + foreach (ParameterDefinition parameter in method.Parameters) { + if (paramName == parameter.Name) { + if (_attributes.ContainsKey (parameter)) + _context.LogMessage (MessageContainer.CreateWarningMessage ($"There are duplicate parameter names for '{paramName}' inside '{method.Name}' in '{_xmlDocumentLocation}'", 2024)); + _attributes[parameter] = attributes; + break; + } + } + } } - return methodParameters; } - ArrayBuilder> ProcessReturnParameters (TypeDefinition type, - MethodDefinition method, XPathNodeIterator iterator) + void ProcessReturnParameters (TypeDefinition type, MethodDefinition method, XPathNodeIterator iterator) { - var methodParameters = new ArrayBuilder> (); - + iterator = iterator.Current.SelectChildren ("return", string.Empty); + bool firstAppearance = true; while (iterator.MoveNext ()) { - methodParameters.Add (ProcessAttributes (iterator)); + if (firstAppearance) { + firstAppearance = false; + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[method.MethodReturnType] = attributes; + } else { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"There is more than one return parameter specified for '{method.Name}' in '{_xmlDocumentLocation}'", 2023)); + } } - return methodParameters; } void ProcessMethodName (TypeDefinition type, string name, XPathNodeIterator iterator) @@ -431,7 +466,7 @@ void ProcessMethodName (TypeDefinition type, string name, XPathNodeIterator iter foreach (MethodDefinition method in type.Methods) if (name == method.Name) - ProcessMethodChildren (type, method, iterator); + ProcessMethod (type, method, iterator); } static MethodDefinition GetMethod (TypeDefinition type, string signature) @@ -478,10 +513,9 @@ void ProcessPropertySignature (TypeDefinition type, string signature, XPathNodeI { PropertyDefinition property = GetProperty (type, signature); if (property != null) { - ArrayBuilder attributes = ProcessAttributes (iterator); - DynamicallyAccessedMemberTypes propertyAnnotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (attributes, _context, _xmlDocumentLocation); - if (propertyAnnotation != DynamicallyAccessedMemberTypes.None) - _properties[property] = propertyAnnotation; + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[property] = attributes; } } @@ -492,24 +526,37 @@ void ProcessPropertyName (TypeDefinition type, string name, XPathNodeIterator it foreach (PropertyDefinition property in type.Properties) { if (property.Name == name) { - ArrayBuilder attributes = ProcessAttributes (iterator); - DynamicallyAccessedMemberTypes propertyAnnotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (attributes, _context, _xmlDocumentLocation); - if (propertyAnnotation != DynamicallyAccessedMemberTypes.None) - _properties[property] = propertyAnnotation; + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[property] = attributes; } } } - static PropertyDefinition GetProperty (TypeDefinition type, string signature) + void ProcessEventSignature (TypeDefinition type, string signature, XPathNodeIterator iterator) { - if (!type.HasProperties) - return null; + EventDefinition @event = GetEvent (type, signature); + if (@event == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find event '{signature}' in type '{type.FullName}' specified in {_xmlDocumentLocation}", 2016)); + return; + } + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[@event] = attributes; + } - foreach (PropertyDefinition property in type.Properties) - if (signature == property.PropertyType.FullName + " " + property.Name) - return property; + void ProcessEventName (TypeDefinition type, string name, XPathNodeIterator iterator) + { + if (!type.HasEvents) + return; - return null; + foreach (EventDefinition @event in type.Events) { + if (@event.Name == name) { + IEnumerable attributes = ProcessAttributes (iterator.Current); + if (attributes.Count () > 0) + _attributes[@event] = attributes; + } + } } AssemblyDefinition GetAssembly (LinkContext context, AssemblyNameReference assemblyName) @@ -539,27 +586,30 @@ static string GetAttribute (XPathNavigator nav, string attribute) return nav.GetAttribute (attribute, string.Empty); } - private struct AnnotatedMethod + protected static EventDefinition GetEvent (TypeDefinition type, string signature) { - public readonly DynamicallyAccessedMemberTypes ReturnAnnotation; - public readonly (string ParamName, DynamicallyAccessedMemberTypes Annotation)[] ParameterAnnotations; + if (!type.HasEvents) + return null; - public AnnotatedMethod (DynamicallyAccessedMemberTypes returnAnnotation, - (string ParamName, DynamicallyAccessedMemberTypes Annotation)[] paramAnnotations) - => (ReturnAnnotation, ParameterAnnotations) = (returnAnnotation, paramAnnotations); + foreach (EventDefinition @event in type.Events) + if (signature == @event.EventType.FullName + " " + @event.Name) + return @event; + + return null; } - private struct Attribute + static PropertyDefinition GetProperty (TypeDefinition type, string signature) { - public string attributeName { get; set; } - public ArrayBuilder arguments { get; set; } + if (!type.HasProperties) + return null; - public Attribute (string _attributeName, ArrayBuilder _arguments) - { - attributeName = _attributeName; - arguments = _arguments; - } + foreach (PropertyDefinition property in type.Properties) + if (signature == property.PropertyType.FullName + " " + property.Name) + return property; + + return null; } + bool ShouldProcessElement (XPathNavigator nav) { var feature = GetAttribute (nav, "feature"); @@ -583,4 +633,4 @@ bool ShouldProcessElement (XPathNavigator nav) return bValue == featureSetting; } } -} +} \ No newline at end of file diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index f3f2f9df2696..a8ba8ea4ae56 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -162,19 +162,9 @@ public virtual void Process (LinkContext context) { _context = context; - IFlowAnnotationSource annotationSource = new AttributeFlowAnnotationSource (); - if (_context.AttributeDefinitions != null && _context.AttributeDefinitions.Count > 0) { - annotationSource = new AggregateFlowAnnotationSource ( - _context.AttributeDefinitions.Select (xmlStringPath => { - var xmlAnnotations = new XmlFlowAnnotationSource (_context); - xmlAnnotations.ParseXml (xmlStringPath); - return xmlAnnotations; - }) - .Append (annotationSource)); - } - - _flowAnnotations = new FlowAnnotations (annotationSource); + CustomAttributeSource annotationSources = new CustomAttributeSource (_context); + _flowAnnotations = new FlowAnnotations (_context, annotationSources); Initialize (); Process (); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs index e654b499ba05..5f0db25cbc8c 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs @@ -13,7 +13,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [SkipKeptItemsValidation] [SetupLinkerAttributeDefinitionsFile ("XmlAnnotations.xml")] - [LogContains ("warning IL2021: Could not parse argument 'NonValidArgument' specified in", true)] + [LogContains ("ILlinker: warning IL2032: Attribute type 'System.DoesNotExistattribute' could not be found")] + [LogContains ("ILlinker: warning IL2021: Could not parse argument 'NonValidArgument' specified in *", true)] class XmlAnnotations { public static void Main () @@ -38,6 +39,7 @@ public static void Main () [UnrecognizedReflectionAccessPattern (typeof (XmlAnnotations), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] [UnrecognizedReflectionAccessPattern (typeof (XmlAnnotations), nameof (RequireNonPublicConstructors), new Type[] { typeof (Type) })] + [RecognizedReflectionAccessPattern] private void ReadFromInstanceField () { RequireDefaultConstructor (_typeWithDefaultConstructor); @@ -46,6 +48,7 @@ private void ReadFromInstanceField () } [UnrecognizedReflectionAccessPattern (typeof (XmlAnnotations), nameof (RequirePublicConstructors), new Type[] { typeof (Type) })] + [RecognizedReflectionAccessPattern] private void TwoAnnotatedParameters ( Type type, Type type2) diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml index 0fad8df94030..35046e1910d5 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml @@ -3,54 +3,54 @@ - + 0 - + DefaultConstructor - + DefaultConstructor - + PublicConstructors - + NonValidArgument - + DefaultConstructor - + DefaultConstructor - + DefaultConstructor - + DefaultConstructor From 19504f746a7e9e81e89a01dc087980236959a358 Mon Sep 17 00:00:00 2001 From: Tlakollo Date: Tue, 26 May 2020 23:13:15 -0700 Subject: [PATCH 2/6] - Fix whitespace - Fix review comments --- docs/data-formats.md | 38 +++++------------ docs/error-codes.md | 10 +++-- .../Linker.Dataflow/CustomAttributeSource.cs | 21 ++++++---- src/linker/Linker.Dataflow/FlowAnnotations.cs | 16 +++---- .../XmlFlowAnnotationSource.cs | 42 +++++++------------ .../DataFlow/XmlAnnotations.xml | 2 +- 6 files changed, 53 insertions(+), 76 deletions(-) diff --git a/docs/data-formats.md b/docs/data-formats.md index 78fd4b06b3b5..b8d7df1fa931 100644 --- a/docs/data-formats.md +++ b/docs/data-formats.md @@ -259,7 +259,7 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor @@ -275,7 +275,7 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor @@ -308,21 +308,21 @@ This allows to add a custom attribute to a class, interface, delegate, struct or - + DefaultConstructor - + PublicConstructors - + DefaultConstructor @@ -332,24 +332,6 @@ This allows to add a custom attribute to a class, interface, delegate, struct or ``` -### DynamicallyAccessedMembers attribute in implicit this parameter - -In the case of the implicit "this" parameter the way to include a custom attribute is to include an attribute -directly on the method element - -```xml - - - - - - DefaultConstructor - - - - - - ### Custom attribute in multiple method parameters ```xml @@ -358,17 +340,17 @@ directly on the method element - + DefaultConstructor - + DefaultConstructor - + PublicConstructors @@ -386,7 +368,7 @@ directly on the method element - + DefaultConstructor @@ -409,7 +391,7 @@ attributes are applied. - + PublicConstructors diff --git a/docs/error-codes.md b/docs/error-codes.md index 2a129932738a..89131cb5748c 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -171,9 +171,9 @@ error and warning codes. - The linker found an instance of attribute 'attribute' on 'method' but it lacks a required constructor argument. Linker will ignore this attribute. -#### `IL2029`: There is no xml attribute 'fullname' in xml element '{attributeFullName}' +#### `IL2029`: Attribute element does not contain attribute 'fullname' -- The linker found an instance of attribute 'attribute' on 'method' but it lacks a required constructor argument. Linker will ignore this attribute. +- An attribute element was declared but does not contain the attribute 'fullname' or 'fullname' attribute is empty #### `IL2030`: There is no xml attribute 'assembly' in xml element 'attribute element' @@ -185,4 +185,8 @@ error and warning codes. #### `IL2032`: Attribute type 'attribute type' could not be found -- The described 'attribute type' could not be found in the assemblies \ No newline at end of file +- The described 'attribute type' could not be found in the assemblies + +#### `IL2033`: Argument 'argument' specified in 'XML document location' could not be transformed to the constructor parameter type + +- The number of arguments correspond to a certain type constructor, but the type of arguments specified in the xml does not match the type of arguments in the constructor. \ No newline at end of file diff --git a/src/linker/Linker.Dataflow/CustomAttributeSource.cs b/src/linker/Linker.Dataflow/CustomAttributeSource.cs index 516fe55cfc30..4d4b07e00ef6 100644 --- a/src/linker/Linker.Dataflow/CustomAttributeSource.cs +++ b/src/linker/Linker.Dataflow/CustomAttributeSource.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using Mono.Cecil; -using System.Collections.ObjectModel; using System.Linq; namespace Mono.Linker.Dataflow @@ -15,7 +14,7 @@ class CustomAttributeSource public CustomAttributeSource (LinkContext _context) { - Collection annotationSources = new Collection (); + ArrayBuilder annotationSources = new ArrayBuilder (); if (_context.AttributeDefinitions != null && _context.AttributeDefinitions.Count > 0) { foreach (string a in _context.AttributeDefinitions) { XmlFlowAnnotationSource xmlAnnotations = new XmlFlowAnnotationSource (_context); @@ -29,20 +28,24 @@ public CustomAttributeSource (LinkContext _context) public IEnumerable GetCustomAttributes (ICustomAttributeProvider provider) { IEnumerable aggregateAttributes = null; - foreach (var source in _sources) { - if (source.HasCustomAttributes (provider)) - aggregateAttributes = aggregateAttributes == null ? source.GetCustomAttributes (provider) : aggregateAttributes.Concat (source.GetCustomAttributes (provider)); + if (_sources != null) { + foreach (var source in _sources) { + if (source.HasCustomAttributes (provider)) + aggregateAttributes = aggregateAttributes == null ? source.GetCustomAttributes (provider) : aggregateAttributes.Concat (source.GetCustomAttributes (provider)); + } } if (provider.HasCustomAttributes) aggregateAttributes = aggregateAttributes == null ? provider.CustomAttributes : aggregateAttributes.Concat (provider.CustomAttributes); - return aggregateAttributes ?? Enumerable.Empty(); + return aggregateAttributes ?? Enumerable.Empty (); } public bool HasCustomAttributes (ICustomAttributeProvider provider) { - foreach (var source in _sources) { - if (source.HasCustomAttributes (provider)) { - return true; + if (_sources != null) { + foreach (var source in _sources) { + if (source.HasCustomAttributes (provider)) { + return true; + } } } if (provider.HasCustomAttributes) { diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs index 0e90672d1be8..b07d616352cc 100644 --- a/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -53,10 +53,10 @@ public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition m return DynamicallyAccessedMemberTypes.None; } - public DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (CustomAttributeSource source, ICustomAttributeProvider provider) + private DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (ICustomAttributeProvider provider) { - if (source.HasCustomAttributes (provider)) { - foreach (var attribute in source.GetCustomAttributes (provider)) { + if (_source.HasCustomAttributes (provider)) { + foreach (var attribute in _source.GetCustomAttributes (provider)) { if (IsDynamicallyAccessedMembersAttribute (attribute)) { if (attribute.ConstructorArguments.Count == 0) { _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but no argument was proportioned", 2020)); @@ -110,7 +110,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (!IsTypeInterestingForDataflow (field.FieldType)) continue; - DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, field); + DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (field); if (annotation == DynamicallyAccessedMemberTypes.None) { continue; } @@ -134,7 +134,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) if (method.HasImplicitThis ()) { offset = 1; if (IsTypeInterestingForDataflow (method.DeclaringType)) { - DynamicallyAccessedMemberTypes ta = GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, method); + DynamicallyAccessedMemberTypes ta = GetMemberTypesForDynamicallyAccessedMemberAttribute (method); if (ta != DynamicallyAccessedMemberTypes.None) { paramAnnotations = new DynamicallyAccessedMemberTypes[method.Parameters.Count + offset]; paramAnnotations[0] = ta; @@ -149,7 +149,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) continue; } - DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, method.Parameters[i]); + DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMemberAttribute (method.Parameters[i]); if (pa == DynamicallyAccessedMemberTypes.None) { continue; } @@ -161,7 +161,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) } DynamicallyAccessedMemberTypes returnAnnotation = IsTypeInterestingForDataflow (method.ReturnType) ? - GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, method.MethodReturnType) : DynamicallyAccessedMemberTypes.None; + GetMemberTypesForDynamicallyAccessedMemberAttribute (method.MethodReturnType) : DynamicallyAccessedMemberTypes.None; if (returnAnnotation != DynamicallyAccessedMemberTypes.None || paramAnnotations != null) { annotatedMethods.Add (new MethodAnnotations (method, paramAnnotations, returnAnnotation)); } @@ -189,7 +189,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) continue; } - DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (_source, property); + DynamicallyAccessedMemberTypes annotation = GetMemberTypesForDynamicallyAccessedMemberAttribute (property); if (annotation == DynamicallyAccessedMemberTypes.None) { continue; } diff --git a/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs b/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs index 5db7d2479e66..770a022b6961 100644 --- a/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs +++ b/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs @@ -10,7 +10,6 @@ using System.Xml.XPath; using Mono.Cecil; -using Mono.Cecil.Rocks; namespace Mono.Linker.Dataflow { @@ -57,7 +56,7 @@ IEnumerable ProcessAttributes (XPathNavigator nav) _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute element doest not contain attribute 'assembly' in xml element '{attributeFullName}'", 2030)); continue; } else if (assemblyName == "*") - attributeType = GetTypeFromName (concatAttribute); + attributeType = _context.GetType (concatAttribute); else { try { assembly = GetAssembly (_context, AssemblyNameReference.Parse (assemblyName)); @@ -73,7 +72,7 @@ IEnumerable ProcessAttributes (XPathNavigator nav) } ArrayBuilder arguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)); - MethodDefinition constructor = attributeType.GetConstructors ().FirstOrDefault (c => c.Parameters.Count == arguments.Count); + MethodDefinition constructor = attributeType.Methods.Where (method => method.IsConstructor).FirstOrDefault (c => c.Parameters.Count == arguments.Count); if (constructor == null) { _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find a constructor for type '{attributeType}' that receives '{arguments.Count}' arguments as parameter", 2022)); continue; @@ -102,7 +101,12 @@ IEnumerable ProcessAttributes (XPathNavigator nav) argumentValue = xmlArguments[i]; break; case MetadataType.Int32: - argumentValue = int.Parse (xmlArguments[i]); + int result; + if (int.TryParse (xmlArguments[i], out result)) + argumentValue = result; + else { + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to the constructor parameter type", 2033)); + } break; default: _context.LogMessage (MessageContainer.CreateWarningMessage ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to a currently supported metadatatype in the xml", 2020)); @@ -118,30 +122,13 @@ IEnumerable ProcessAttributes (XPathNavigator nav) return attributes; } - public TypeDefinition GetTypeFromName (string fullName) - { - TypeDefinition attributeType; - foreach (AssemblyDefinition asm in _context.GetAssemblies ()) { - attributeType = asm.FindType (fullName); - if (attributeType != null) - return attributeType; - - foreach (AssemblyDefinition refasm in _context.ResolveReferences (asm)) { - attributeType = refasm.FindType (fullName); - if (attributeType != null) - return attributeType; - } - } - return null; - } - ArrayBuilder GetAttributeChildren (XPathNodeIterator iterator) { - ArrayBuilder childs = new ArrayBuilder (); + ArrayBuilder children = new ArrayBuilder (); while (iterator.MoveNext ()) { - childs.Add (iterator.Current.Value); + children.Add (iterator.Current.Value); } - return childs; + return children; } public void ParseXml (string document) @@ -169,7 +156,7 @@ private void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator) if (GetFullName (iterator.Current) == "*") { foreach (AssemblyDefinition assemblyIterator in context.GetAssemblies ()) { - ProcessTypes (assemblyIterator, iterator); + ProcessTypes (assemblyIterator, iterator, true); } } else { AssemblyDefinition assembly = GetAssembly (context, GetAssemblyName (iterator.Current)); @@ -186,7 +173,7 @@ private void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator) } } - void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator) + void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator, bool searchOnAllAssemblies = false) { iterator = iterator.Current.SelectChildren ("type", string.Empty); while (iterator.MoveNext ()) { @@ -217,7 +204,8 @@ void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator) } if (type == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve type '{fullname}' specified in {_xmlDocumentLocation}", 2008)); + if (!searchOnAllAssemblies) + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve type '{fullname}' specified in {_xmlDocumentLocation}", 2008)); continue; } diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml index 35046e1910d5..2498fa4769cb 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml @@ -6,7 +6,7 @@ 0 - + DefaultConstructor From 627d0ee19c0df0b99c801111f1873c9c24deac97 Mon Sep 17 00:00:00 2001 From: Tlakollo Date: Mon, 1 Jun 2020 16:51:38 -0700 Subject: [PATCH 3/6] - Fix git comments --- docs/data-formats.md | 5 +-- docs/error-codes.md | 10 ++---- .../Linker.Dataflow/CustomAttributeSource.cs | 35 +++++++++---------- src/linker/Linker.Dataflow/FlowAnnotations.cs | 24 ++++++------- .../XmlFlowAnnotationSource.cs | 19 ++++------ .../DataFlow/XmlAnnotations.cs | 2 +- .../DataFlow/XmlAnnotations.xml | 16 ++++----- 7 files changed, 50 insertions(+), 61 deletions(-) diff --git a/docs/data-formats.md b/docs/data-formats.md index b8d7df1fa931..61e507e1f630 100644 --- a/docs/data-formats.md +++ b/docs/data-formats.md @@ -403,8 +403,9 @@ attributes are applied. ### Custom attributes elements -The attribute element requires fullname and assembly attributes without them it will generate -a warning and skip the attribute. +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 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 diff --git a/docs/error-codes.md b/docs/error-codes.md index 89131cb5748c..0890ec531419 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -175,18 +175,14 @@ error and warning codes. - An attribute element was declared but does not contain the attribute 'fullname' or 'fullname' attribute is empty -#### `IL2030`: There is no xml attribute 'assembly' in xml element 'attribute element' - -- The linker found an 'attribute element' on the xml file but it didnt contain an 'assembly' attribute - -#### `IL2031`: Could not resolve assembly 'assembly' in attribute 'attribute' specified in the 'XML document location' +#### `IL2030`: Could not resolve assembly 'assembly' in attribute 'attribute' specified in the 'XML document location' - The assembly 'assembly' described as a attribute property of 'attribute' could not be resolved in 'XML document location' -#### `IL2032`: Attribute type 'attribute type' could not be found +#### `IL2031`: Attribute type 'attribute type' could not be found - The described 'attribute type' could not be found in the assemblies -#### `IL2033`: Argument 'argument' specified in 'XML document location' could not be transformed to the constructor parameter type +#### `IL2032`: Argument 'argument' specified in 'XML document location' could not be transformed to the constructor parameter type - The number of arguments correspond to a certain type constructor, but the type of arguments specified in the xml does not match the type of arguments in the constructor. \ No newline at end of file diff --git a/src/linker/Linker.Dataflow/CustomAttributeSource.cs b/src/linker/Linker.Dataflow/CustomAttributeSource.cs index 4d4b07e00ef6..c2fa02f152ef 100644 --- a/src/linker/Linker.Dataflow/CustomAttributeSource.cs +++ b/src/linker/Linker.Dataflow/CustomAttributeSource.cs @@ -10,33 +10,35 @@ namespace Mono.Linker.Dataflow { class CustomAttributeSource { - private readonly XmlFlowAnnotationSource[] _sources; + private readonly List _sources; - public CustomAttributeSource (LinkContext _context) + public CustomAttributeSource (LinkContext context) { - ArrayBuilder annotationSources = new ArrayBuilder (); - if (_context.AttributeDefinitions != null && _context.AttributeDefinitions.Count > 0) { - foreach (string a in _context.AttributeDefinitions) { - XmlFlowAnnotationSource xmlAnnotations = new XmlFlowAnnotationSource (_context); + List annotationSources = new List (); + if (context.AttributeDefinitions?.Count > 0) { + foreach (string a in context.AttributeDefinitions) { + XmlFlowAnnotationSource xmlAnnotations = new XmlFlowAnnotationSource (context); xmlAnnotations.ParseXml (a); annotationSources.Add (xmlAnnotations); } } - _sources = annotationSources.ToArray (); + _sources = annotationSources; } public IEnumerable GetCustomAttributes (ICustomAttributeProvider provider) { - IEnumerable aggregateAttributes = null; - if (_sources != null) { + if (_sources.Count > 0) { foreach (var source in _sources) { - if (source.HasCustomAttributes (provider)) - aggregateAttributes = aggregateAttributes == null ? source.GetCustomAttributes (provider) : aggregateAttributes.Concat (source.GetCustomAttributes (provider)); + if (source.HasCustomAttributes (provider)) { + foreach (var customAttribute in source.GetCustomAttributes (provider)) + yield return customAttribute; + } } } - if (provider.HasCustomAttributes) - aggregateAttributes = aggregateAttributes == null ? provider.CustomAttributes : aggregateAttributes.Concat (provider.CustomAttributes); - return aggregateAttributes ?? Enumerable.Empty (); + if (provider.HasCustomAttributes) { + foreach (var customAttribute in provider.CustomAttributes) + yield return customAttribute; + } } public bool HasCustomAttributes (ICustomAttributeProvider provider) @@ -48,10 +50,7 @@ public bool HasCustomAttributes (ICustomAttributeProvider provider) } } } - if (provider.HasCustomAttributes) { - return true; - } - return false; + return provider.HasCustomAttributes; } } } diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs index b07d616352cc..1c75e9870cc5 100644 --- a/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -55,19 +55,17 @@ public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition m private DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (ICustomAttributeProvider provider) { - if (_source.HasCustomAttributes (provider)) { - foreach (var attribute in _source.GetCustomAttributes (provider)) { - if (IsDynamicallyAccessedMembersAttribute (attribute)) { - if (attribute.ConstructorArguments.Count == 0) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but no argument was proportioned", 2020)); - } else if (attribute.ConstructorArguments.Count == 1) { - var arguments = attribute.ConstructorArguments.ToArray (); - return (DynamicallyAccessedMemberTypes) arguments[0].Value; - } else { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but there is more than one argument", 2022)); - } - } - } + if (!_source.HasCustomAttributes (provider)) + return DynamicallyAccessedMemberTypes.None; + foreach (var attribute in _source.GetCustomAttributes (provider)) { + if (!IsDynamicallyAccessedMembersAttribute (attribute)) + continue; + if (attribute.ConstructorArguments.Count == 0) + _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but no argument was proportioned", 2020)); + else if (attribute.ConstructorArguments.Count == 1) + return (DynamicallyAccessedMemberTypes) (int) attribute.ConstructorArguments[0].Value; + else + _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but there is more than one argument", 2022)); } return DynamicallyAccessedMemberTypes.None; } diff --git a/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs b/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs index 770a022b6961..b79a6f6e8497 100644 --- a/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs +++ b/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs @@ -49,30 +49,25 @@ IEnumerable ProcessAttributes (XPathNavigator nav) _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute element does not contain attribute 'fullname'", 2029)); continue; } - string concatAttribute; - concatAttribute = attributeFullName.EndsWith ("Attribute") ? attributeFullName : String.Concat (attributeFullName, "Attribute"); string assemblyName = GetAttribute (iterator.Current, "assembly"); - if (assemblyName == String.Empty) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute element doest not contain attribute 'assembly' in xml element '{attributeFullName}'", 2030)); - continue; - } else if (assemblyName == "*") - attributeType = _context.GetType (concatAttribute); + if (assemblyName == String.Empty) + attributeType = _context.GetType (attributeFullName); else { try { assembly = GetAssembly (_context, AssemblyNameReference.Parse (assemblyName)); } catch (Exception) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve assembly '{assemblyName}' in attribute '{attributeFullName}' specified in the '{_xmlDocumentLocation}'", 2031)); + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve assembly '{assemblyName}' in attribute '{attributeFullName}' specified in the '{_xmlDocumentLocation}'", 2030)); continue; } - attributeType = assembly.FindType (concatAttribute); + attributeType = assembly.FindType (attributeFullName); } if (attributeType == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute type '{attributeFullName}' could not be found", 2032)); + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute type '{attributeFullName}' could not be found", 2031)); continue; } ArrayBuilder arguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)); - MethodDefinition constructor = attributeType.Methods.Where (method => method.IsConstructor).FirstOrDefault (c => c.Parameters.Count == arguments.Count); + MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == arguments.Count); if (constructor == null) { _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find a constructor for type '{attributeType}' that receives '{arguments.Count}' arguments as parameter", 2022)); continue; @@ -105,7 +100,7 @@ IEnumerable ProcessAttributes (XPathNavigator nav) if (int.TryParse (xmlArguments[i], out result)) argumentValue = result; else { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to the constructor parameter type", 2033)); + _context.LogMessage (MessageContainer.CreateWarningMessage ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to the constructor parameter type", 2032)); } break; default: diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs index 5f0db25cbc8c..8b56bdd8c098 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] [SetupLinkerAttributeDefinitionsFile ("XmlAnnotations.xml")] - [LogContains ("ILlinker: warning IL2032: Attribute type 'System.DoesNotExistattribute' could not be found")] + [LogContains ("ILlinker: warning IL2031: Attribute type 'System.DoesNotExistattribute' could not be found")] [LogContains ("ILlinker: warning IL2021: Could not parse argument 'NonValidArgument' specified in *", true)] class XmlAnnotations { diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml index 2498fa4769cb..56c3dce01a82 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.xml @@ -6,51 +6,51 @@ 0 - + DefaultConstructor - + DefaultConstructor - + PublicConstructors - + NonValidArgument - + DefaultConstructor - + DefaultConstructor - + DefaultConstructor - + DefaultConstructor From 4d8d45d6fe3875cc4ab3282bb81df3dec347c6c3 Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Tue, 2 Jun 2020 04:22:40 -0700 Subject: [PATCH 4/6] Move attribute sources to the main linker namespace --- .../CustomAttributeSource.cs | 12 ++++------ .../XmlCustomAttributeSource.cs} | 23 +++++++++---------- 2 files changed, 16 insertions(+), 19 deletions(-) rename src/linker/{Linker.Dataflow => Linker}/CustomAttributeSource.cs (77%) rename src/linker/{Linker.Dataflow/XmlFlowAnnotationSource.cs => Linker/XmlCustomAttributeSource.cs} (96%) diff --git a/src/linker/Linker.Dataflow/CustomAttributeSource.cs b/src/linker/Linker/CustomAttributeSource.cs similarity index 77% rename from src/linker/Linker.Dataflow/CustomAttributeSource.cs rename to src/linker/Linker/CustomAttributeSource.cs index c2fa02f152ef..89e328faaff3 100644 --- a/src/linker/Linker.Dataflow/CustomAttributeSource.cs +++ b/src/linker/Linker/CustomAttributeSource.cs @@ -4,25 +4,23 @@ using System.Collections.Generic; using Mono.Cecil; -using System.Linq; -namespace Mono.Linker.Dataflow +namespace Mono.Linker { class CustomAttributeSource { - private readonly List _sources; + readonly List _sources; public CustomAttributeSource (LinkContext context) { - List annotationSources = new List (); + _sources = new List(); if (context.AttributeDefinitions?.Count > 0) { foreach (string a in context.AttributeDefinitions) { - XmlFlowAnnotationSource xmlAnnotations = new XmlFlowAnnotationSource (context); + XmlCustomAttributeSource xmlAnnotations = new XmlCustomAttributeSource (context); xmlAnnotations.ParseXml (a); - annotationSources.Add (xmlAnnotations); + _sources.Add (xmlAnnotations); } } - _sources = annotationSources; } public IEnumerable GetCustomAttributes (ICustomAttributeProvider provider) diff --git a/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs b/src/linker/Linker/XmlCustomAttributeSource.cs similarity index 96% rename from src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs rename to src/linker/Linker/XmlCustomAttributeSource.cs index b79a6f6e8497..ac1607ac1663 100644 --- a/src/linker/Linker.Dataflow/XmlFlowAnnotationSource.cs +++ b/src/linker/Linker/XmlCustomAttributeSource.cs @@ -8,12 +8,11 @@ using System.Text; using System.Text.RegularExpressions; using System.Xml.XPath; - using Mono.Cecil; -namespace Mono.Linker.Dataflow +namespace Mono.Linker { - class XmlFlowAnnotationSource + class XmlCustomAttributeSource { readonly Dictionary> _attributes = new Dictionary> (); @@ -21,7 +20,7 @@ class XmlFlowAnnotationSource XPathDocument _document; string _xmlDocumentLocation; - public XmlFlowAnnotationSource (LinkContext context) + public XmlCustomAttributeSource (LinkContext context) { _context = context; } @@ -143,7 +142,7 @@ public void ParseXml (string document) } } - private void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator) + void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator) { while (iterator.MoveNext ()) { if (!ShouldProcessElement (iterator.Current)) @@ -395,19 +394,19 @@ void ProcessMethodSignature (TypeDefinition type, string signature, XPathNodeIte _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find method '{signature}' in type '{type.FullName}' specified in '{_xmlDocumentLocation}'", 2009)); return; } - ProcessMethod (type, method, iterator); + ProcessMethod (method, iterator); } - void ProcessMethod (TypeDefinition type, MethodDefinition method, XPathNodeIterator iterator) + void ProcessMethod (MethodDefinition method, XPathNodeIterator iterator) { IEnumerable attributes = ProcessAttributes (iterator.Current); if (attributes.Count () > 0) _attributes[method] = attributes; - ProcessReturnParameters (type, method, iterator); - ProcessParameters (type, method, iterator); + ProcessReturnParameters (method, iterator); + ProcessParameters (method, iterator); } - void ProcessParameters (TypeDefinition type, MethodDefinition method, XPathNodeIterator iterator) + void ProcessParameters (MethodDefinition method, XPathNodeIterator iterator) { iterator = iterator.Current.SelectChildren ("parameter", string.Empty); while (iterator.MoveNext ()) { @@ -426,7 +425,7 @@ void ProcessParameters (TypeDefinition type, MethodDefinition method, XPathNodeI } } - void ProcessReturnParameters (TypeDefinition type, MethodDefinition method, XPathNodeIterator iterator) + void ProcessReturnParameters (MethodDefinition method, XPathNodeIterator iterator) { iterator = iterator.Current.SelectChildren ("return", string.Empty); bool firstAppearance = true; @@ -449,7 +448,7 @@ void ProcessMethodName (TypeDefinition type, string name, XPathNodeIterator iter foreach (MethodDefinition method in type.Methods) if (name == method.Name) - ProcessMethod (type, method, iterator); + ProcessMethod (method, iterator); } static MethodDefinition GetMethod (TypeDefinition type, string signature) From e8e6f549cf5b825b765ee510b16908ea0d66517d Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Tue, 2 Jun 2020 05:09:01 -0700 Subject: [PATCH 5/6] Fixes after rebase to master --- src/linker/Linker.Dataflow/FlowAnnotations.cs | 10 +++---- src/linker/Linker/CustomAttributeSource.cs | 2 +- src/linker/Linker/XmlCustomAttributeSource.cs | 28 +++++++++---------- .../DataFlow/XmlAnnotations.cs | 4 +-- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs index 1c75e9870cc5..1b5db029d2c1 100644 --- a/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -53,7 +53,7 @@ public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition m return DynamicallyAccessedMemberTypes.None; } - private DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (ICustomAttributeProvider provider) + DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (ICustomAttributeProvider provider, IMemberDefinition locationMember = null) { if (!_source.HasCustomAttributes (provider)) return DynamicallyAccessedMemberTypes.None; @@ -61,11 +61,11 @@ private DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMembe if (!IsDynamicallyAccessedMembersAttribute (attribute)) continue; if (attribute.ConstructorArguments.Count == 0) - _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but no argument was proportioned", 2020)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"DynamicallyAccessedMembersAttribute was specified but no argument was proportioned", 2020, locationMember ?? (provider as IMemberDefinition))); else if (attribute.ConstructorArguments.Count == 1) return (DynamicallyAccessedMemberTypes) (int) attribute.ConstructorArguments[0].Value; else - _context.LogMessage (MessageContainer.CreateWarningMessage ($"DynamicallyAccessedMembers attribute was specified but there is more than one argument", 2022)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"DynamicallyAccessedMembersAttribute was specified but there is more than one argument", 2022, locationMember ?? (provider as IMemberDefinition))); } return DynamicallyAccessedMemberTypes.None; } @@ -147,7 +147,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) continue; } - DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMemberAttribute (method.Parameters[i]); + DynamicallyAccessedMemberTypes pa = GetMemberTypesForDynamicallyAccessedMemberAttribute (method.Parameters[i], method); if (pa == DynamicallyAccessedMemberTypes.None) { continue; } @@ -159,7 +159,7 @@ TypeAnnotations BuildTypeAnnotations (TypeDefinition type) } DynamicallyAccessedMemberTypes returnAnnotation = IsTypeInterestingForDataflow (method.ReturnType) ? - GetMemberTypesForDynamicallyAccessedMemberAttribute (method.MethodReturnType) : DynamicallyAccessedMemberTypes.None; + GetMemberTypesForDynamicallyAccessedMemberAttribute (method.MethodReturnType, method) : DynamicallyAccessedMemberTypes.None; if (returnAnnotation != DynamicallyAccessedMemberTypes.None || paramAnnotations != null) { annotatedMethods.Add (new MethodAnnotations (method, paramAnnotations, returnAnnotation)); } diff --git a/src/linker/Linker/CustomAttributeSource.cs b/src/linker/Linker/CustomAttributeSource.cs index 89e328faaff3..232d9142fb04 100644 --- a/src/linker/Linker/CustomAttributeSource.cs +++ b/src/linker/Linker/CustomAttributeSource.cs @@ -13,7 +13,7 @@ class CustomAttributeSource public CustomAttributeSource (LinkContext context) { - _sources = new List(); + _sources = new List (); if (context.AttributeDefinitions?.Count > 0) { foreach (string a in context.AttributeDefinitions) { XmlCustomAttributeSource xmlAnnotations = new XmlCustomAttributeSource (context); diff --git a/src/linker/Linker/XmlCustomAttributeSource.cs b/src/linker/Linker/XmlCustomAttributeSource.cs index ac1607ac1663..70ebbf16c11c 100644 --- a/src/linker/Linker/XmlCustomAttributeSource.cs +++ b/src/linker/Linker/XmlCustomAttributeSource.cs @@ -45,7 +45,7 @@ IEnumerable ProcessAttributes (XPathNavigator nav) string attributeFullName = GetFullName (iterator.Current); if (attributeFullName == String.Empty) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute element does not contain attribute 'fullname'", 2029)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Attribute element does not contain attribute 'fullname'", 2029, _xmlDocumentLocation)); continue; } string assemblyName = GetAttribute (iterator.Current, "assembly"); @@ -55,20 +55,20 @@ IEnumerable ProcessAttributes (XPathNavigator nav) try { assembly = GetAssembly (_context, AssemblyNameReference.Parse (assemblyName)); } catch (Exception) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve assembly '{assemblyName}' in attribute '{attributeFullName}' specified in the '{_xmlDocumentLocation}'", 2030)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not resolve assembly '{assemblyName}' in attribute '{attributeFullName}' specified in the '{_xmlDocumentLocation}'", 2030, _xmlDocumentLocation)); continue; } attributeType = assembly.FindType (attributeFullName); } if (attributeType == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Attribute type '{attributeFullName}' could not be found", 2031)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Attribute type '{attributeFullName}' could not be found", 2031, _xmlDocumentLocation)); continue; } ArrayBuilder arguments = GetAttributeChildren (iterator.Current.SelectChildren ("argument", string.Empty)); MethodDefinition constructor = attributeType.Methods.Where (method => method.IsInstanceConstructor ()).FirstOrDefault (c => c.Parameters.Count == arguments.Count); if (constructor == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find a constructor for type '{attributeType}' that receives '{arguments.Count}' arguments as parameter", 2022)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not find a constructor for type '{attributeType}' that receives '{arguments.Count}' arguments as parameter", 2022, _xmlDocumentLocation)); continue; } string[] xmlArguments = arguments.ToArray (); @@ -86,7 +86,7 @@ IEnumerable ProcessAttributes (XPathNavigator nav) } } if (argumentValue == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not parse argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' as a {constructor.Parameters[i].ParameterType.FullName}", 2021)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not parse argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' as a {constructor.Parameters[i].ParameterType.FullName}", 2021, _xmlDocumentLocation)); recognizedArgument = false; } } else { @@ -99,11 +99,11 @@ IEnumerable ProcessAttributes (XPathNavigator nav) if (int.TryParse (xmlArguments[i], out result)) argumentValue = result; else { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to the constructor parameter type", 2032)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to the constructor parameter type", 2032, _xmlDocumentLocation)); } break; default: - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to a currently supported metadatatype in the xml", 2020)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to a currently supported metadatatype in the xml", 2020, _xmlDocumentLocation)); recognizedArgument = false; break; } @@ -156,7 +156,7 @@ void ProcessAssemblies (LinkContext context, XPathNodeIterator iterator) AssemblyDefinition assembly = GetAssembly (context, GetAssemblyName (iterator.Current)); if (assembly == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve assembly {GetAssemblyName (iterator.Current).Name} specified in {_xmlDocumentLocation}", 2007)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not resolve assembly {GetAssemblyName (iterator.Current).Name} specified in {_xmlDocumentLocation}", 2007, _xmlDocumentLocation)); continue; } IEnumerable attributes = ProcessAttributes (iterator.Current); @@ -199,7 +199,7 @@ void ProcessTypes (AssemblyDefinition assembly, XPathNodeIterator iterator, bool if (type == null) { if (!searchOnAllAssemblies) - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not resolve type '{fullname}' specified in {_xmlDocumentLocation}", 2008)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not resolve type '{fullname}' specified in {_xmlDocumentLocation}", 2008, _xmlDocumentLocation)); continue; } @@ -353,7 +353,7 @@ void ProcessFieldSignature (TypeDefinition type, string signature, XPathNodeIter { FieldDefinition field = GetField (type, signature); if (field == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find field '{signature}' in type '{type.FullName}' specified in { _xmlDocumentLocation}", 2016)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not find field '{signature}' in type '{type.FullName}' specified in { _xmlDocumentLocation}", 2016, _xmlDocumentLocation)); return; } IEnumerable attributes = ProcessAttributes (iterator.Current); @@ -391,7 +391,7 @@ void ProcessMethodSignature (TypeDefinition type, string signature, XPathNodeIte { MethodDefinition method = GetMethod (type, signature); if (method == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find method '{signature}' in type '{type.FullName}' specified in '{_xmlDocumentLocation}'", 2009)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not find method '{signature}' in type '{type.FullName}' specified in '{_xmlDocumentLocation}'", 2009, _xmlDocumentLocation)); return; } ProcessMethod (method, iterator); @@ -416,7 +416,7 @@ void ProcessParameters (MethodDefinition method, XPathNodeIterator iterator) foreach (ParameterDefinition parameter in method.Parameters) { if (paramName == parameter.Name) { if (_attributes.ContainsKey (parameter)) - _context.LogMessage (MessageContainer.CreateWarningMessage ($"There are duplicate parameter names for '{paramName}' inside '{method.Name}' in '{_xmlDocumentLocation}'", 2024)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"There are duplicate parameter names for '{paramName}' inside '{method.Name}' in '{_xmlDocumentLocation}'", 2024, _xmlDocumentLocation)); _attributes[parameter] = attributes; break; } @@ -436,7 +436,7 @@ void ProcessReturnParameters (MethodDefinition method, XPathNodeIterator iterato if (attributes.Count () > 0) _attributes[method.MethodReturnType] = attributes; } else { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"There is more than one return parameter specified for '{method.Name}' in '{_xmlDocumentLocation}'", 2023)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"There is more than one return parameter specified for '{method.Name}' in '{_xmlDocumentLocation}'", 2023, _xmlDocumentLocation)); } } } @@ -519,7 +519,7 @@ void ProcessEventSignature (TypeDefinition type, string signature, XPathNodeIter { EventDefinition @event = GetEvent (type, signature); if (@event == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage ($"Could not find event '{signature}' in type '{type.FullName}' specified in {_xmlDocumentLocation}", 2016)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Could not find event '{signature}' in type '{type.FullName}' specified in {_xmlDocumentLocation}", 2016, _xmlDocumentLocation)); return; } IEnumerable attributes = ProcessAttributes (iterator.Current); diff --git a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs index 8b56bdd8c098..8a64c0dfffb4 100644 --- a/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs +++ b/test/Mono.Linker.Tests.Cases/DataFlow/XmlAnnotations.cs @@ -13,8 +13,8 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [SkipKeptItemsValidation] [SetupLinkerAttributeDefinitionsFile ("XmlAnnotations.xml")] - [LogContains ("ILlinker: warning IL2031: Attribute type 'System.DoesNotExistattribute' could not be found")] - [LogContains ("ILlinker: warning IL2021: Could not parse argument 'NonValidArgument' specified in *", true)] + [LogContains ("XmlAnnotations.xml: warning IL2031: Attribute type 'System.DoesNotExistattribute' could not be found")] + [LogContains ("XmlAnnotations.xml: warning IL2021: Could not parse argument 'NonValidArgument' specified in *", true)] class XmlAnnotations { public static void Main () From 2a5c1b88945c0d3aa03bd86f587e6d7f9f960bbc Mon Sep 17 00:00:00 2001 From: vitek-karas Date: Tue, 2 Jun 2020 09:37:56 -0700 Subject: [PATCH 6/6] PR feedback --- docs/data-formats.md | 14 ++++++ docs/error-codes.md | 4 +- src/linker/Linker.Dataflow/FlowAnnotations.cs | 46 +++++++++---------- src/linker/Linker/CustomAttributeSource.cs | 17 ++++--- src/linker/Linker/XmlCustomAttributeSource.cs | 2 +- 5 files changed, 51 insertions(+), 32 deletions(-) diff --git a/docs/data-formats.md b/docs/data-formats.md index 61e507e1f630..a875b0489504 100644 --- a/docs/data-formats.md +++ b/docs/data-formats.md @@ -378,6 +378,20 @@ This allows to add a custom attribute to a class, interface, delegate, struct or ``` +### Custom attribute on type in all assemblies + +```xml + + + + + DefaultConstructor + + + + +``` + ### Conditional custom attributes The `feature` and `featurevalue` attributes are optional, but must be used together when used. diff --git a/docs/error-codes.md b/docs/error-codes.md index 0890ec531419..94169850a548 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -135,9 +135,9 @@ error and warning codes. - The 'XML document location' defined the set accessor of property 'property' on type 'type', but the accessor was not found. -#### `IL2020`: Argument 'xml argument' specified in 'XML Document location' could not be transformed to a currently supported metadatatype in the xml +#### `IL2020`: Argument 'argument' specified in 'XML document location' is of unsupported type 'type' -- There is no way to convert the 'xml argument' string to the constructor parameter type. The constructor parameter type is not supported. +- The constructor parameter type is not supported in the XML reading code. #### `IL2021`: Could not parse argument 'argument' specified in 'XML document location' as a 'type' diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs index 1b5db029d2c1..43eec09e5cba 100644 --- a/src/linker/Linker.Dataflow/FlowAnnotations.cs +++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs @@ -23,12 +23,6 @@ public FlowAnnotations (LinkContext context, CustomAttributeSource annotationSou _context = context; } - public bool IsDynamicallyAccessedMembersAttribute (CustomAttribute attribute) - { - var attributeType = attribute.AttributeType; - return attributeType.Name == "DynamicallyAccessedMembersAttribute" && attributeType.Namespace == "System.Diagnostics.CodeAnalysis"; - } - public bool RequiresDataFlowAnalysis (MethodDefinition method) { return GetAnnotations (method.DeclaringType).TryGetAnnotation (method, out _); @@ -53,23 +47,6 @@ public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition m return DynamicallyAccessedMemberTypes.None; } - DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (ICustomAttributeProvider provider, IMemberDefinition locationMember = null) - { - if (!_source.HasCustomAttributes (provider)) - return DynamicallyAccessedMemberTypes.None; - foreach (var attribute in _source.GetCustomAttributes (provider)) { - if (!IsDynamicallyAccessedMembersAttribute (attribute)) - continue; - if (attribute.ConstructorArguments.Count == 0) - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"DynamicallyAccessedMembersAttribute was specified but no argument was proportioned", 2020, locationMember ?? (provider as IMemberDefinition))); - else if (attribute.ConstructorArguments.Count == 1) - return (DynamicallyAccessedMemberTypes) (int) attribute.ConstructorArguments[0].Value; - else - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"DynamicallyAccessedMembersAttribute was specified but there is more than one argument", 2022, locationMember ?? (provider as IMemberDefinition))); - } - return DynamicallyAccessedMemberTypes.None; - } - public DynamicallyAccessedMemberTypes GetReturnParameterAnnotation (MethodDefinition method) { if (GetAnnotations (method.DeclaringType).TryGetAnnotation (method, out var annotation)) { @@ -98,6 +75,29 @@ TypeAnnotations GetAnnotations (TypeDefinition type) return value; } + static bool IsDynamicallyAccessedMembersAttribute (CustomAttribute attribute) + { + var attributeType = attribute.AttributeType; + return attributeType.Name == "DynamicallyAccessedMembersAttribute" && attributeType.Namespace == "System.Diagnostics.CodeAnalysis"; + } + + DynamicallyAccessedMemberTypes GetMemberTypesForDynamicallyAccessedMemberAttribute (ICustomAttributeProvider provider, IMemberDefinition locationMember = null) + { + if (!_source.HasCustomAttributes (provider)) + return DynamicallyAccessedMemberTypes.None; + foreach (var attribute in _source.GetCustomAttributes (provider)) { + if (!IsDynamicallyAccessedMembersAttribute (attribute)) + continue; + if (attribute.ConstructorArguments.Count == 1) + return (DynamicallyAccessedMemberTypes) (int) attribute.ConstructorArguments[0].Value; + else if (attribute.ConstructorArguments.Count == 0) + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"DynamicallyAccessedMembersAttribute was specified but no argument was proportioned", 2020, locationMember ?? (provider as IMemberDefinition))); + else + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"DynamicallyAccessedMembersAttribute was specified but there is more than one argument", 2022, locationMember ?? (provider as IMemberDefinition))); + } + return DynamicallyAccessedMemberTypes.None; + } + TypeAnnotations BuildTypeAnnotations (TypeDefinition type) { var annotatedFields = new ArrayBuilder (); diff --git a/src/linker/Linker/CustomAttributeSource.cs b/src/linker/Linker/CustomAttributeSource.cs index 232d9142fb04..e9fd8198e1c6 100644 --- a/src/linker/Linker/CustomAttributeSource.cs +++ b/src/linker/Linker/CustomAttributeSource.cs @@ -25,6 +25,11 @@ public CustomAttributeSource (LinkContext context) public IEnumerable GetCustomAttributes (ICustomAttributeProvider provider) { + if (provider.HasCustomAttributes) { + foreach (var customAttribute in provider.CustomAttributes) + yield return customAttribute; + } + if (_sources.Count > 0) { foreach (var source in _sources) { if (source.HasCustomAttributes (provider)) { @@ -33,22 +38,22 @@ public IEnumerable GetCustomAttributes (ICustomAttributeProvide } } } - if (provider.HasCustomAttributes) { - foreach (var customAttribute in provider.CustomAttributes) - yield return customAttribute; - } } public bool HasCustomAttributes (ICustomAttributeProvider provider) { - if (_sources != null) { + if (provider.HasCustomAttributes) + return true; + + if (_sources.Count > 0) { foreach (var source in _sources) { if (source.HasCustomAttributes (provider)) { return true; } } } - return provider.HasCustomAttributes; + + return false; } } } diff --git a/src/linker/Linker/XmlCustomAttributeSource.cs b/src/linker/Linker/XmlCustomAttributeSource.cs index 70ebbf16c11c..dd883da76f99 100644 --- a/src/linker/Linker/XmlCustomAttributeSource.cs +++ b/src/linker/Linker/XmlCustomAttributeSource.cs @@ -103,7 +103,7 @@ IEnumerable ProcessAttributes (XPathNavigator nav) } break; default: - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' could not be transformed to a currently supported metadatatype in the xml", 2020, _xmlDocumentLocation)); + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Argument '{xmlArguments[i]}' specified in '{_xmlDocumentLocation}' is of unsupported type '{constructor.Parameters[i].ParameterType}'", 2020, _xmlDocumentLocation)); recognizedArgument = false; break; }