From 3d4d0e05cba44c5be926cc32d2a3b346f16318b7 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 26 May 2020 18:04:07 +0000 Subject: [PATCH 01/21] Add DynamicDependencyAttribute --- docs/error-codes.md | 30 ++- .../DynamicDependencyLookupStep.cs | 116 +++++++++++ src/linker/Linker.Steps/MarkStep.cs | 192 +++++++++++++++--- .../PreserveDependencyLookupStep.cs | 100 --------- src/linker/Linker/Annotations.cs | 48 ++++- src/linker/Linker/AssemblyUtilities.cs | 14 +- src/linker/Linker/DependencyInfo.cs | 3 + src/linker/Linker/Driver.cs | 8 +- src/linker/Linker/DynamicDependency.cs | 58 ++++++ .../Linker/LinkerAttributesInformation.cs | 147 ++++++++++++-- src/linker/Linker/MessageOrigin.cs | 5 +- src/linker/Linker/TypeDefinitionExtensions.cs | 14 +- .../DynamicDependencyAttribute.cs | 136 +++++++++++++ 13 files changed, 707 insertions(+), 164 deletions(-) create mode 100644 src/linker/Linker.Steps/DynamicDependencyLookupStep.cs delete mode 100644 src/linker/Linker.Steps/PreserveDependencyLookupStep.cs create mode 100644 src/linker/Linker/DynamicDependency.cs create mode 100644 src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs diff --git a/docs/error-codes.md b/docs/error-codes.md index 94169850a548..cd879dccdae4 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -163,9 +163,9 @@ error and warning codes. - The linker found a call to a method which is annotated with 'RequiresUnreferencedCodeAttribute' which can break functionality of a trimmed application. -#### `IL2027`: Attribute 'attribute' should only be used once on 'method'. +#### `IL2027`: Attribute 'attribute' should only be used once on 'member'. -- The linker found multiple instances of attribute 'attribute' on 'method'. This attribute is only allowed to have one instance, linker will only use the fist instance and ignore the rest. +- The linker found multiple instances of attribute 'attribute' on 'member'. This attribute is only allowed to have one instance, linker will only use the fist instance and ignore the rest. #### `IL2028`: Attribute 'attribute' on 'method' doesn't have a required constructor argument. @@ -185,4 +185,28 @@ error and warning codes. #### `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 +- 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. + +#### `IL2033`: Unsupported PreserveDependencyAttribute on 'member'. Use DynamicDependencyAttribute instead. + +- PreserveDependencyAttribute was an internal attribute that was never officially supported. Instead, use the similar DynamicDependencyAttribute. + +#### `IL2034`: Invalid DynamicDependencyAttribute on 'member' + +- The input contains an invalid use of DynamicDependencyAttribute. Ensure that you are using one of the officially supported constructors. + +#### `IL2035`: Unresolved assembly 'assemblyName' in DynamicDependencyAttribute on 'member' + +- The assembly string given in a DynamicDependencyAttribute constructor could not be resolved. Ensure that the argument specifies a valid asembly name, and that the assembly is available to the linker. + +#### `IL2036`: Unresolved type 'typeName' in DynamicDependencyAttribute on 'member' + +- The type in a DynamicDependencyAttribute constructor could not be resolved. Ensure that the argument specifies a valid type name or type reference, that the type exists in the specified assembly, and that the assembly is available to the linker. + +#### `IL2037`: Unresolved member 'memberSignature' in DynamicDependencyAttribute on 'member' + +- The member signature in a DynamicDependencyAttribute constructor could not be resolved. Ensure that it refers to an existing member, and that it uses the format defined at https://github.com/dotnet/csharplang/blob/master/spec/documentation-comments.md#id-string-format. + +#### `IL2038`: No members were resolved for for 'memberTypes' in DynamicDependencyAttribute on 'member' + +- The DynamicallyAccessedMemberTypes passed into the DynamicDependencyAttribute constructor did not match any members on the specified type. No members will be kept for this attribute. Ensure that you are using DynamicallyAccessedMemberTypes which exist for the type. diff --git a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs new file mode 100644 index 000000000000..4cc15093309f --- /dev/null +++ b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs @@ -0,0 +1,116 @@ +// 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; +using System.Diagnostics; +using Mono.Cecil; +using System.Diagnostics.CodeAnalysis; + +#nullable enable + +namespace Mono.Linker.Steps +{ + public class DynamicDependencyLookupStep : LoadReferencesStep + { + protected override void ProcessAssembly (AssemblyDefinition assembly) + { + var module = assembly.MainModule; + + foreach (var type in module.Types) { + ProcessType (type); + } + } + + void ProcessType (TypeDefinition type) + { + if (type.HasMethods) { + foreach (var method in type.GetMethods ()) { + var methodDefinition = method.Resolve (); + if (methodDefinition?.HasCustomAttributes != true) + continue; + + ProcessDynamicDependencyAttributes (methodDefinition); + } + } + + if (type.HasFields) { + foreach (var field in type.Fields) { + var fieldDefinition = field.Resolve (); + if (fieldDefinition?.HasCustomAttributes != true) + continue; + + ProcessDynamicDependencyAttributes (fieldDefinition); + } + } + + if (type.HasNestedTypes) { + foreach (var nestedType in type.NestedTypes) { + ProcessType (nestedType); + } + } + } + + void ProcessDynamicDependencyAttributes (IMemberDefinition member) + { + Debug.Assert (member is MethodDefinition || member is FieldDefinition); + + bool hasDynamicDependencyAttributes = false; + foreach (var ca in member.CustomAttributes) { + if (LinkerAttributesInformation.IsAttribute (ca.AttributeType)) + hasDynamicDependencyAttributes = true; + + if (!IsPreserveDependencyAttribute (ca.AttributeType)) + continue; +#if FEATURE_ILLINK + Context.LogMessage (MessageContainer.CreateWarningMessage (Context, + $"Unsupported PreserveDependencyAttribute on '{member}'. Use DynamicDependencyAttribute instead.", + 2033, MessageOrigin.TryGetOrigin (member))); +#else + if (ca.ConstructorArguments.Count != 3) + continue; + + if (!(ca.ConstructorArguments[2].Value is string assemblyName)) + continue; + + var assembly = Context.Resolve (new AssemblyNameReference (assemblyName, new Version ())); + if (assembly == null) + continue; + ProcessReferences (assembly); +#endif + } + + // avoid allocating linker attributes for members that don't need them + if (!hasDynamicDependencyAttributes) + return; + + var dynamicDependencies = member switch + { + MethodDefinition method => Context.Annotations.GetLinkerAttributes (method), + FieldDefinition field => Context.Annotations.GetLinkerAttributes (field), + _ => throw new InternalErrorException ("Unexpected member type") + }; + + foreach (var dynamicDependency in dynamicDependencies) { + if (dynamicDependency.AssemblyName == null) + continue; + + var assembly = Context.Resolve (new AssemblyNameReference (dynamicDependency.AssemblyName, new Version ())); + if (assembly == null) { + Context.LogMessage (MessageContainer.CreateWarningMessage (Context, + $"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{member}'", + 2035, MessageOrigin.TryGetOrigin (member))); + continue; + } + + ProcessReferences (assembly); + } + + } + + public static bool IsPreserveDependencyAttribute (TypeReference tr) + { + return tr.Name == "PreserveDependencyAttribute" && tr.Namespace == "System.Runtime.CompilerServices"; + } + } +} diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index fab55393be2d..06250d895457 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -30,6 +30,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Text.RegularExpressions; using Mono.Cecil; @@ -54,7 +55,10 @@ public partial class MarkStep : IStep #if DEBUG static readonly DependencyKind[] _entireTypeReasons = new DependencyKind[] { DependencyKind.NestedType, +#if !FEATURE_ILLINK DependencyKind.PreservedDependency, +#endif + DependencyKind.DynamicDependency, DependencyKind.TypeInAssembly, DependencyKind.AccessedViaReflection, DependencyKind.BaseType, @@ -71,7 +75,10 @@ public partial class MarkStep : IStep DependencyKind.InteropMethodDependency, DependencyKind.Ldtoken, DependencyKind.MemberOfType, +#if !FEATURE_ILLINK DependencyKind.PreservedDependency, +#endif + DependencyKind.DynamicDependency, DependencyKind.ReferencedBySpecialAttribute, DependencyKind.TypePreserve, }; @@ -130,7 +137,10 @@ public partial class MarkStep : IStep DependencyKind.Newobj, DependencyKind.Override, DependencyKind.OverrideOnInstantiatedType, +#if !FEATURE_ILLINK DependencyKind.PreservedDependency, +#endif + DependencyKind.DynamicDependency, DependencyKind.PreservedMethod, DependencyKind.ReferencedBySpecialAttribute, DependencyKind.SerializationMethodForType, @@ -521,10 +531,13 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo bool markOnUse = _context.KeepUsedAttributeTypesOnly && Annotations.GetAction (GetAssemblyFromCustomAttributeProvider (provider)) == AssemblyAction.Link; + bool hasDynamicDependencyAttributes = false; foreach (CustomAttribute ca in provider.CustomAttributes) { - if (ProcessLinkerSpecialAttribute (ca, provider, reason)) { + if (LinkerAttributesInformation.IsAttribute (ca.AttributeType)) + hasDynamicDependencyAttributes = true; + + if (ProcessLinkerSpecialAttribute (ca, provider, reason)) continue; - } if (markOnUse) { _lateMarkedAttributes.Enqueue ((new AttributeProviderPair (ca, provider), reason)); @@ -534,24 +547,145 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo MarkCustomAttribute (ca, reason); MarkSpecialCustomAttributeDependencies (ca, provider); } + + // avoid allocating linker attributes for members that don't need them + if (!hasDynamicDependencyAttributes) + return; + + var dynamicDependencies = provider switch + { + MethodDefinition method => _context.Annotations.GetLinkerAttributes (method), + FieldDefinition field => _context.Annotations.GetLinkerAttributes (field), + _ => null + }; + + if (dynamicDependencies == null) + return; + + foreach (var dynamicDependency in dynamicDependencies) + MarkDynamicDependency (dynamicDependency, (MemberReference) provider); } protected virtual bool ProcessLinkerSpecialAttribute (CustomAttribute ca, ICustomAttributeProvider provider, in DependencyInfo reason) { - if (IsUserDependencyMarker (ca.AttributeType) && provider is MemberReference mr) { + var isPreserveDependency = IsUserDependencyMarker (ca.AttributeType); + var isDynamicDependency = LinkerAttributesInformation.IsAttribute (ca.AttributeType); + + if (!((isPreserveDependency || isDynamicDependency) && provider is MemberReference mr)) + return false; + +#if !FEATURE_ILLINK + if (isPreserveDependency) MarkUserDependency (mr, ca); +#endif - if (_context.KeepDependencyAttributes || Annotations.GetAction (mr.Module.Assembly) != AssemblyAction.Link) { - MarkCustomAttribute (ca, reason); - } else { - // Record the custom attribute so that it has a reason, without actually marking it. - Tracer.AddDirectDependency (ca, reason, marked: false); + if (_context.KeepDependencyAttributes || Annotations.GetAction (mr.Module.Assembly) != AssemblyAction.Link) { + MarkCustomAttribute (ca, reason); + } else { + // Record the custom attribute so that it has a reason, without actually marking it. + Tracer.AddDirectDependency (ca, reason, marked: false); + } + + return true; + } + + void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference context) + { + Debug.Assert (context is MethodDefinition || context is FieldDefinition); + var member = context as IMemberDefinition; + AssemblyDefinition assembly; + if (dynamicDependency.AssemblyName is string assemblyName) { + assembly = _context.GetLoadedAssembly (assemblyName); + if (assembly == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, + $"Unresolved assembly '{assemblyName}' in DynamicDependencyAttribute on '{context}'", + 2035, MessageOrigin.TryGetOrigin (member))); + return; } + } else { + assembly = context.Module.Assembly; + Debug.Assert (assembly != null); + } - return true; + TypeDefinition type; + if (dynamicDependency.TypeName is string typeName) { + type = assembly.FindTypeByDocumentationSignature (typeName); + if (type == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, + $"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", + 2036, MessageOrigin.TryGetOrigin (member))); + return; + } + } else if (dynamicDependency.Type is TypeReference typeReference) { + type = typeReference.Resolve (); + if (type == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, + $"Unresolved type '{typeReference}' in DynamicDependencyAtribute on '{context}'", + 2036, MessageOrigin.TryGetOrigin (member))); + return; + } + } else { + type = context.DeclaringType.Resolve (); + if (type == null) { + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, + $"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute on '{context}'", + 2036, MessageOrigin.TryGetOrigin (member))); + return; + } } - return false; + IEnumerable members; + if (dynamicDependency.MemberSignature is string memberSignature) { + members = type.FindMembersByDocumentationSignature (memberSignature); + if (!members.Any ()) { + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, + $"Unresolved member '{memberSignature}' in DynamicDependencyAttribute", + 2037, MessageOrigin.TryGetOrigin (member))); + return; + } + } else { + var memberTypes = dynamicDependency.MemberTypes; + members = DynamicallyAccessedMembersBinder.GetDynamicallyAccessedMembers (type, memberTypes); + if (!members.Any ()) { + _context.LogMessage (MessageContainer.CreateWarningMessage (_context, + $"No members were resolved for '{memberTypes}' in DynamicDependencyAttribute on '{context}'", + 2038, MessageOrigin.TryGetOrigin (member))); + return; + } + } + + MarkMembers (type, members, new DependencyInfo (DependencyKind.DynamicDependency, dynamicDependency.OriginalAttribute)); + } + + void MarkMembers (TypeDefinition typeDefinition, IEnumerable members, DependencyInfo reason) + { + foreach (var member in members) { + if (member == typeDefinition) { + MarkEntireType (typeDefinition, includeBaseTypes: true, reason); + continue; + } + switch (member) { + case TypeDefinition type: + MarkType (type, reason); + break; + case MethodDefinition method: + MarkMethod (method, reason); + break; + case FieldDefinition field: + MarkField (field, reason); + break; + case PropertyDefinition property: + MarkProperty (property, reason); + MarkMethodIfNotNull (property.GetMethod, reason); + MarkMethodIfNotNull (property.SetMethod, reason); + MarkMethodsIf (property.OtherMethods, m => true, reason); + break; + case EventDefinition @event: + MarkEvent (@event, reason); + MarkMethodsIf (@event.OtherMethods, m => true, reason); + break; + } + } } protected static AssemblyDefinition GetAssemblyFromCustomAttributeProvider (ICustomAttributeProvider provider) @@ -571,27 +705,14 @@ protected static AssemblyDefinition GetAssemblyFromCustomAttributeProvider (ICus protected virtual bool IsUserDependencyMarker (TypeReference type) { - return PreserveDependencyLookupStep.IsPreserveDependencyAttribute (type); + return DynamicDependencyLookupStep.IsPreserveDependencyAttribute (type); } +#if !FEATURE_ILLINK protected virtual void MarkUserDependency (MemberReference context, CustomAttribute ca) { - if (ca.HasProperties && ca.Properties[0].Name == "Condition") { - var condition = ca.Properties[0].Argument.Value as string; - switch (condition) { - case "": - case null: - break; - case "DEBUG": - if (!_context.KeepMembersForDebugger) - return; - - break; - default: - // Don't have yet a way to match the general condition so everything is excluded - return; - } - } + if (!LinkerAttributesInformation.ShouldProcessDependencyAttribute (_context, ca)) + return; AssemblyDefinition assembly; var args = ca.ConstructorArguments; @@ -706,6 +827,7 @@ bool MarkDependencyField (TypeDefinition type, string name, in DependencyInfo re return false; } +#endif // !FEATURE_ILLINK void LazyMarkCustomAttributes (ICustomAttributeProvider provider, ModuleDefinition module) { @@ -2610,7 +2732,21 @@ protected virtual void MarkInterfaceImplementation (InterfaceImplementation ifac bool HasManuallyTrackedDependency (MethodBody methodBody) { - return PreserveDependencyLookupStep.HasPreserveDependencyAttribute (methodBody.Method); + var method = methodBody.Method; + + if (!method.HasCustomAttributes) + return false; + + // avoid allocating linker attributes for members that don't need them + foreach (var ca in method.CustomAttributes) { + if (LinkerAttributesInformation.IsAttribute (ca.AttributeType)) + return true; +#if !FEATURE_ILLINK + if (DynamicDependencyLookupStep.IsPreserveDependencyAttribute (ca.AttributeType)) + return true; +#endif + } + return false; } // diff --git a/src/linker/Linker.Steps/PreserveDependencyLookupStep.cs b/src/linker/Linker.Steps/PreserveDependencyLookupStep.cs deleted file mode 100644 index 9d3eb8d8dc24..000000000000 --- a/src/linker/Linker.Steps/PreserveDependencyLookupStep.cs +++ /dev/null @@ -1,100 +0,0 @@ -// -// PreserveDependencyLookupStep.cs -// -// Author: -// Marek Safar (marek.safar@gmail.com) -// -// Copyright (C) 2018 Microsoft Corporation -// -// Permission is hereby granted, free of charge, to any person obtaining -// a copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to -// permit persons to whom the Software is furnished to do so, subject to -// the following conditions: -// -// The above copyright notice and this permission notice shall be -// included in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// - -using System; -using Mono.Cecil; -using Mono.Collections.Generic; - -namespace Mono.Linker.Steps -{ - public class PreserveDependencyLookupStep : LoadReferencesStep - { - protected override void ProcessAssembly (AssemblyDefinition assembly) - { - var module = assembly.MainModule; - - foreach (var type in module.Types) { - if (type.HasMethods) { - foreach (var method in type.GetMethods ()) { - var md = method.Resolve (); - if (md?.HasCustomAttributes != true) - continue; - - ProcessPreserveDependencyAttribute (md.CustomAttributes); - } - } - - if (type.HasFields) { - foreach (var field in type.Fields) { - var md = field.Resolve (); - if (md?.HasCustomAttributes != true) - continue; - - ProcessPreserveDependencyAttribute (md.CustomAttributes); - } - } - } - } - - public static bool IsPreserveDependencyAttribute (TypeReference tr) - { - return tr.Name == "PreserveDependencyAttribute" && tr.Namespace == "System.Runtime.CompilerServices"; - } - - public static bool HasPreserveDependencyAttribute (MethodDefinition method) - { - if (!method.HasCustomAttributes) - return false; - - foreach (var ca in method.CustomAttributes) { - if (IsPreserveDependencyAttribute (ca.AttributeType)) - return true; - } - - return false; - } - - void ProcessPreserveDependencyAttribute (Collection attributes) - { - foreach (var ca in attributes) { - if (!IsPreserveDependencyAttribute (ca.AttributeType)) - continue; - - if (ca.ConstructorArguments.Count != 3) - continue; - - if (!(ca.ConstructorArguments[2].Value is string assemblyName)) - continue; - - var newDependency = Context.Resolve (new AssemblyNameReference (assemblyName, new Version ())); - if (newDependency != null) - ProcessReferences (newDependency); - } - } - } -} diff --git a/src/linker/Linker/Annotations.cs b/src/linker/Linker/Annotations.cs index 7b68e51d2997..6cb058b65a62 100644 --- a/src/linker/Linker/Annotations.cs +++ b/src/linker/Linker/Annotations.cs @@ -56,6 +56,7 @@ public partial class AnnotationStore protected readonly Dictionary> base_methods = new Dictionary> (); protected readonly Dictionary symbol_readers = new Dictionary (); readonly Dictionary method_linker_attributes = new Dictionary (); + readonly Dictionary field_linker_attributes = new Dictionary (); readonly Dictionary> custom_annotations = new Dictionary> (); protected readonly Dictionary> resources_to_remove = new Dictionary> (); @@ -64,7 +65,6 @@ public partial class AnnotationStore protected readonly HashSet marked_instantiated = new HashSet (); protected readonly HashSet indirectly_called = new HashSet (); - public AnnotationStore (LinkContext context) => this.context = context; public bool ProcessSatelliteAssemblies { get; set; } @@ -429,7 +429,7 @@ public bool SetPreservedStaticCtor (TypeDefinition type) return marked_types_with_cctor.Add (type); } - public bool HasLinkerAttribute (MethodDefinition method) where T : Attribute + public bool HasLinkerAttribute (MethodDefinition method) { if (!method_linker_attributes.TryGetValue (method, out var linkerAttributeInformation)) { linkerAttributeInformation = new LinkerAttributesInformation (context, method); @@ -439,7 +439,17 @@ public bool HasLinkerAttribute (MethodDefinition method) where T : Attribute return linkerAttributeInformation.HasAttribute (); } - public IEnumerable GetLinkerAttributes (MethodDefinition method) where T : Attribute + public bool HasLinkerAttribute (FieldDefinition field) + { + if (!field_linker_attributes.TryGetValue (field, out var linkerAttributeInformation)) { + linkerAttributeInformation = new LinkerAttributesInformation (context, field); + field_linker_attributes.Add (field, linkerAttributeInformation); + } + + return linkerAttributeInformation.HasAttribute (); + } + + public IEnumerable GetLinkerAttributes (MethodDefinition method) { if (!method_linker_attributes.TryGetValue (method, out var linkerAttributeInformation)) { linkerAttributeInformation = new LinkerAttributesInformation (context, method); @@ -449,7 +459,17 @@ public IEnumerable GetLinkerAttributes (MethodDefinition method) where T : return linkerAttributeInformation.GetAttributes (); } - public bool TryGetLinkerAttribute (MethodDefinition method, out T attribute) where T : Attribute + public IEnumerable GetLinkerAttributes (FieldDefinition field) + { + if (!field_linker_attributes.TryGetValue (field, out var linkerAttributeInformation)) { + linkerAttributeInformation = new LinkerAttributesInformation (context, field); + field_linker_attributes.Add (field, linkerAttributeInformation); + } + + return linkerAttributeInformation.GetAttributes (); + } + + public bool TryGetLinkerAttribute (MethodDefinition method, out T attribute) { var attributes = GetLinkerAttributes (method); if (attributes.Count () > 1) { @@ -457,8 +477,28 @@ public bool TryGetLinkerAttribute (MethodDefinition method, out T attribute) 2027, MessageOrigin.TryGetOrigin (method, 0)); } + Debug.Assert (attributes.Count () <= 1); attribute = attributes.FirstOrDefault (); return attribute != null; } + + public bool TryGetLinkerAttribute (FieldDefinition field, out T attribute) + { + var attributes = GetLinkerAttributes (field); + if (attributes.Count () > 1) { + context.LogMessage (MessageContainer.CreateWarningMessage (context, + $"Attribute '{typeof (T).FullName}' should only be used once on '{field}'.", + 2027, + origin: MessageOrigin.TryGetOrigin (field, 0))); + } + Debug.Assert (attributes.Count () <= 1); + attribute = attributes.FirstOrDefault (); + return attribute != null; + } + + public bool IsAttribute (CustomAttribute attribute) + { + return attribute.AttributeType.FullName == typeof (T).FullName; + } } } diff --git a/src/linker/Linker/AssemblyUtilities.cs b/src/linker/Linker/AssemblyUtilities.cs index 62a1284130db..e9442eeb844b 100644 --- a/src/linker/Linker/AssemblyUtilities.cs +++ b/src/linker/Linker/AssemblyUtilities.cs @@ -1,4 +1,5 @@ -using System; +using System.Collections.Generic; +using System.Diagnostics; using Mono.Cecil; namespace Mono.Linker @@ -39,5 +40,16 @@ public static TypeDefinition FindType (this AssemblyDefinition assembly, string var type = assembly.MainModule.GetType (fullName); return type?.Resolve (); } + + // Takes a documentation signature (not including the documentation member type prefix) and resolves it to a type + // in the assembly. + public static TypeDefinition FindTypeByDocumentationSignature (this AssemblyDefinition assembly, string signature) + { + int index = 0; + var results = new List (); + DocumentationSignatureParser.ParseSignaturePart (signature, ref index, assembly.MainModule, DocumentationSignatureParser.MemberType.Type, results); + Debug.Assert (results.Count <= 1); + return results.Count == 0 ? null : (TypeDefinition) results[0]; + } } } diff --git a/src/linker/Linker/DependencyInfo.cs b/src/linker/Linker/DependencyInfo.cs index 5a4d6453a82e..63a9be6f3b50 100644 --- a/src/linker/Linker/DependencyInfo.cs +++ b/src/linker/Linker/DependencyInfo.cs @@ -109,7 +109,10 @@ public enum DependencyKind OverrideOnInstantiatedType = 66, // instantiated type -> override method on the type // Linker-specific behavior (preservation hints, patterns, user inputs, linker outputs, etc.) + DynamicDependency = 67, // DynamicDependency attribute -> member +#if !FEATURE_ILLINK PreservedDependency = 67, // PreserveDependency attribute -> member +#endif AccessedViaReflection = 68, // method -> detected member accessed via reflection from that method PreservedMethod = 69, // type/method -> preserved method (explicitly preserved in Annotations by XML or other steps) TypePreserve = 70, // type -> field/method preserved for the type (explicitly set in Annotations by XML or other steps) diff --git a/src/linker/Linker/Driver.cs b/src/linker/Linker/Driver.cs index 1978d9e03f8f..1f7928d9fc66 100644 --- a/src/linker/Linker/Driver.cs +++ b/src/linker/Linker/Driver.cs @@ -593,7 +593,7 @@ protected int SetupContext (ILogger customLogger = null) p.AddStepAfter (typeof (LoadReferencesStep), new LoadI18nAssemblies (assemblies)); if (assemblies != I18nAssemblies.None) - p.AddStepAfter (typeof (PreserveDependencyLookupStep), new PreserveCalendarsStep (assemblies)); + p.AddStepAfter (typeof (DynamicDependencyLookupStep), new PreserveCalendarsStep (assemblies)); #endif if (_needAddBypassNGenStep) @@ -633,8 +633,8 @@ protected int SetupContext (ILogger customLogger = null) // dynamically adds steps: // ResolveFromXmlStep [optional, possibly many] // BodySubstituterStep [optional, possibly many] - // PreserveDependencyLookupStep - // [mono only] PreselveCalendarsStep [optional] + // DynamicDependencyLookupStep + // [mono only] PreserveCalendarsStep [optional] // TypeMapStep // BodySubstituterStep [optional] // RemoveSecurityStep [optional] @@ -1060,7 +1060,7 @@ static Pipeline GetStandardPipeline () Pipeline p = new Pipeline (); p.AppendStep (new LoadReferencesStep ()); p.AppendStep (new BlacklistStep ()); - p.AppendStep (new PreserveDependencyLookupStep ()); + p.AppendStep (new DynamicDependencyLookupStep ()); p.AppendStep (new TypeMapStep ()); p.AppendStep (new MarkStep ()); p.AppendStep (new SweepStep ()); diff --git a/src/linker/Linker/DynamicDependency.cs b/src/linker/Linker/DynamicDependency.cs new file mode 100644 index 000000000000..3d9315f90c6a --- /dev/null +++ b/src/linker/Linker/DynamicDependency.cs @@ -0,0 +1,58 @@ +using System.Diagnostics.CodeAnalysis; +using Mono.Cecil; + +#nullable enable + +namespace Mono.Linker +{ + /// Tracks dependencies created via DynamicDependencyAttribute in the linker. + /// This is almost identical to DynamicDependencyAttribute, but it holds a + /// TypeReference instead of a Type, and it has a reference to the original + /// CustomAttribute for dependency tracing. + internal class DynamicDependency + { + public CustomAttribute? OriginalAttribute { get; set; } + public DynamicDependency (string memberSignature) + { + MemberSignature = memberSignature; + } + + public DynamicDependency (string memberSignature, TypeReference type) + { + MemberSignature = memberSignature; + Type = type; + } + + public DynamicDependency (string memberSignature, string typeName, string assemblyName) + { + MemberSignature = memberSignature; + TypeName = typeName; + AssemblyName = assemblyName; + } + + public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, TypeReference type) + { + MemberTypes = memberTypes; + Type = type; + } + + public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) + { + MemberTypes = memberTypes; + TypeName = typeName; + AssemblyName = assemblyName; + } + + public string? MemberSignature { get; } + + public DynamicallyAccessedMemberTypes MemberTypes { get; } + + public TypeReference? Type { get; } + + public string? TypeName { get; } + + public string? AssemblyName { get; } + + public string? Condition { get; set; } + } +} \ No newline at end of file diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index fe8f92a8ee49..8b3892e17b10 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using Mono.Cecil; @@ -12,42 +13,63 @@ namespace Mono.Linker { readonly struct LinkerAttributesInformation { - readonly Dictionary> _linkerAttributes; + readonly Dictionary> _linkerAttributes; - public LinkerAttributesInformation (LinkContext context, MethodDefinition method) + public LinkerAttributesInformation (LinkContext context, IMemberDefinition member) { _linkerAttributes = null; - if (method.HasCustomAttributes) { - foreach (var customAttribute in method.CustomAttributes) { + if (member.HasCustomAttributes) { + foreach (var customAttribute in member.CustomAttributes) { var attributeType = customAttribute.AttributeType; - Attribute attributeValue = null; - if (attributeType.Name == "RequiresUnreferencedCodeAttribute" && attributeType.Namespace == "System.Diagnostics.CodeAnalysis") { - attributeValue = ProcessRequiresUnreferencedCodeAttribute (context, method, customAttribute); - } - - if (attributeValue != null) { - if (_linkerAttributes == null) - _linkerAttributes = new Dictionary> (); + object attributeValue = null; + if (IsAttribute (attributeType)) + attributeValue = ProcessRequiresUnreferencedCodeAttribute (context, member, customAttribute); + else if (IsAttribute (attributeType)) + attributeValue = ProcessDynamicDependencyAttribute (context, member, customAttribute); + AddAttribute (ref _linkerAttributes, attributeValue); + } + } + } - Type attributeValueType = attributeValue.GetType (); - if (!_linkerAttributes.TryGetValue (attributeValueType, out var attributeList)) { - attributeList = new List (); - _linkerAttributes.Add (attributeValueType, attributeList); - } + public LinkerAttributesInformation (LinkContext context, FieldDefinition field) + { + _linkerAttributes = null; - attributeList.Add (attributeValue); - } + if (field.HasCustomAttributes) { + foreach (var customAttribute in field.CustomAttributes) { + var attributeType = customAttribute.AttributeType; + object attributeValue = null; + if (IsAttribute (attributeType)) + attributeValue = ProcessDynamicDependencyAttribute (context, field, customAttribute); + AddAttribute (ref _linkerAttributes, attributeValue); } } } - public bool HasAttribute () where T : Attribute + static void AddAttribute (ref Dictionary> attributes, object attributeValue) + { + if (attributeValue == null) + return; + + if (attributes == null) + attributes = new Dictionary> (); + + Type attributeValueType = attributeValue.GetType (); + if (!attributes.TryGetValue (attributeValueType, out var attributeList)) { + attributeList = new List (); + attributes.Add (attributeValueType, attributeList); + } + + attributeList.Add (attributeValue); + } + + public bool HasAttribute () { return _linkerAttributes != null && _linkerAttributes.ContainsKey (typeof (T)); } - public IEnumerable GetAttributes () where T : Attribute + public IEnumerable GetAttributes () { if (_linkerAttributes == null || !_linkerAttributes.TryGetValue (typeof (T), out var attributeList)) return Enumerable.Empty (); @@ -59,7 +81,13 @@ public IEnumerable GetAttributes () where T : Attribute return attributeList.Cast (); } - static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, MethodDefinition method, CustomAttribute customAttribute) + public static bool IsAttribute (TypeReference tr) + { + var type = typeof (T); + return tr.Name == type.Name && tr.Namespace == tr.Namespace; + } + + static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, IMemberDefinition method, CustomAttribute customAttribute) { if (customAttribute.HasConstructorArguments) { string message = (string) customAttribute.ConstructorArguments[0].Value; @@ -77,5 +105,80 @@ static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, 2028, MessageOrigin.TryGetOrigin (method, 0)); return null; } + + static DynamicDependency ProcessDynamicDependencyAttribute (LinkContext context, IMemberDefinition member, CustomAttribute customAttribute) + { + if (!ShouldProcessDependencyAttribute (context, customAttribute)) + return null; + + var dynamicDependency = GetDynamicDependency (context, customAttribute); + if (dynamicDependency == null) { + context.LogMessage (MessageContainer.CreateErrorMessage ($"Invalid DynamicDependencyAttribute on '{member}'", 2034)); + return null; + } + + dynamicDependency.OriginalAttribute = customAttribute; + return dynamicDependency; + } + + static DynamicDependency GetDynamicDependency (LinkContext context, CustomAttribute ca) + { + var args = ca.ConstructorArguments; + if (args.Count > 3) + return null; + + // First argument is string or DynamicallyAccessedMemberTypes + string memberSignature = args[0].Value as string; + if (args.Count == 1) + return memberSignature == null ? null : new DynamicDependency (memberSignature); + DynamicallyAccessedMemberTypes? memberTypes = null; + if (memberSignature == null) { + var argType = args[0].Type; + if (!(argType.Namespace == "System.Diagnostics.CodeAnalysis" && argType.Name == "DynamicallyAccessedMemberTypes")) + return null; + try { + memberTypes = (DynamicallyAccessedMemberTypes) args[0].Value; + } catch (InvalidCastException) { } + if (memberTypes == null) + return null; + } + + // Second argument is Type for ctors with two args, string for ctors with three args + if (args.Count == 2) { + if (!(args[1].Value is TypeReference type)) + return null; + return memberSignature == null ? new DynamicDependency (memberTypes.Value, type) : new DynamicDependency (memberSignature, type); + } + Debug.Assert (args.Count == 3); + if (!(args[1].Value is string typeName)) + return null; + + // Third argument is assembly name + if (!(args[2].Value is string assemblyName)) + return null; + + return memberSignature == null ? new DynamicDependency (memberTypes.Value, typeName, assemblyName) : new DynamicDependency (memberSignature, typeName, assemblyName); + } + + public static bool ShouldProcessDependencyAttribute (LinkContext context, CustomAttribute ca) + { + if (ca.HasProperties && ca.Properties[0].Name == "Condition") { + var condition = ca.Properties[0].Argument.Value as string; + switch (condition) { + case "": + case null: + return true; + case "DEBUG": + if (!context.KeepMembersForDebugger) + return false; + + break; + default: + // Don't have yet a way to match the general condition so everything is excluded + return false; + } + } + return true; + } } } diff --git a/src/linker/Linker/MessageOrigin.cs b/src/linker/Linker/MessageOrigin.cs index 213464f1dbf0..10f0e446971c 100644 --- a/src/linker/Linker/MessageOrigin.cs +++ b/src/linker/Linker/MessageOrigin.cs @@ -42,8 +42,11 @@ private MessageOrigin (string fileName, IMemberDefinition memberDefinition, int SourceColumn = sourceColumn; } - public static MessageOrigin TryGetOrigin (MethodDefinition sourceMethod, int ilOffset) + public static MessageOrigin TryGetOrigin (IMemberDefinition sourceMember, int ilOffset = 0) { + if (!(sourceMember is MethodDefinition sourceMethod)) + return new MessageOrigin (sourceMember); + if (sourceMethod.DebugInformation.HasSequencePoints) { SequencePoint correspondingSequencePoint = sourceMethod.DebugInformation.SequencePoints .Where (s => s.Offset <= ilOffset)?.Last (); diff --git a/src/linker/Linker/TypeDefinitionExtensions.cs b/src/linker/Linker/TypeDefinitionExtensions.cs index c00db8fe8619..5caed0bc594b 100644 --- a/src/linker/Linker/TypeDefinitionExtensions.cs +++ b/src/linker/Linker/TypeDefinitionExtensions.cs @@ -1,5 +1,6 @@ - using System; +using System.Collections.Generic; +using System.Text; using Mono.Cecil; namespace Mono.Linker @@ -42,5 +43,16 @@ public static bool IsSerializable (this TypeDefinition td) { return (td.Attributes & TypeAttributes.Serializable) != 0; } + + // Takes a member signature (not including the declaring type) and returns the matching members on the type. + public static IEnumerable FindMembersByDocumentationSignature (this TypeDefinition type, string signature) + { + int index = 0; + var results = new List (); + var nameBuilder = new StringBuilder (); + var (name, arity) = DocumentationSignatureParser.ParseTypeOrNamespaceName (signature, ref index, nameBuilder); + DocumentationSignatureParser.GetMatchingMembers (signature, ref index, type.Module, type, name, arity, DocumentationSignatureParser.MemberType.All, results); + return results; + } } } \ No newline at end of file diff --git a/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs b/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs new file mode 100644 index 000000000000..843d45c03e35 --- /dev/null +++ b/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs @@ -0,0 +1,136 @@ +// 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. + +#nullable enable + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// States a dependency that one member has on another. + /// + /// + /// This can be used to inform tooling of a dependency that is otherwise not evident purely from + /// metadata and IL, for example a member relied on via reflection. + /// + /// + /// This is a copy of the enum definition in the framework at https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs + /// + [AttributeUsage ( + AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method, + AllowMultiple = true, Inherited = false)] + internal sealed class DynamicDependencyAttribute : Attribute + { + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on the same type as the consumer. + /// + /// The signature of the member depended on. + public DynamicDependencyAttribute (string memberSignature) + { + MemberSignature = memberSignature; + } + + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on a . + /// + /// The signature of the member depended on. + /// The containing . + public DynamicDependencyAttribute (string memberSignature, Type type) + { + MemberSignature = memberSignature; + Type = type; + } + + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on a type in an assembly. + /// + /// The signature of the member depended on. + /// The full name of the type containing the specified member. + /// The assembly name of the type containing the specified member. + public DynamicDependencyAttribute (string memberSignature, string typeName, string assemblyName) + { + MemberSignature = memberSignature; + TypeName = typeName; + AssemblyName = assemblyName; + } + + /// + /// Initializes a new instance of the class + /// with the specified types of members on a . + /// + /// The types of members depended on. + /// The containing the specified members. + public DynamicDependencyAttribute (DynamicallyAccessedMemberTypes memberTypes, Type type) + { + MemberTypes = memberTypes; + Type = type; + } + + /// + /// Initializes a new instance of the class + /// with the specified types of members on a type in an assembly. + /// + /// The types of members depended on. + /// The full name of the type containing the specified members. + /// The assembly name of the type containing the specified members. + public DynamicDependencyAttribute (DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) + { + MemberTypes = memberTypes; + TypeName = typeName; + AssemblyName = assemblyName; + } + + /// + /// Gets the signature of the member depended on. + /// + /// + /// Either must be a valid string or + /// must not equal , but not both. + /// + public string? MemberSignature { get; } + + /// + /// Gets the which specifies the type + /// of members depended on. + /// + /// + /// Either must be a valid string or + /// must not equal , but not both. + /// + public DynamicallyAccessedMemberTypes MemberTypes { get; } + + /// + /// Gets the containing the specified member. + /// + /// + /// If neither nor are specified, + /// the type of the consumer is assumed. + /// + public Type? Type { get; } + + /// + /// Gets the full name of the type containing the specified member. + /// + /// + /// If neither nor are specified, + /// the type of the consumer is assumed. + /// + public string? TypeName { get; } + + /// + /// Gets the assembly name of the specified type. + /// + /// + /// is only valid when is specified. + /// + public string? AssemblyName { get; } + + /// + /// Gets or sets the condition in which the dependency is applicable, e.g. "DEBUG". + /// + public string? Condition { get; set; } + } +} From 9898afb53567caefc8fcf36ac95ef071dc3949cc Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Tue, 26 May 2020 23:45:35 +0000 Subject: [PATCH 02/21] Add tests for DynamicDependencyAttribute --- src/linker/Linker.Steps/MarkStep.cs | 2 +- .../Linker/LinkerAttributesInformation.cs | 6 +- .../DynamicDependencyAttribute.cs | 136 ++++++++++++++++++ .../DynamicDependencyInCopyAssembly.cs | 18 +++ ...ynamicDependencyMethodInAssemblyLibrary.cs | 14 ++ ...ndencyMethodInNonReferencedAssemblyBase.cs | 7 + ...dencyMethodInNonReferencedAssemblyBase2.cs | 10 ++ ...odInNonReferencedAssemblyChainedLibrary.cs | 19 +++ ...ferencedAssemblyChainedReferenceLibrary.cs | 11 ++ ...ncyMethodInNonReferencedAssemblyLibrary.cs | 14 ++ ...cyMethodInNonReferencedAssemblyLibrary.xml | 5 + ...eferencedAssemblyWithCopyUsedAction_Lib.cs | 9 ++ .../DynamicDependencyField.cs | 29 ++++ .../DynamicDependencyFromCopiedAssembly.cs | 23 +++ .../DynamicDependencyKeptOption.cs | 30 ++++ ...ynamicDependencyMemberSignatureWildcard.cs | 23 +++ .../DynamicDependencyMethod.cs | 126 ++++++++++++++++ .../DynamicDependencyMethodInAssembly.cs | 23 +++ ...DependencyMethodInNonReferencedAssembly.cs | 42 ++++++ ...ncyMethodInNonReferencedAssemblyChained.cs | 46 ++++++ ...InNonReferencedAssemblyChainedReference.cs | 49 +++++++ ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 49 +++++++ ...cyOnUnusedMethodInNonReferencedAssembly.cs | 39 +++++ ...NonReferencedAssemblyWithCopyUsedAction.cs | 22 +++ ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 47 ++++++ .../PreserveDependencyMethodInAssembly.cs | 2 +- .../TestCases/TestDatabase.cs | 5 + .../Mono.Linker.Tests/TestCases/TestSuites.cs | 8 +- 28 files changed, 809 insertions(+), 5 deletions(-) create mode 100644 test/Mono.Linker.Tests.Cases.Expectations/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyInCopyAssembly.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyField.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromCopiedAssembly.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyKeptOption.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssembly.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChained.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReference.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssembly.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 06250d895457..969a8849c28d 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -639,7 +639,7 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference members = type.FindMembersByDocumentationSignature (memberSignature); if (!members.Any ()) { _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Unresolved member '{memberSignature}' in DynamicDependencyAttribute", + $"Unresolved member '{memberSignature}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (member))); return; } diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index 8b3892e17b10..c41e580f5d83 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. @@ -113,7 +113,9 @@ static DynamicDependency ProcessDynamicDependencyAttribute (LinkContext context, var dynamicDependency = GetDynamicDependency (context, customAttribute); if (dynamicDependency == null) { - context.LogMessage (MessageContainer.CreateErrorMessage ($"Invalid DynamicDependencyAttribute on '{member}'", 2034)); + context.LogMessage (MessageContainer.CreateWarningMessage (context, + $"Invalid DynamicDependencyAttribute on '{member}'", + 2034, MessageOrigin.TryGetOrigin (member))); return null; } diff --git a/test/Mono.Linker.Tests.Cases.Expectations/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs b/test/Mono.Linker.Tests.Cases.Expectations/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs new file mode 100644 index 000000000000..107521234047 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases.Expectations/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs @@ -0,0 +1,136 @@ +// 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. + +#nullable enable + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// States a dependency that one member has on another. + /// + /// + /// This can be used to inform tooling of a dependency that is otherwise not evident purely from + /// metadata and IL, for example a member relied on via reflection. + /// + /// + /// This is a copy of the enum definition in the framework at https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs + /// + [AttributeUsage ( + AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method, + AllowMultiple = true, Inherited = false)] + public sealed class DynamicDependencyAttribute : Attribute + { + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on the same type as the consumer. + /// + /// The signature of the member depended on. + public DynamicDependencyAttribute (string memberSignature) + { + MemberSignature = memberSignature; + } + + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on a . + /// + /// The signature of the member depended on. + /// The containing . + public DynamicDependencyAttribute (string memberSignature, Type type) + { + MemberSignature = memberSignature; + Type = type; + } + + /// + /// Initializes a new instance of the class + /// with the specified signature of a member on a type in an assembly. + /// + /// The signature of the member depended on. + /// The full name of the type containing the specified member. + /// The assembly name of the type containing the specified member. + public DynamicDependencyAttribute (string memberSignature, string typeName, string assemblyName) + { + MemberSignature = memberSignature; + TypeName = typeName; + AssemblyName = assemblyName; + } + + /// + /// Initializes a new instance of the class + /// with the specified types of members on a . + /// + /// The types of members depended on. + /// The containing the specified members. + public DynamicDependencyAttribute (DynamicallyAccessedMemberTypes memberTypes, Type type) + { + MemberTypes = memberTypes; + Type = type; + } + + /// + /// Initializes a new instance of the class + /// with the specified types of members on a type in an assembly. + /// + /// The types of members depended on. + /// The full name of the type containing the specified members. + /// The assembly name of the type containing the specified members. + public DynamicDependencyAttribute (DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) + { + MemberTypes = memberTypes; + TypeName = typeName; + AssemblyName = assemblyName; + } + + /// + /// Gets the signature of the member depended on. + /// + /// + /// Either must be a valid string or + /// must not equal , but not both. + /// + public string? MemberSignature { get; } + + /// + /// Gets the which specifies the type + /// of members depended on. + /// + /// + /// Either must be a valid string or + /// must not equal , but not both. + /// + public DynamicallyAccessedMemberTypes MemberTypes { get; } + + /// + /// Gets the containing the specified member. + /// + /// + /// If neither nor are specified, + /// the type of the consumer is assumed. + /// + public Type? Type { get; } + + /// + /// Gets the full name of the type containing the specified member. + /// + /// + /// If neither nor are specified, + /// the type of the consumer is assumed. + /// + public string? TypeName { get; } + + /// + /// Gets the assembly name of the specified type. + /// + /// + /// is only valid when is specified. + /// + public string? AssemblyName { get; } + + /// + /// Gets or sets the condition in which the dependency is applicable, e.g. "DEBUG". + /// + public string? Condition { get; set; } + } +} diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyInCopyAssembly.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyInCopyAssembly.cs new file mode 100644 index 000000000000..deef452cdee2 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyInCopyAssembly.cs @@ -0,0 +1,18 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies +{ + public class DynamicDependencyInCopyAssembly + { + [DynamicDependency ("ExtraMethod1")] + public DynamicDependencyInCopyAssembly () + { + } + + static void ExtraMethod1 () + { + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs new file mode 100644 index 000000000000..1e0e385e4ebe --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs @@ -0,0 +1,14 @@ +using System; +namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies +{ + public class DynamicDependencyMethodInAssemblyLibrary + { + public DynamicDependencyMethodInAssemblyLibrary () + { + } + + private void Foo () + { + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs new file mode 100644 index 000000000000..33910f8eb0eb --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs @@ -0,0 +1,7 @@ +namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies +{ + public abstract class DynamicDependencyMethodInNonReferencedAssemblyBase + { + public abstract string Method (); + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs new file mode 100644 index 000000000000..12a1569daacc --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs @@ -0,0 +1,10 @@ +namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies +{ + public class DynamicDependencyMethodInNonReferencedAssemblyBase2 : DynamicDependencyMethodInNonReferencedAssemblyBase + { + public override string Method () + { + return "Base2"; + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs new file mode 100644 index 000000000000..48b315f7d44b --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs @@ -0,0 +1,19 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies +{ + public class DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary : DynamicDependencyMethodInNonReferencedAssemblyBase + { + public override string Method () + { + Dependency (); + return "Dependency"; + } + + [DynamicDependency (".ctor()", "Mono.Linker.Tests.Cases.Advanced.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyBase2", "base2")] + public static void Dependency () + { + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs new file mode 100644 index 000000000000..d0392bb6a3d1 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs @@ -0,0 +1,11 @@ +namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies +{ + public class DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary : DynamicDependencyMethodInNonReferencedAssemblyBase + { + public override string Method () + { + DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.Dependency (); + return "Dependency"; + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs new file mode 100644 index 000000000000..b2d1f083aea7 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs @@ -0,0 +1,14 @@ +namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies +{ + public class DynamicDependencyMethodInNonReferencedAssemblyLibrary : DynamicDependencyMethodInNonReferencedAssemblyBase + { + public override string Method () + { + return "Dependency"; + } + + private void UnusedMethod () + { + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml new file mode 100644 index 000000000000..5cad4f63d0b6 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs new file mode 100644 index 000000000000..e74ee7393ced --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs @@ -0,0 +1,9 @@ +namespace Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies +{ + public class DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib + { + public static void MethodPreservedViaDependencyAttribute () + { + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyField.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyField.cs new file mode 100644 index 000000000000..edef9e077b4e --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyField.cs @@ -0,0 +1,29 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + public class DynamicDependencyField + { + public static void Main () + { + var b = new B (); + b.field = 3; + } + + [KeptMember (".ctor()")] + class B + { + [Kept] + [DynamicDependency ("ExtraMethod1")] + public int field; + + [Kept] + static void ExtraMethod1 () + { + } + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromCopiedAssembly.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromCopiedAssembly.cs new file mode 100644 index 000000000000..e35c2a10636a --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyFromCopiedAssembly.cs @@ -0,0 +1,23 @@ +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; +using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [SetupLinkerAction ("copy", "lib")] + [SetupCompileBefore ("lib.dll", new[] { "Dependencies/DynamicDependencyInCopyAssembly.cs" })] + [KeptAllTypesAndMembersInAssembly ("lib.dll")] + public class DynamicDependencyFromCopiedAssembly + { + public static void Main () + { + Test (); + } + + [Kept] + static void Test () + { + var b = new DynamicDependencyInCopyAssembly (); + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyKeptOption.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyKeptOption.cs new file mode 100644 index 000000000000..e93ad71244e2 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyKeptOption.cs @@ -0,0 +1,30 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [SetupLinkerArgument ("--keep-dep-attributes", "true")] + class DynamicDependencyKeptOption + { + public static void Main () + { + B.Test (); + } + + class B + { + [Kept] + int field; + + [Kept] + [KeptAttributeAttribute (typeof (DynamicDependencyAttribute))] + + [DynamicDependency ("field")] + public static void Test () + { + } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs new file mode 100644 index 000000000000..98e5ad250f52 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs @@ -0,0 +1,23 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [LogContains ("IL2073: Unresolved member '*' in DynamicDependencyAttribute")] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs" })] + public class DynamicDependencyMemberSignatureWildcard + { + public static void Main () + { + Dependency (); + } + + [Kept] + [DynamicDependency ("*", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")] + static void Dependency () + { + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs new file mode 100644 index 000000000000..1f093d04e0ff --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs @@ -0,0 +1,126 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [LogContains ("IL2037: Unresolved member 'MissingMethod' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] + [LogContains ("IL2037: Unresolved member 'Dependency2``1(``0,System.Int32,System.Object)' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] + [LogContains ("IL2037: Unresolved member '#ctor()' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] + [LogContains ("IL2037: Unresolved member '#cctor()' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] + class DynamicDependencyMethod + { + public static void Main () + { + new B (); // Needed to avoid lazy body marking stubbing + + B.Method (); + B.SameContext (); + B.Broken (); + B.Conditional (); + } + + [KeptMember (".ctor()")] + class B + { + [Kept] + int field; + + [Kept] + void Method2 (out sbyte arg) + { + arg = 1; + } + + [Kept] + [DynamicDependency ("Dependency1()", typeof (C))] + [DynamicDependency ("Dependency2``1(``0[],System.Int32", typeof (C))] + [DynamicDependency ("#ctor()", typeof (C))] // To avoid lazy body marking stubbing + [DynamicDependency ("field", typeof (C))] + [DynamicDependency ("NextOne(Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Nested@)", typeof (Nested))] + [DynamicDependency ("#cctor()", typeof (Nested))] + // Dependency on a property itself should be expressed as a dependency on one or both accessor methods + [DynamicDependency ("get_Property()", typeof (C))] + public static void Method () + { + } + + [Kept] + [DynamicDependency ("field")] + [DynamicDependency ("Method2(System.SByte@)")] + public static void SameContext () + { + } + + [Kept] + [DynamicDependency ("MissingMethod", typeof (C))] + [DynamicDependency ("Dependency2``1(``0,System.Int32,System.Object)", typeof (C))] + [DynamicDependency ("")] + [DynamicDependency ("#ctor()", typeof (NestedStruct))] + [DynamicDependency ("#cctor()", typeof (C))] + public static void Broken () + { + } + + [Kept] + [DynamicDependency ("ConditionalTest()", typeof (C), Condition = "don't have it")] + public static void Conditional () + { + } + } + + class Nested + { + [Kept] + private static void NextOne (ref Nested arg1) + { + } + + [Kept] + static Nested () + { + + } + } + + struct NestedStruct + { + public string Name; + + public NestedStruct (string name) + { + Name = name; + } + } + } + + [KeptMember (".ctor()")] + class C + { + [Kept] + internal string field; + + [Kept] + internal void Dependency1 () + { + } + + internal void Dependency1 (long arg1) + { + } + + [Kept] + internal void Dependency2 (T[] arg1, int arg2) + { + } + + [Kept] + [KeptBackingField] + internal string Property { [Kept] get; set; } + + internal void ConditionalTest () + { + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs new file mode 100644 index 000000000000..aa39e7aeaf7b --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs @@ -0,0 +1,23 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", ".ctor()")] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs" })] + public class DynamicDependencyMethodInAssembly + { + public static void Main () + { + Dependency (); + } + + [Kept] + [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")] + static void Dependency () + { + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssembly.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssembly.cs new file mode 100644 index 000000000000..103c7b33a8bc --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssembly.cs @@ -0,0 +1,42 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)] + [KeptAssembly ("base.dll")] + [KeptAssembly ("library.dll")] + [KeptMemberInAssembly ("base.dll", typeof (DynamicDependencyMethodInNonReferencedAssemblyBase), "Method()")] + [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "Method()")] + public class DynamicDependencyMethodInNonReferencedAssembly + { + public static void Main () + { + var obj = new Foo (); + var val = obj.Method (); + Dependency (); + } + + [Kept] + [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "library")] + static void Dependency () + { + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))] + class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase + { + [Kept] + public override string Method () + { + return "Foo"; + } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChained.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChained.cs new file mode 100644 index 000000000000..07acabf169ae --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChained.cs @@ -0,0 +1,46 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [IgnoreTestCase ("Currently failing")] + [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })] + [SetupCompileBefore ("base2.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs" }, references: new[] { "base.dll" }, addAsReference: false)] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)] + [KeptAssembly ("base.dll")] + [KeptAssembly ("base2.dll")] + [KeptAssembly ("library.dll")] + [KeptMemberInAssembly ("base.dll", typeof (DynamicDependencyMethodInNonReferencedAssemblyBase), "Method()")] + [KeptMemberInAssembly ("base2.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyBase2", "Method()")] + [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary", "Method()")] + public class DynamicDependencyMethodInNonReferencedAssemblyChained + { + public static void Main () + { + var obj = new Foo (); + var val = obj.Method (); + Dependency (); + } + + [Kept] + [DynamicDependency (".ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary", "library")] + static void Dependency () + { + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))] + class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase + { + [Kept] + public override string Method () + { + return "Foo"; + } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReference.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReference.cs new file mode 100644 index 000000000000..26a25634a3df --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReference.cs @@ -0,0 +1,49 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [IgnoreTestCase ("Currently failing")] + [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })] + [SetupCompileBefore ("base2.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase2.cs" }, references: new[] { "base.dll" }, addAsReference: false)] + [SetupCompileBefore ("reference.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary.cs" }, references: new[] { "base.dll", "reference.dll" }, addAsReference: false)] + [KeptAssembly ("base.dll")] + [KeptAssembly ("base2.dll")] + [KeptAssembly ("library.dll")] + [KeptAssembly ("reference.dll")] + [KeptMemberInAssembly ("base.dll", typeof (DynamicDependencyMethodInNonReferencedAssemblyBase), "Method()")] + [KeptMemberInAssembly ("base2.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyBase2", "Method()")] + [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary", "Method()")] + [KeptMemberInAssembly ("reference.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedLibrary", "Method()")] + public class DynamicDependencyMethodInNonReferencedAssemblyChainedReference + { + public static void Main () + { + var obj = new Foo (); + var val = obj.Method (); + Dependency (); + } + + [Kept] + [DynamicDependency (".ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyChainedReferenceLibrary", "library")] + static void Dependency () + { + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))] + class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase + { + [Kept] + public override string Method () + { + return "Foo"; + } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs new file mode 100644 index 000000000000..68f3d62cb4cb --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -0,0 +1,49 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + /// + /// This is an acceptable bug with the currently implementation. Embedded link xml files will not be processed + /// + [IgnoreDescriptors (false)] + [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })] + [SetupCompileBefore ( + "DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll", + new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" }, + references: new[] { "base.dll" }, + resources: new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml" }, + addAsReference: false)] + [KeptAssembly ("base.dll")] + [RemovedMemberInAssembly ("DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "UnusedMethod()")] + public class DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml + { + public static void Main () + { + var obj = new Foo (); + var val = obj.Method (); + Dependency (); + } + + [Kept] + [DynamicDependency (".ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "DynamicDependencyMethodInNonReferencedAssemblyLibrary")] + static void Dependency () + { + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))] + class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase + { + [Kept] + public override string Method () + { + return "Foo"; + } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssembly.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssembly.cs new file mode 100644 index 000000000000..e76c1db84008 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssembly.cs @@ -0,0 +1,39 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)] + [KeptAssembly ("base.dll")] + [RemovedAssembly ("library.dll")] + [KeptMemberInAssembly ("base.dll", typeof (DynamicDependencyMethodInNonReferencedAssemblyBase), "Method()")] + public class DynamicDependencyOnUnusedMethodInNonReferencedAssembly + { + public static void Main () + { + var obj = new Foo (); + var val = obj.Method (); + } + + [DynamicDependency (".ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "library")] + static void Dependency () + { + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))] + class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase + { + [Kept] + public override string Method () + { + return "Foo"; + } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs new file mode 100644 index 000000000000..81fd282bcf7d --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs @@ -0,0 +1,22 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + [SetupLinkerUserAction ("copyused")] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs" }, addAsReference: false)] + [RemovedAssembly ("library.dll")] + public class DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction + { + public static void Main () + { + } + + [DynamicDependency ("MethodPreservedViaDependencyAttribute()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib", "library")] + static void Dependency () + { + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs new file mode 100644 index 000000000000..973630da8b87 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -0,0 +1,47 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + /// + /// This test is here to ensure that link xml embedded in an assembly used by a [DynamicDependency] is not processed if the dependency is not used + /// + [IgnoreDescriptors (false)] + [SetupCompileBefore ("base.dll", new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyBase.cs" })] + [SetupCompileBefore ( + "DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll", + new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.cs" }, + references: new[] { "base.dll" }, + resources: new[] { "Dependencies/DynamicDependencyMethodInNonReferencedAssemblyLibrary.xml" }, + addAsReference: false)] + [KeptAssembly ("base.dll")] + [RemovedAssembly ("DynamicDependencyMethodInNonReferencedAssemblyLibrary.dll")] + public class DynamicDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml + { + public static void Main () + { + var obj = new Foo (); + var val = obj.Method (); + } + + [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "DynamicDependencyMethodInNonReferencedAssemblyLibrary")] + static void Dependency () + { + } + + [Kept] + [KeptMember (".ctor()")] + [KeptBaseType (typeof (DynamicDependencyMethodInNonReferencedAssemblyBase))] + class Foo : DynamicDependencyMethodInNonReferencedAssemblyBase + { + [Kept] + public override string Method () + { + return "Foo"; + } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs index c41022d9df77..8f5ca86d6721 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs @@ -6,7 +6,7 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies.PreserveDependencyMethodInAssemblyLibrary", ".ctor()")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] - [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyMethodInAssemblyLibrary.cs" }, new[] { "FakeSystemAssembly.dll" })] + [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyMethodInAssemblyLibrary.cs" })] public class PreserveDependencyMethodInAssembly { public static void Main () diff --git a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs index 5b3cce796f86..f46086e43d0c 100644 --- a/test/Mono.Linker.Tests/TestCases/TestDatabase.cs +++ b/test/Mono.Linker.Tests/TestCases/TestDatabase.cs @@ -92,6 +92,11 @@ public static IEnumerable PreserveDependenciesTests () return NUnitCasesBySuiteName ("PreserveDependencies"); } + public static IEnumerable DynamicDependenciesTests () + { + return NUnitCasesBySuiteName ("DynamicDependencies"); + } + public static IEnumerable LibrariesTests () { return NUnitCasesBySuiteName ("Libraries"); diff --git a/test/Mono.Linker.Tests/TestCases/TestSuites.cs b/test/Mono.Linker.Tests/TestCases/TestSuites.cs index dab23fcbf931..06b98347b26a 100644 --- a/test/Mono.Linker.Tests/TestCases/TestSuites.cs +++ b/test/Mono.Linker.Tests/TestCases/TestSuites.cs @@ -103,12 +103,18 @@ public void ComponentModelTests (TestCase testCase) Run (testCase); } - [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.PreserveDependenciesTests))] + [TestCaseSource (typeof (TestDatabase),nameof (TestDatabase.PreserveDependenciesTests))] public void PreserveDependenciesTests (TestCase testCase) { Run (testCase); } + [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.DynamicDependenciesTests))] + public void DynamicDependenciesTests (TestCase testCase) + { + Run (testCase); + } + [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.SymbolsTests))] public void SymbolsTests (TestCase testCase) { From 3faac9ea4f8da99c971b0fb4871f3c841d62a624 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 00:06:54 +0000 Subject: [PATCH 03/21] Test PreserveDependency on illink, disable on mono --- ...serveDependencyPreservesInterfaceMethod.cs | 3 + .../PreserveDependencyField.cs | 3 + .../PreserveDependencyFromCopiedAssembly.cs | 3 + .../PreserveDependencyKeptOption.cs | 3 + ...eserveDependencyMemberSignatureWildcard.cs | 3 + .../PreserveDependencyMethod.cs | 3 + .../PreserveDependencyMethodInAssembly.cs | 3 + ...DependencyMethodInNonReferencedAssembly.cs | 3 + ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 3 + .../PreserveDependencyMethodUnsupported.cs | 121 ++++++++++++++++++ ...cyOnUnusedMethodInNonReferencedAssembly.cs | 3 + ...NonReferencedAssemblyWithCopyUsedAction.cs | 3 + ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 3 + .../WorksWithPreserveDependency.cs | 3 + 14 files changed, 160 insertions(+) create mode 100644 test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodUnsupported.cs diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/PreserveDependencyPreservesInterfaceMethod.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/PreserveDependencyPreservesInterfaceMethod.cs index db4a57a8401a..23872ac9aa92 100644 --- a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/PreserveDependencyPreservesInterfaceMethod.cs +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/PreserveDependencyPreservesInterfaceMethod.cs @@ -7,6 +7,9 @@ namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptC /// /// The interface can still be removed in this case because PreserveDependency is just preserving Foo() on the current type /// +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "../../../PreserveDependencies/Dependencies/PreserveDependencyAttribute.cs" })] public class PreserveDependencyPreservesInterfaceMethod { diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyField.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyField.cs index ea451e8121ae..6cba30a0c889 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyField.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyField.cs @@ -4,6 +4,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] public class PreserveDependencyField { diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyFromCopiedAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyFromCopiedAssembly.cs index 78e896cd3990..ad772bfb8a0d 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyFromCopiedAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyFromCopiedAssembly.cs @@ -4,6 +4,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupLinkerAction ("copy", "lib")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("lib.dll", new[] { "Dependencies/PreserveDependencyInCopyAssembly.cs" }, new[] { "FakeSystemAssembly.dll" })] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyKeptOption.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyKeptOption.cs index cc46a7fb6413..af9a41d886f0 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyKeptOption.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyKeptOption.cs @@ -4,6 +4,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupLinkerArgument ("--keep-dep-attributes", "true")] [KeptTypeInAssembly ("FakeSystemAssembly.dll", typeof (PreserveDependencyAttribute))] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMemberSignatureWildcard.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMemberSignatureWildcard.cs index 61d9d4d768cf..727e996f383c 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMemberSignatureWildcard.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMemberSignatureWildcard.cs @@ -4,6 +4,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies.PreserveDependencyMethodInAssemblyLibrary", ".ctor()")] [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies.PreserveDependencyMethodInAssemblyLibrary", "Foo()")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs index c34ec6842426..9e139b58af9f 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs @@ -5,6 +5,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [LogContains ("Could not resolve 'Mono.Linker.Tests.Cases.PreserveDependencies.MissingType' type dependency")] [LogContains ("Could not resolve dependency member 'MissingMethod' declared in type 'Mono.Linker.Tests.Cases.PreserveDependencies.C'")] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs index 8f5ca86d6721..8e74ea629298 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs @@ -4,6 +4,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies.PreserveDependencyMethodInAssemblyLibrary", ".ctor()")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyMethodInAssemblyLibrary.cs" })] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssembly.cs index a035815ea8e1..a922c88343f3 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssembly.cs @@ -5,6 +5,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("base.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyBase.cs" })] [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs index b27d68c0ba95..5fe3521febd8 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -8,6 +8,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies /// /// This is an acceptable bug with the currently implementation. Embedded link xml files will not be processed /// +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [IgnoreDescriptors (false)] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("base.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyBase.cs" })] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodUnsupported.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodUnsupported.cs new file mode 100644 index 000000000000..d2668f364b1f --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodUnsupported.cs @@ -0,0 +1,121 @@ +using System.Runtime.CompilerServices; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.PreserveDependencies +{ + +#if !NETCOREAPP + [IgnoreTestCase ("This test checks that PreserveDependency correctly issues a warning on .NET Core where it is unsupported.")] +#endif + [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] + [LogContains ("IL2029: Unsupported PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethodUnsupported/B::Method()'. Use DynamicDependencyAttribute instead.")] + [LogContains ("IL2029: Unsupported PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethodUnsupported/B::SameContext()'. Use DynamicDependencyAttribute instead.")] + [LogContains ("IL2029: Unsupported PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethodUnsupported/B::Broken()'. Use DynamicDependencyAttribute instead.")] + [LogContains ("IL2029: Unsupported PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethodUnsupported/B::Conditional()'. Use DynamicDependencyAttribute instead.")] + class PreserveDependencyMethodUnsupported + { + public static void Main () + { + new B (); // Needed to avoid lazy body marking stubbing + + B.Method (); + B.SameContext (); + B.Broken (); + B.Conditional (); + } + + [KeptMember (".ctor()")] + class B + { + int field; + + void Method2 (out sbyte arg) + { + arg = 1; + } + + [Kept] + [PreserveDependency ("Dependency1()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + [PreserveDependency ("Dependency2`1 ( T[] , System.Int32 ) ", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + [PreserveDependency (".ctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] // To avoid lazy body marking stubbing + [PreserveDependency ("field", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + [PreserveDependency ("NextOne (Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+Nested&)", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+Nested")] + [PreserveDependency (".cctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+Nested")] + // Dependency on a property itself should be expressed as a dependency on one or both accessor methods + [PreserveDependency ("get_Property()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + public static void Method () + { + } + + [Kept] + [PreserveDependency ("field")] + [PreserveDependency ("Method2 (System.SByte&)")] + public static void SameContext () + { + } + + [Kept] + [PreserveDependency ("MissingType", "Mono.Linker.Tests.Cases.PreserveDependencies.MissingType")] + [PreserveDependency ("MissingMethod", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + [PreserveDependency ("Dependency2`1 (T, System.Int32, System.Object)", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + [PreserveDependency ("")] + [PreserveDependency (".ctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+NestedStruct")] + [PreserveDependency (".cctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + public static void Broken () + { + } + + [Kept] + [PreserveDependency ("ConditionalTest()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported", Condition = "don't have it")] + public static void Conditional () + { + } + } + + class Nested + { + private static void NextOne (ref Nested arg1) + { + } + + static Nested () + { + + } + } + + struct NestedStruct + { + public string Name; + + public NestedStruct (string name) + { + Name = name; + } + } + } + + class CUnsupported + { + internal string field; + + internal void Dependency1 () + { + } + + internal void Dependency1 (long arg1) + { + } + + internal void Dependency2 (T[] arg1, int arg2) + { + } + + internal string Property { get; set; } + + internal void ConditionalTest () + { + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssembly.cs index 3c74c120c437..1824af98edea 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssembly.cs @@ -5,6 +5,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("base.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyBase.cs" })] [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs index f29043cb2a61..09b294013a51 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs @@ -4,6 +4,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupLinkerUserAction ("copyused")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs" }, addAsReference: false)] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs index 010f200b8865..83317c767e1f 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -8,6 +8,9 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies /// /// This test is here to ensure that link xml embedded in an assembly used by a [PreserveDependency] is not processed if the dependency is not used /// +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [IgnoreDescriptors (false)] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("base.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyBase.cs" })] diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs index 5f4cad1d26bd..28c544fa0f65 100644 --- a/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs +++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs @@ -4,6 +4,9 @@ namespace Mono.Linker.Tests.Cases.UnreachableBody { +#if NETCOREAPP + [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] +#endif [SetupLinkerArgument ("--enable-opt", "unreachablebodies")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "../PreserveDependencies/Dependencies/PreserveDependencyAttribute.cs" })] public class WorksWithPreserveDependency From 51fa3b90b433d367a07b7e3aa370852cc3d4653f Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 00:07:09 +0000 Subject: [PATCH 04/21] Add more tests for DynamicDependency --- ...namicDependencyPreservesInterfaceMethod.cs | 38 +++++++++++++++++++ .../WorksWithDynamicDependency.cs | 37 ++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/DynamicDependencyPreservesInterfaceMethod.cs create mode 100644 test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithDynamicDependency.cs diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/DynamicDependencyPreservesInterfaceMethod.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/DynamicDependencyPreservesInterfaceMethod.cs new file mode 100644 index 000000000000..03a7e8fee88e --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/DynamicDependencyPreservesInterfaceMethod.cs @@ -0,0 +1,38 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptCtor +{ + /// + /// The interface can still be removed in this case because PreserveDependency is just preserving Foo() on the current type + /// + public class DynamicDependencyPreservesInterfaceMethod + { + public static void Main () + { + StaticMethodOnlyUsed.StaticMethod (); + } + + interface IUnusedInterface + { + void Foo (); + } + + [Kept] + class StaticMethodOnlyUsed : IUnusedInterface + { + [Kept] + public void Foo () + { + } + + [Kept] + [DynamicDependency ("Foo")] + public static void StaticMethod () + { + } + } + } +} \ No newline at end of file diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithDynamicDependency.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithDynamicDependency.cs new file mode 100644 index 000000000000..0a78b8ad5fb9 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithDynamicDependency.cs @@ -0,0 +1,37 @@ +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.UnreachableBody +{ + [SetupLinkerArgument ("--enable-opt", "unreachablebodies")] + public class WorksWithDynamicDependency + { + public static void Main () + { + Foo.StaticMethod (); + } + + [Kept] + class Foo + { + [Kept] + [DynamicDependency ("InstanceMethod()")] + public static void StaticMethod () + { + } + + [Kept] + [ExpectBodyModified] + public void InstanceMethod () + { + UsedByMethod (); + } + + void UsedByMethod () + { + } + } + } +} \ No newline at end of file From 5dcfa8611568a4790daa5a1d10248c72a0b84f1d Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 00:21:56 +0000 Subject: [PATCH 05/21] Fix whitespace and failing test --- src/linker/Linker/LinkerAttributesInformation.cs | 2 +- ...micDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs | 2 +- test/Mono.Linker.Tests/TestCases/TestSuites.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index c41e580f5d83..22a5e396e74e 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// 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. diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs index 68f3d62cb4cb..334cfb2c4be4 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -29,7 +29,7 @@ public static void Main () } [Kept] - [DynamicDependency (".ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "DynamicDependencyMethodInNonReferencedAssemblyLibrary")] + [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInNonReferencedAssemblyLibrary", "DynamicDependencyMethodInNonReferencedAssemblyLibrary")] static void Dependency () { } diff --git a/test/Mono.Linker.Tests/TestCases/TestSuites.cs b/test/Mono.Linker.Tests/TestCases/TestSuites.cs index 06b98347b26a..739084f0bd09 100644 --- a/test/Mono.Linker.Tests/TestCases/TestSuites.cs +++ b/test/Mono.Linker.Tests/TestCases/TestSuites.cs @@ -103,7 +103,7 @@ public void ComponentModelTests (TestCase testCase) Run (testCase); } - [TestCaseSource (typeof (TestDatabase),nameof (TestDatabase.PreserveDependenciesTests))] + [TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.PreserveDependenciesTests))] public void PreserveDependenciesTests (TestCase testCase) { Run (testCase); From ebe8d9b468dcb994d94c779deb37f80ef43ca4eb Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 00:26:18 +0000 Subject: [PATCH 06/21] Fix mono build with LangVersion latest --- .../Mono.Linker.Tests.Cases.Expectations.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj b/test/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj index 769832748ef5..656d7fd9bc63 100644 --- a/test/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj +++ b/test/Mono.Linker.Tests.Cases.Expectations/Mono.Linker.Tests.Cases.Expectations.csproj @@ -1,5 +1,9 @@ + + latest + + netcoreapp3.0 From 4ead2f0483a497218f72d65ef8a1377e10821eb1 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 17:20:54 +0000 Subject: [PATCH 07/21] Use null sentinel Instead of type itself for DynamicallyAccessedMemberTypes.All --- src/linker/Linker.Steps/MarkStep.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 969a8849c28d..8545cf844ee0 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -660,10 +660,6 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference void MarkMembers (TypeDefinition typeDefinition, IEnumerable members, DependencyInfo reason) { foreach (var member in members) { - if (member == typeDefinition) { - MarkEntireType (typeDefinition, includeBaseTypes: true, reason); - continue; - } switch (member) { case TypeDefinition type: MarkType (type, reason); @@ -684,6 +680,9 @@ void MarkMembers (TypeDefinition typeDefinition, IEnumerable MarkEvent (@event, reason); MarkMethodsIf (@event.OtherMethods, m => true, reason); break; + case null: + MarkEntireType (typeDefinition, includeBaseTypes: true, reason); + break; } } } From e85ce8f628d81515e9c7a03e088c84a3312e023c Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 17:45:53 +0000 Subject: [PATCH 08/21] Changes to attribute caching - Use IMemberDefinition as key - Remove optimization for DynamicDependencyAttribute case - Add optimization to check for presence of attributes in the cache - Add checking of member types for the attributes --- .../DynamicDependencyLookupStep.cs | 16 +---- src/linker/Linker.Steps/MarkStep.cs | 19 +---- src/linker/Linker/Annotations.cs | 71 ++++++------------- .../Linker/LinkerAttributesInformation.cs | 55 +++++++------- 4 files changed, 49 insertions(+), 112 deletions(-) diff --git a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs index 4cc15093309f..99c18c1dfcda 100644 --- a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs +++ b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs @@ -55,11 +55,7 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) { Debug.Assert (member is MethodDefinition || member is FieldDefinition); - bool hasDynamicDependencyAttributes = false; foreach (var ca in member.CustomAttributes) { - if (LinkerAttributesInformation.IsAttribute (ca.AttributeType)) - hasDynamicDependencyAttributes = true; - if (!IsPreserveDependencyAttribute (ca.AttributeType)) continue; #if FEATURE_ILLINK @@ -80,16 +76,8 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) #endif } - // avoid allocating linker attributes for members that don't need them - if (!hasDynamicDependencyAttributes) - return; - - var dynamicDependencies = member switch - { - MethodDefinition method => Context.Annotations.GetLinkerAttributes (method), - FieldDefinition field => Context.Annotations.GetLinkerAttributes (field), - _ => throw new InternalErrorException ("Unexpected member type") - }; + var dynamicDependencies = Context.Annotations.GetLinkerAttributes (member); + Debug.Assert (dynamicDependencies != null); foreach (var dynamicDependency in dynamicDependencies) { if (dynamicDependency.AssemblyName == null) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 8545cf844ee0..a2f8c007a29d 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -531,11 +531,7 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo bool markOnUse = _context.KeepUsedAttributeTypesOnly && Annotations.GetAction (GetAssemblyFromCustomAttributeProvider (provider)) == AssemblyAction.Link; - bool hasDynamicDependencyAttributes = false; foreach (CustomAttribute ca in provider.CustomAttributes) { - if (LinkerAttributesInformation.IsAttribute (ca.AttributeType)) - hasDynamicDependencyAttributes = true; - if (ProcessLinkerSpecialAttribute (ca, provider, reason)) continue; @@ -548,19 +544,11 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo MarkSpecialCustomAttributeDependencies (ca, provider); } - // avoid allocating linker attributes for members that don't need them - if (!hasDynamicDependencyAttributes) + if (!(provider is MethodDefinition || provider is FieldDefinition)) return; - var dynamicDependencies = provider switch - { - MethodDefinition method => _context.Annotations.GetLinkerAttributes (method), - FieldDefinition field => _context.Annotations.GetLinkerAttributes (field), - _ => null - }; - - if (dynamicDependencies == null) - return; + var dynamicDependencies = _context.Annotations.GetLinkerAttributes ((IMemberDefinition) provider); + Debug.Assert (dynamicDependencies != null); foreach (var dynamicDependency in dynamicDependencies) MarkDynamicDependency (dynamicDependency, (MemberReference) provider); @@ -2736,7 +2724,6 @@ bool HasManuallyTrackedDependency (MethodBody methodBody) if (!method.HasCustomAttributes) return false; - // avoid allocating linker attributes for members that don't need them foreach (var ca in method.CustomAttributes) { if (LinkerAttributesInformation.IsAttribute (ca.AttributeType)) return true; diff --git a/src/linker/Linker/Annotations.cs b/src/linker/Linker/Annotations.cs index 6cb058b65a62..7489e93f7304 100644 --- a/src/linker/Linker/Annotations.cs +++ b/src/linker/Linker/Annotations.cs @@ -55,8 +55,7 @@ public partial class AnnotationStore protected readonly Dictionary> override_methods = new Dictionary> (); protected readonly Dictionary> base_methods = new Dictionary> (); protected readonly Dictionary symbol_readers = new Dictionary (); - readonly Dictionary method_linker_attributes = new Dictionary (); - readonly Dictionary field_linker_attributes = new Dictionary (); + readonly Dictionary linker_attributes = new Dictionary (); readonly Dictionary> custom_annotations = new Dictionary> (); protected readonly Dictionary> resources_to_remove = new Dictionary> (); @@ -429,76 +428,46 @@ public bool SetPreservedStaticCtor (TypeDefinition type) return marked_types_with_cctor.Add (type); } - public bool HasLinkerAttribute (MethodDefinition method) + public bool HasLinkerAttribute (IMemberDefinition member) { - if (!method_linker_attributes.TryGetValue (method, out var linkerAttributeInformation)) { - linkerAttributeInformation = new LinkerAttributesInformation (context, method); - method_linker_attributes.Add (method, linkerAttributeInformation); - } - - return linkerAttributeInformation.HasAttribute (); - } + // Avoid setting up and inserting LinkerAttributesInformation for members without attributes. + if (!member.HasCustomAttributes) + return false; - public bool HasLinkerAttribute (FieldDefinition field) - { - if (!field_linker_attributes.TryGetValue (field, out var linkerAttributeInformation)) { - linkerAttributeInformation = new LinkerAttributesInformation (context, field); - field_linker_attributes.Add (field, linkerAttributeInformation); + if (!linker_attributes.TryGetValue (member, out var linkerAttributeInformation)) { + linkerAttributeInformation = new LinkerAttributesInformation (context, member); + linker_attributes.Add (member, linkerAttributeInformation); } return linkerAttributeInformation.HasAttribute (); } - public IEnumerable GetLinkerAttributes (MethodDefinition method) + public IEnumerable GetLinkerAttributes (IMemberDefinition member) { - if (!method_linker_attributes.TryGetValue (method, out var linkerAttributeInformation)) { - linkerAttributeInformation = new LinkerAttributesInformation (context, method); - method_linker_attributes.Add (method, linkerAttributeInformation); - } + // Avoid setting up and inserting LinkerAttributesInformation for members without attributes. + if (!member.HasCustomAttributes) + return Enumerable.Empty (); - return linkerAttributeInformation.GetAttributes (); - } - - public IEnumerable GetLinkerAttributes (FieldDefinition field) - { - if (!field_linker_attributes.TryGetValue (field, out var linkerAttributeInformation)) { - linkerAttributeInformation = new LinkerAttributesInformation (context, field); - field_linker_attributes.Add (field, linkerAttributeInformation); + if (!linker_attributes.TryGetValue (member, out var linkerAttributeInformation)) { + linkerAttributeInformation = new LinkerAttributesInformation (context, member); + linker_attributes.Add (member, linkerAttributeInformation); } return linkerAttributeInformation.GetAttributes (); } - public bool TryGetLinkerAttribute (MethodDefinition method, out T attribute) + public bool TryGetLinkerAttribute (IMemberDefinition member, out T attribute) { - var attributes = GetLinkerAttributes (method); - if (attributes.Count () > 1) { - context.LogWarning ($"Attribute '{typeof (T).FullName}' should only be used once on '{method}'.", - 2027, MessageOrigin.TryGetOrigin (method, 0)); - } - - Debug.Assert (attributes.Count () <= 1); - attribute = attributes.FirstOrDefault (); - return attribute != null; - } - - public bool TryGetLinkerAttribute (FieldDefinition field, out T attribute) - { - var attributes = GetLinkerAttributes (field); + var attributes = GetLinkerAttributes (member); if (attributes.Count () > 1) { context.LogMessage (MessageContainer.CreateWarningMessage (context, - $"Attribute '{typeof (T).FullName}' should only be used once on '{field}'.", - 2027, - origin: MessageOrigin.TryGetOrigin (field, 0))); + $"Attribute '{typeof (T).FullName}' should only be used once on '{member}'.", + 2027, MessageOrigin.TryGetOrigin (member, 0))); } + Debug.Assert (attributes.Count () <= 1); attribute = attributes.FirstOrDefault (); return attribute != null; } - - public bool IsAttribute (CustomAttribute attribute) - { - return attribute.AttributeType.FullName == typeof (T).FullName; - } } } diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index 22a5e396e74e..174be094d503 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -15,33 +15,18 @@ readonly struct LinkerAttributesInformation { readonly Dictionary> _linkerAttributes; - public LinkerAttributesInformation (LinkContext context, IMemberDefinition member) + public LinkerAttributesInformation (LinkContext context, ICustomAttributeProvider provider) { _linkerAttributes = null; - if (member.HasCustomAttributes) { - foreach (var customAttribute in member.CustomAttributes) { + if (provider.HasCustomAttributes) { + foreach (var customAttribute in provider.CustomAttributes) { var attributeType = customAttribute.AttributeType; object attributeValue = null; if (IsAttribute (attributeType)) - attributeValue = ProcessRequiresUnreferencedCodeAttribute (context, member, customAttribute); + attributeValue = ProcessRequiresUnreferencedCodeAttribute (context, provider, customAttribute); else if (IsAttribute (attributeType)) - attributeValue = ProcessDynamicDependencyAttribute (context, member, customAttribute); - AddAttribute (ref _linkerAttributes, attributeValue); - } - } - } - - public LinkerAttributesInformation (LinkContext context, FieldDefinition field) - { - _linkerAttributes = null; - - if (field.HasCustomAttributes) { - foreach (var customAttribute in field.CustomAttributes) { - var attributeType = customAttribute.AttributeType; - object attributeValue = null; - if (IsAttribute (attributeType)) - attributeValue = ProcessDynamicDependencyAttribute (context, field, customAttribute); + attributeValue = ProcessDynamicDependencyAttribute (context, provider, customAttribute); AddAttribute (ref _linkerAttributes, attributeValue); } } @@ -87,8 +72,11 @@ public static bool IsAttribute (TypeReference tr) return tr.Name == type.Name && tr.Namespace == tr.Namespace; } - static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, IMemberDefinition method, CustomAttribute customAttribute) + static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, ICustomAttributeProvider provider, CustomAttribute customAttribute) { + if (!(provider is MethodDefinition method)) + return null; + if (customAttribute.HasConstructorArguments) { string message = (string) customAttribute.ConstructorArguments[0].Value; string url = null; @@ -106,21 +94,23 @@ static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, return null; } - static DynamicDependency ProcessDynamicDependencyAttribute (LinkContext context, IMemberDefinition member, CustomAttribute customAttribute) + static DynamicDependency ProcessDynamicDependencyAttribute (LinkContext context, ICustomAttributeProvider provider, CustomAttribute customAttribute) { + if (!(provider is MethodDefinition || provider is FieldDefinition)) + return null; + var member = provider as IMemberDefinition; + if (!ShouldProcessDependencyAttribute (context, customAttribute)) return null; var dynamicDependency = GetDynamicDependency (context, customAttribute); - if (dynamicDependency == null) { - context.LogMessage (MessageContainer.CreateWarningMessage (context, - $"Invalid DynamicDependencyAttribute on '{member}'", - 2034, MessageOrigin.TryGetOrigin (member))); - return null; - } + if (dynamicDependency != null) + return dynamicDependency; - dynamicDependency.OriginalAttribute = customAttribute; - return dynamicDependency; + context.LogMessage (MessageContainer.CreateWarningMessage (context, + $"Invalid DynamicDependencyAttribute on '{member}'", + 2034, MessageOrigin.TryGetOrigin (member))); + return null; } static DynamicDependency GetDynamicDependency (LinkContext context, CustomAttribute ca) @@ -159,7 +149,10 @@ static DynamicDependency GetDynamicDependency (LinkContext context, CustomAttrib if (!(args[2].Value is string assemblyName)) return null; - return memberSignature == null ? new DynamicDependency (memberTypes.Value, typeName, assemblyName) : new DynamicDependency (memberSignature, typeName, assemblyName); + var dynamicDependency = memberSignature == null ? new DynamicDependency (memberTypes.Value, typeName, assemblyName) : new DynamicDependency (memberSignature, typeName, assemblyName); + dynamicDependency.OriginalAttribute = ca; + + return dynamicDependency; } public static bool ShouldProcessDependencyAttribute (LinkContext context, CustomAttribute ca) From 39bb0dc678f5f06a08b492acb5c77c013ea8ead3 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 21:52:24 +0000 Subject: [PATCH 09/21] Use Attribute type in cache, and move helpers to DynamicDependency --- src/linker/Linker/Annotations.cs | 6 +- src/linker/Linker/DynamicDependency.cs | 89 ++++++++++++++++++- .../Linker/LinkerAttributesInformation.cs | 18 ++-- 3 files changed, 99 insertions(+), 14 deletions(-) diff --git a/src/linker/Linker/Annotations.cs b/src/linker/Linker/Annotations.cs index 7489e93f7304..f1ab366be4e0 100644 --- a/src/linker/Linker/Annotations.cs +++ b/src/linker/Linker/Annotations.cs @@ -428,7 +428,7 @@ public bool SetPreservedStaticCtor (TypeDefinition type) return marked_types_with_cctor.Add (type); } - public bool HasLinkerAttribute (IMemberDefinition member) + public bool HasLinkerAttribute (IMemberDefinition member) where T : Attribute { // Avoid setting up and inserting LinkerAttributesInformation for members without attributes. if (!member.HasCustomAttributes) @@ -442,7 +442,7 @@ public bool HasLinkerAttribute (IMemberDefinition member) return linkerAttributeInformation.HasAttribute (); } - public IEnumerable GetLinkerAttributes (IMemberDefinition member) + public IEnumerable GetLinkerAttributes (IMemberDefinition member) where T : Attribute { // Avoid setting up and inserting LinkerAttributesInformation for members without attributes. if (!member.HasCustomAttributes) @@ -456,7 +456,7 @@ public IEnumerable GetLinkerAttributes (IMemberDefinition member) return linkerAttributeInformation.GetAttributes (); } - public bool TryGetLinkerAttribute (IMemberDefinition member, out T attribute) + public bool TryGetLinkerAttribute (IMemberDefinition member, out T attribute) where T : Attribute { var attributes = GetLinkerAttributes (member); if (attributes.Count () > 1) { diff --git a/src/linker/Linker/DynamicDependency.cs b/src/linker/Linker/DynamicDependency.cs index 3d9315f90c6a..c0e0cbca18c4 100644 --- a/src/linker/Linker/DynamicDependency.cs +++ b/src/linker/Linker/DynamicDependency.cs @@ -1,3 +1,5 @@ +using System; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Mono.Cecil; @@ -8,8 +10,9 @@ namespace Mono.Linker /// Tracks dependencies created via DynamicDependencyAttribute in the linker. /// This is almost identical to DynamicDependencyAttribute, but it holds a /// TypeReference instead of a Type, and it has a reference to the original - /// CustomAttribute for dependency tracing. - internal class DynamicDependency + /// CustomAttribute for dependency tracing. It is also a place for helper + /// methods related to the attribute. + internal class DynamicDependency : Attribute { public CustomAttribute? OriginalAttribute { get; set; } public DynamicDependency (string memberSignature) @@ -54,5 +57,87 @@ public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, string typ public string? AssemblyName { get; } public string? Condition { get; set; } + + public static DynamicDependency? ProcessAttribute (LinkContext context, ICustomAttributeProvider provider, CustomAttribute customAttribute) + { + if (!(provider is MethodDefinition || provider is FieldDefinition)) + return null; + var member = provider as IMemberDefinition; + + if (!DynamicDependency.ShouldProcess (context, customAttribute)) + return null; + + var dynamicDependency = GetDynamicDependency (context, customAttribute); + if (dynamicDependency != null) + return dynamicDependency; + + context.LogMessage (MessageContainer.CreateWarningMessage (context, + $"Invalid DynamicDependencyAttribute on '{member}'", + 2030, MessageOrigin.TryGetOrigin (member))); + return null; + } + + static DynamicDependency? GetDynamicDependency (LinkContext context, CustomAttribute ca) + { + var args = ca.ConstructorArguments; + if (args.Count < 1 || args.Count > 3) + return null; + + // First argument is string or DynamicallyAccessedMemberTypes + string? memberSignature = args[0].Value as string; + if (args.Count == 1) + return memberSignature == null ? null : new DynamicDependency (memberSignature); + DynamicallyAccessedMemberTypes? memberTypes = null; + if (memberSignature == null) { + var argType = args[0].Type; + if (!(argType.Namespace == "System.Diagnostics.CodeAnalysis" && argType.Name == "DynamicallyAccessedMemberTypes")) + return null; + try { + memberTypes = (DynamicallyAccessedMemberTypes) args[0].Value; + } catch (InvalidCastException) { } + if (memberTypes == null) + return null; + } + + // Second argument is Type for ctors with two args, string for ctors with three args + if (args.Count == 2) { + if (!(args[1].Value is TypeReference type)) + return null; + return memberSignature == null ? new DynamicDependency (memberTypes!.Value, type) : new DynamicDependency (memberSignature, type); + } + Debug.Assert (args.Count == 3); + if (!(args[1].Value is string typeName)) + return null; + + // Third argument is assembly name + if (!(args[2].Value is string assemblyName)) + return null; + + var dynamicDependency = memberSignature == null ? new DynamicDependency (memberTypes!.Value, typeName, assemblyName) : new DynamicDependency (memberSignature, typeName, assemblyName); + dynamicDependency.OriginalAttribute = ca; + + return dynamicDependency; + } + + public static bool ShouldProcess (LinkContext context, CustomAttribute ca) + { + if (ca.HasProperties && ca.Properties[0].Name == "Condition") { + var condition = ca.Properties[0].Argument.Value as string; + switch (condition) { + case "": + case null: + return true; + case "DEBUG": + if (!context.KeepMembersForDebugger) + return false; + + break; + default: + // Don't have yet a way to match the general condition so everything is excluded + return false; + } + } + return true; + } } } \ No newline at end of file diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index 174be094d503..67ec96014f95 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -13,7 +13,7 @@ namespace Mono.Linker { readonly struct LinkerAttributesInformation { - readonly Dictionary> _linkerAttributes; + readonly Dictionary> _linkerAttributes; public LinkerAttributesInformation (LinkContext context, ICustomAttributeProvider provider) { @@ -22,39 +22,39 @@ public LinkerAttributesInformation (LinkContext context, ICustomAttributeProvide if (provider.HasCustomAttributes) { foreach (var customAttribute in provider.CustomAttributes) { var attributeType = customAttribute.AttributeType; - object attributeValue = null; + Attribute attributeValue = null; if (IsAttribute (attributeType)) attributeValue = ProcessRequiresUnreferencedCodeAttribute (context, provider, customAttribute); else if (IsAttribute (attributeType)) - attributeValue = ProcessDynamicDependencyAttribute (context, provider, customAttribute); + attributeValue = DynamicDependency.ProcessAttribute (context, provider, customAttribute); AddAttribute (ref _linkerAttributes, attributeValue); } } } - static void AddAttribute (ref Dictionary> attributes, object attributeValue) + static void AddAttribute (ref Dictionary> attributes, Attribute attributeValue) { if (attributeValue == null) return; if (attributes == null) - attributes = new Dictionary> (); + attributes = new Dictionary> (); Type attributeValueType = attributeValue.GetType (); if (!attributes.TryGetValue (attributeValueType, out var attributeList)) { - attributeList = new List (); + attributeList = new List (); attributes.Add (attributeValueType, attributeList); } attributeList.Add (attributeValue); } - public bool HasAttribute () + public bool HasAttribute () where T : Attribute { return _linkerAttributes != null && _linkerAttributes.ContainsKey (typeof (T)); } - public IEnumerable GetAttributes () + public IEnumerable GetAttributes () where T : Attribute { if (_linkerAttributes == null || !_linkerAttributes.TryGetValue (typeof (T), out var attributeList)) return Enumerable.Empty (); @@ -66,7 +66,7 @@ public IEnumerable GetAttributes () return attributeList.Cast (); } - public static bool IsAttribute (TypeReference tr) + public static bool IsAttribute (TypeReference tr) where T : Attribute { var type = typeof (T); return tr.Name == type.Name && tr.Namespace == tr.Namespace; From 60efa312fc9e8a6286a72aad3de27b8103aca145 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 22:05:51 +0000 Subject: [PATCH 10/21] Remove DynamicDependencyAttribute implementation --- .../DynamicDependencyAttribute.cs | 126 +----------------- 1 file changed, 2 insertions(+), 124 deletions(-) diff --git a/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs b/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs index 843d45c03e35..f7d594ef2a17 100644 --- a/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs +++ b/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs @@ -6,131 +6,9 @@ namespace System.Diagnostics.CodeAnalysis { - /// - /// States a dependency that one member has on another. - /// - /// - /// This can be used to inform tooling of a dependency that is otherwise not evident purely from - /// metadata and IL, for example a member relied on via reflection. - /// - /// - /// This is a copy of the enum definition in the framework at https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs - /// - [AttributeUsage ( - AttributeTargets.Constructor | AttributeTargets.Field | AttributeTargets.Method, - AllowMultiple = true, Inherited = false)] + /// This is a n internal version of copy of the attribute in the framework at https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs + /// We currently only use the type as a generic parameter, so the implementation isn't copied. internal sealed class DynamicDependencyAttribute : Attribute { - /// - /// Initializes a new instance of the class - /// with the specified signature of a member on the same type as the consumer. - /// - /// The signature of the member depended on. - public DynamicDependencyAttribute (string memberSignature) - { - MemberSignature = memberSignature; - } - - /// - /// Initializes a new instance of the class - /// with the specified signature of a member on a . - /// - /// The signature of the member depended on. - /// The containing . - public DynamicDependencyAttribute (string memberSignature, Type type) - { - MemberSignature = memberSignature; - Type = type; - } - - /// - /// Initializes a new instance of the class - /// with the specified signature of a member on a type in an assembly. - /// - /// The signature of the member depended on. - /// The full name of the type containing the specified member. - /// The assembly name of the type containing the specified member. - public DynamicDependencyAttribute (string memberSignature, string typeName, string assemblyName) - { - MemberSignature = memberSignature; - TypeName = typeName; - AssemblyName = assemblyName; - } - - /// - /// Initializes a new instance of the class - /// with the specified types of members on a . - /// - /// The types of members depended on. - /// The containing the specified members. - public DynamicDependencyAttribute (DynamicallyAccessedMemberTypes memberTypes, Type type) - { - MemberTypes = memberTypes; - Type = type; - } - - /// - /// Initializes a new instance of the class - /// with the specified types of members on a type in an assembly. - /// - /// The types of members depended on. - /// The full name of the type containing the specified members. - /// The assembly name of the type containing the specified members. - public DynamicDependencyAttribute (DynamicallyAccessedMemberTypes memberTypes, string typeName, string assemblyName) - { - MemberTypes = memberTypes; - TypeName = typeName; - AssemblyName = assemblyName; - } - - /// - /// Gets the signature of the member depended on. - /// - /// - /// Either must be a valid string or - /// must not equal , but not both. - /// - public string? MemberSignature { get; } - - /// - /// Gets the which specifies the type - /// of members depended on. - /// - /// - /// Either must be a valid string or - /// must not equal , but not both. - /// - public DynamicallyAccessedMemberTypes MemberTypes { get; } - - /// - /// Gets the containing the specified member. - /// - /// - /// If neither nor are specified, - /// the type of the consumer is assumed. - /// - public Type? Type { get; } - - /// - /// Gets the full name of the type containing the specified member. - /// - /// - /// If neither nor are specified, - /// the type of the consumer is assumed. - /// - public string? TypeName { get; } - - /// - /// Gets the assembly name of the specified type. - /// - /// - /// is only valid when is specified. - /// - public string? AssemblyName { get; } - - /// - /// Gets or sets the condition in which the dependency is applicable, e.g. "DEBUG". - /// - public string? Condition { get; set; } } } From aaa9ffa922bd7c05429cd00d5152ff657cfaaa08 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 22:06:51 +0000 Subject: [PATCH 11/21] Don't disable flow analysis for Dynamic/PreserveDependency --- src/linker/Linker.Steps/MarkStep.cs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index a2f8c007a29d..35ab8295a55f 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -2717,24 +2717,6 @@ protected virtual void MarkInterfaceImplementation (InterfaceImplementation ifac Annotations.Mark (iface, new DependencyInfo (DependencyKind.InterfaceImplementationOnType, type)); } - bool HasManuallyTrackedDependency (MethodBody methodBody) - { - var method = methodBody.Method; - - if (!method.HasCustomAttributes) - return false; - - foreach (var ca in method.CustomAttributes) { - if (LinkerAttributesInformation.IsAttribute (ca.AttributeType)) - return true; -#if !FEATURE_ILLINK - if (DynamicDependencyLookupStep.IsPreserveDependencyAttribute (ca.AttributeType)) - return true; -#endif - } - return false; - } - // // Extension point for reflection logic handling customization // @@ -2748,9 +2730,6 @@ protected virtual bool ProcessReflectionDependency (MethodBody body, Instruction // protected virtual void MarkReflectionLikeDependencies (MethodBody body, bool requiresReflectionMethodBodyScanner) { - if (HasManuallyTrackedDependency (body)) - return; - if (requiresReflectionMethodBodyScanner) { var scanner = new ReflectionMethodBodyScanner (_context, this, _flowAnnotations); scanner.ScanAndProcessReturnValue (body); From bf5f4233448b7d3b5b403a046abcf25d2e4f0917 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Thu, 28 May 2020 00:16:39 +0000 Subject: [PATCH 12/21] Add tests for DynamicallyAccessedMemberTypes --- src/linker/Linker.Steps/MarkStep.cs | 3 +- ...ynamicDependencyMethodInAssemblyLibrary.cs | 2 + .../DynamicDependencyMemberTypes.cs | 280 ++++++++++++++++++ .../DynamicDependencyMethod.cs | 19 ++ .../DynamicDependencyMethodInAssembly.cs | 2 + 5 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberTypes.cs diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 35ab8295a55f..f4b399c6ad03 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -94,6 +94,7 @@ public partial class MarkStep : IStep DependencyKind.CustomAttributeArgumentValue, DependencyKind.DeclaringType, DependencyKind.DeclaringTypeOfCalledMethod, + DependencyKind.DynamicDependency, DependencyKind.ElementType, DependencyKind.FieldType, DependencyKind.GenericArgumentType, @@ -698,7 +699,7 @@ protected virtual bool IsUserDependencyMarker (TypeReference type) #if !FEATURE_ILLINK protected virtual void MarkUserDependency (MemberReference context, CustomAttribute ca) { - if (!LinkerAttributesInformation.ShouldProcessDependencyAttribute (_context, ca)) + if (!DynamicDependency.ShouldProcess (_context, ca)) return; AssemblyDefinition assembly; diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs index 1e0e385e4ebe..fc625b8694f1 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs @@ -10,5 +10,7 @@ public DynamicDependencyMethodInAssemblyLibrary () private void Foo () { } + + private int privateField; } } diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberTypes.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberTypes.cs new file mode 100644 index 000000000000..f3c9629394e0 --- /dev/null +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberTypes.cs @@ -0,0 +1,280 @@ +using System; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.DynamicDependencies +{ + class DynamicDependencyMemberTypes + { + public static void Main () + { + B.Method (); + } + + static class B + { + [Kept] + [DynamicDependency (DynamicallyAccessedMemberTypes.DefaultConstructor, typeof (TypeWithAutoImplementedDefaultConstructor))] + [DynamicDependency (DynamicallyAccessedMemberTypes.DefaultConstructor, typeof (TypeWithDefaultConstructor))] + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicConstructors, typeof (TypeWithPublicConstructor))] + [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicConstructors, typeof (TypeWithNonPublicConstructor))] + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicMethods, typeof (TypeWithPublicMethod))] + [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicMethods, typeof (TypeWithNonPublicMethod))] + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicFields, typeof (TypeWithPublicField))] + [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicFields, typeof (TypeWithNonPublicField))] + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicNestedTypes, typeof (TypeWithPublicNestedType))] + [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicNestedTypes, typeof (TypeWithNonPublicNestedType))] + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicProperties, typeof (TypeWithPublicProperty))] + [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicProperties, typeof (TypeWithNonPublicProperty))] + [DynamicDependency (DynamicallyAccessedMemberTypes.PublicEvents, typeof (TypeWithPublicEvent))] + [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicEvents, typeof (TypeWithNonPublicEvent))] + [DynamicDependency (DynamicallyAccessedMemberTypes.All, typeof (TypeWithAll))] + [DynamicDependency (DynamicallyAccessedMemberTypes.None, typeof (TypeWithNone))] + public static void Method () + { + } + } + + + [KeptMember (".ctor()")] + class TypeWithAutoImplementedDefaultConstructor + { + public void Method () { } + + public int field; + } + + class TypeWithDefaultConstructor + { + [Kept] + public TypeWithDefaultConstructor () { } + + public TypeWithDefaultConstructor (int i) { } + } + + class TypeWithPublicConstructor + { + [Kept] + public TypeWithPublicConstructor (int i) { } + + [Kept] + public TypeWithPublicConstructor (string s) { } + + TypeWithPublicConstructor () { } + } + + class TypeWithNonPublicConstructor + { + public TypeWithNonPublicConstructor (int i) { } + + [Kept] + TypeWithNonPublicConstructor () { } + + [Kept] + TypeWithNonPublicConstructor (string s) { } + } + + + class TypeWithPublicMethod + { + [Kept] + public void PublicMethod () { } + + void PrivateMethod () { } + + public int field; + } + + class TypeWithNonPublicMethod + { + [Kept] + void PrivateMethod () { } + + public void NonPublicMethod () { } + } + + class TypeWithPublicField + { + [Kept] + public int publicField; + + string nonPublicField; + + public void Method () { } + } + + class TypeWithNonPublicField + { + [Kept] + int nonPublicField; + + public string publicField; + + void Method () { } + } + + [Kept] + class TypeWithPublicNestedType + { + [Kept] + public class PublicNestedType + { + public void Method () { } + public int field; + + void NonPublicMethod () { } + } + + public void Method () { } + + void NonPublicMethod () { } + + class NonPublicNestedType + { + } + } + + [Kept] + class TypeWithNonPublicNestedType + { + [Kept] + class NonPublicNestedType + { + public void Method () { } + + public int field; + + void NonPublicMethod () { } + } + + public void Method () { } + + void NonPublicMethod () { } + + public class PublicNestedType + { + } + } + + class TypeWithPublicProperty + { + [Kept] + [KeptBackingField] + public int Property { [Kept] get; [Kept] set; } + + int NonPublicProperty { get; set; } + + public void Method () { } + } + + class TypeWithNonPublicProperty + { + [Kept] + [KeptBackingField] + int NonPublicProperty { [Kept] get; [Kept] set; } + + public int PublicProperty { get; set; } + + void NonPublicMethod () { } + } + + class TypeWithPublicEvent + { + [Kept] + [KeptBackingField] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + public event EventHandler PublicEvent; + + event EventHandler NonPublicEvent; + + public void Method () { } + } + + class TypeWithNonPublicEvent + { + [Kept] + [KeptBackingField] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + event EventHandler NonPublicEvent; + + public event EventHandler PublicEven; + + void NonPublicMethod () { } + } + + [KeptMember (".ctor()")] + class TypeWithAll + { + [Kept] + public void PublicMethod () { } + + [Kept] + void NonPublicMehod () { } + + [Kept] + public int publicField; + + [Kept] + int nonPublicField; + + [Kept] + [KeptBackingField] + public int PublicProperty { [Kept] get; [Kept] set; } + + [Kept] + [KeptBackingField] + int NonPublicProperty { [Kept] get; [Kept] set; } + + [Kept] + [KeptBackingField] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + public event EventHandler PublicEvent; + + [Kept] + [KeptBackingField] + [KeptEventAddMethod] + [KeptEventRemoveMethod] + event EventHandler NonPublicEvent; + + [Kept] + [KeptMember (".ctor()")] + public class PublicNestedType + { + [Kept] + [KeptMember (".ctor()")] + class RecursiveNestedType + { + [Kept] + void Method () { } + } + } + + [Kept] + [KeptMember (".ctor()")] + class NonPublicNestedType + { + [Kept] + [KeptMember (".ctor()")] + class RecursiveNestedType + { + [Kept] + void Method () { } + } + } + } + + public class TypeWithNone + { + public void Method () { } + + public int field; + + public class NestedType { } + } + } +} diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs index 1f093d04e0ff..c70d71ede31f 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs @@ -42,6 +42,10 @@ void Method2 (out sbyte arg) [DynamicDependency ("#cctor()", typeof (Nested))] // Dependency on a property itself should be expressed as a dependency on one or both accessor methods [DynamicDependency ("get_Property()", typeof (C))] + [DynamicDependency ("M``1(Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.S{" + + "Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.G{" + + "Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod.Complex.A,``0}}" + + "[0:,0:,0:][][][0:,0:]@)", typeof (Complex))] public static void Method () { } @@ -84,6 +88,21 @@ static Nested () } } + class Complex + { + [Kept] + public struct S { } + [Kept] + public class A { } + [Kept] + public class G { } + + [Kept] + public void M (ref S>[,][][][,,] a) + { + } + } + struct NestedStruct { public string Name; diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs index aa39e7aeaf7b..be03791c4132 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethodInAssembly.cs @@ -6,6 +6,7 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies { [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", ".ctor()")] + [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "privateField")] [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs" })] public class DynamicDependencyMethodInAssembly { @@ -16,6 +17,7 @@ public static void Main () [Kept] [DynamicDependency ("#ctor()", "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")] + [DynamicDependency (DynamicallyAccessedMemberTypes.NonPublicFields, "Mono.Linker.Tests.Cases.DynamicDependencies.Dependencies.DynamicDependencyMethodInAssemblyLibrary", "library")] static void Dependency () { } From b35fe9cc4a53d4b367ac2a24cc1ab390ed608ba2 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 27 May 2020 17:23:59 -0700 Subject: [PATCH 13/21] Update docs/error-codes.md Co-authored-by: Vitek Karas --- docs/error-codes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/error-codes.md b/docs/error-codes.md index cd879dccdae4..78b550dd9c23 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -209,4 +209,4 @@ error and warning codes. #### `IL2038`: No members were resolved for for 'memberTypes' in DynamicDependencyAttribute on 'member' -- The DynamicallyAccessedMemberTypes passed into the DynamicDependencyAttribute constructor did not match any members on the specified type. No members will be kept for this attribute. Ensure that you are using DynamicallyAccessedMemberTypes which exist for the type. +- The DynamicallyAccessedMemberTypes passed into the DynamicDependencyAttribute constructor did not match any members on the specified type. No members will be kept for this type. Ensure that you are using DynamicallyAccessedMemberTypes which exist for the type. From 0c4154bfc0ab3fd330b9cee5f865d68b236cff3c Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 29 May 2020 17:53:44 +0000 Subject: [PATCH 14/21] PR feedback - Remove assert - Move helpers to signature parser - Consolidate warning messages --- docs/error-codes.md | 8 ++----- src/linker/Linker.Steps/MarkStep.cs | 11 +++++----- src/linker/Linker/AssemblyUtilities.cs | 11 ---------- .../Linker/DocumentationSignatureParser.cs | 22 +++++++++++++++++++ src/linker/Linker/DynamicDependency.cs | 4 ++-- .../Linker/LinkerAttributesInformation.cs | 10 ++------- src/linker/Linker/TypeDefinitionExtensions.cs | 11 ---------- src/linker/Linker/TypeReferenceExtensions.cs | 6 +++++ 8 files changed, 39 insertions(+), 44 deletions(-) diff --git a/docs/error-codes.md b/docs/error-codes.md index 78b550dd9c23..bf6a68948432 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -203,10 +203,6 @@ error and warning codes. - The type in a DynamicDependencyAttribute constructor could not be resolved. Ensure that the argument specifies a valid type name or type reference, that the type exists in the specified assembly, and that the assembly is available to the linker. -#### `IL2037`: Unresolved member 'memberSignature' in DynamicDependencyAttribute on 'member' +### `IL2037`: No members were resolved for 'memberSignature/memberTypes' in DynamicDependencyAttribute on 'member' -- The member signature in a DynamicDependencyAttribute constructor could not be resolved. Ensure that it refers to an existing member, and that it uses the format defined at https://github.com/dotnet/csharplang/blob/master/spec/documentation-comments.md#id-string-format. - -#### `IL2038`: No members were resolved for for 'memberTypes' in DynamicDependencyAttribute on 'member' - -- The DynamicallyAccessedMemberTypes passed into the DynamicDependencyAttribute constructor did not match any members on the specified type. No members will be kept for this type. Ensure that you are using DynamicallyAccessedMemberTypes which exist for the type. +- The member signature or DynamicallyAccessedMemberTypes in a DynamicDependencyAttribute constructor did not resolve to any members on the type. If you using a signature, ensure that it refers to an existing member, and that it uses the format defined at https://github.com/dotnet/csharplang/blob/master/spec/documentation-comments.md#id-string-format. If using DynamicallyAccessedMemberTypes, ensure that the type contains members of the specified member types. diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index f4b399c6ad03..7567c18c02a2 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -549,7 +549,6 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo return; var dynamicDependencies = _context.Annotations.GetLinkerAttributes ((IMemberDefinition) provider); - Debug.Assert (dynamicDependencies != null); foreach (var dynamicDependency in dynamicDependencies) MarkDynamicDependency (dynamicDependency, (MemberReference) provider); @@ -558,7 +557,7 @@ void MarkCustomAttributes (ICustomAttributeProvider provider, in DependencyInfo protected virtual bool ProcessLinkerSpecialAttribute (CustomAttribute ca, ICustomAttributeProvider provider, in DependencyInfo reason) { var isPreserveDependency = IsUserDependencyMarker (ca.AttributeType); - var isDynamicDependency = LinkerAttributesInformation.IsAttribute (ca.AttributeType); + var isDynamicDependency = ca.AttributeType.IsTypeOf (); if (!((isPreserveDependency || isDynamicDependency) && provider is MemberReference mr)) return false; @@ -598,7 +597,7 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference TypeDefinition type; if (dynamicDependency.TypeName is string typeName) { - type = assembly.FindTypeByDocumentationSignature (typeName); + type = DocumentationSignatureParser.GetTypeByDocumentationSignature (assembly, typeName); if (type == null) { _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", @@ -625,10 +624,10 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference IEnumerable members; if (dynamicDependency.MemberSignature is string memberSignature) { - members = type.FindMembersByDocumentationSignature (memberSignature); + members = DocumentationSignatureParser.GetMembersByDocumentationSignature (type, memberSignature); if (!members.Any ()) { _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Unresolved member '{memberSignature}' in DynamicDependencyAttribute on '{context}'", + $"No members were resolved for '{memberSignature}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (member))); return; } @@ -638,7 +637,7 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (!members.Any ()) { _context.LogMessage (MessageContainer.CreateWarningMessage (_context, $"No members were resolved for '{memberTypes}' in DynamicDependencyAttribute on '{context}'", - 2038, MessageOrigin.TryGetOrigin (member))); + 2037, MessageOrigin.TryGetOrigin (member))); return; } } diff --git a/src/linker/Linker/AssemblyUtilities.cs b/src/linker/Linker/AssemblyUtilities.cs index e9442eeb844b..6aaa0a90e23b 100644 --- a/src/linker/Linker/AssemblyUtilities.cs +++ b/src/linker/Linker/AssemblyUtilities.cs @@ -40,16 +40,5 @@ public static TypeDefinition FindType (this AssemblyDefinition assembly, string var type = assembly.MainModule.GetType (fullName); return type?.Resolve (); } - - // Takes a documentation signature (not including the documentation member type prefix) and resolves it to a type - // in the assembly. - public static TypeDefinition FindTypeByDocumentationSignature (this AssemblyDefinition assembly, string signature) - { - int index = 0; - var results = new List (); - DocumentationSignatureParser.ParseSignaturePart (signature, ref index, assembly.MainModule, DocumentationSignatureParser.MemberType.Type, results); - Debug.Assert (results.Count <= 1); - return results.Count == 0 ? null : (TypeDefinition) results[0]; - } } } diff --git a/src/linker/Linker/DocumentationSignatureParser.cs b/src/linker/Linker/DocumentationSignatureParser.cs index ae16ae53ad7f..36a3027582a7 100644 --- a/src/linker/Linker/DocumentationSignatureParser.cs +++ b/src/linker/Linker/DocumentationSignatureParser.cs @@ -53,6 +53,28 @@ public static IEnumerable GetMembersForDocumentationSignature return results; } + // Takes a documentation signature (not including the documentation member type prefix) and resolves it to a type + // in the assembly. + public static TypeDefinition? GetTypeByDocumentationSignature (AssemblyDefinition assembly, string signature) + { + int index = 0; + var results = new List (); + DocumentationSignatureParser.ParseSignaturePart (signature, ref index, assembly.MainModule, DocumentationSignatureParser.MemberType.Type, results); + Debug.Assert (results.Count <= 1); + return results.Count == 0 ? null : (TypeDefinition) results[0]; + } + + // Takes a member signature (not including the declaring type) and returns the matching members on the type. + public static IEnumerable GetMembersByDocumentationSignature (TypeDefinition type, string signature) + { + int index = 0; + var results = new List (); + var nameBuilder = new StringBuilder (); + var (name, arity) = DocumentationSignatureParser.ParseTypeOrNamespaceName (signature, ref index, nameBuilder); + DocumentationSignatureParser.GetMatchingMembers (signature, ref index, type.Module, type, name, arity, DocumentationSignatureParser.MemberType.All, results); + return results; + } + static string GetSignaturePart (TypeReference type) { var builder = new StringBuilder (); diff --git a/src/linker/Linker/DynamicDependency.cs b/src/linker/Linker/DynamicDependency.cs index c0e0cbca18c4..4d478d6dde94 100644 --- a/src/linker/Linker/DynamicDependency.cs +++ b/src/linker/Linker/DynamicDependency.cs @@ -64,7 +64,7 @@ public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, string typ return null; var member = provider as IMemberDefinition; - if (!DynamicDependency.ShouldProcess (context, customAttribute)) + if (!ShouldProcess (context, customAttribute)) return null; var dynamicDependency = GetDynamicDependency (context, customAttribute); @@ -90,7 +90,7 @@ public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, string typ DynamicallyAccessedMemberTypes? memberTypes = null; if (memberSignature == null) { var argType = args[0].Type; - if (!(argType.Namespace == "System.Diagnostics.CodeAnalysis" && argType.Name == "DynamicallyAccessedMemberTypes")) + if (!argType.IsTypeOf ()) return null; try { memberTypes = (DynamicallyAccessedMemberTypes) args[0].Value; diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index 67ec96014f95..1ca5a54a8338 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -23,9 +23,9 @@ public LinkerAttributesInformation (LinkContext context, ICustomAttributeProvide foreach (var customAttribute in provider.CustomAttributes) { var attributeType = customAttribute.AttributeType; Attribute attributeValue = null; - if (IsAttribute (attributeType)) + if (attributeType.IsTypeOf ()) attributeValue = ProcessRequiresUnreferencedCodeAttribute (context, provider, customAttribute); - else if (IsAttribute (attributeType)) + else if (attributeType.IsTypeOf ()) attributeValue = DynamicDependency.ProcessAttribute (context, provider, customAttribute); AddAttribute (ref _linkerAttributes, attributeValue); } @@ -66,12 +66,6 @@ public IEnumerable GetAttributes () where T : Attribute return attributeList.Cast (); } - public static bool IsAttribute (TypeReference tr) where T : Attribute - { - var type = typeof (T); - return tr.Name == type.Name && tr.Namespace == tr.Namespace; - } - static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, ICustomAttributeProvider provider, CustomAttribute customAttribute) { if (!(provider is MethodDefinition method)) diff --git a/src/linker/Linker/TypeDefinitionExtensions.cs b/src/linker/Linker/TypeDefinitionExtensions.cs index 5caed0bc594b..75539251fa72 100644 --- a/src/linker/Linker/TypeDefinitionExtensions.cs +++ b/src/linker/Linker/TypeDefinitionExtensions.cs @@ -43,16 +43,5 @@ public static bool IsSerializable (this TypeDefinition td) { return (td.Attributes & TypeAttributes.Serializable) != 0; } - - // Takes a member signature (not including the declaring type) and returns the matching members on the type. - public static IEnumerable FindMembersByDocumentationSignature (this TypeDefinition type, string signature) - { - int index = 0; - var results = new List (); - var nameBuilder = new StringBuilder (); - var (name, arity) = DocumentationSignatureParser.ParseTypeOrNamespaceName (signature, ref index, nameBuilder); - DocumentationSignatureParser.GetMatchingMembers (signature, ref index, type.Module, type, name, arity, DocumentationSignatureParser.MemberType.All, results); - return results; - } } } \ No newline at end of file diff --git a/src/linker/Linker/TypeReferenceExtensions.cs b/src/linker/Linker/TypeReferenceExtensions.cs index 8498d788969d..d6dab7873f50 100644 --- a/src/linker/Linker/TypeReferenceExtensions.cs +++ b/src/linker/Linker/TypeReferenceExtensions.cs @@ -259,5 +259,11 @@ public static bool IsTypeOf (this TypeReference type, string ns, string name) return type.Name == name && type.Namespace == ns; } + + public static bool IsTypeOf (this TypeReference tr) + { + var type = typeof (T); + return tr.Name == type.Name && tr.Namespace == tr.Namespace; + } } } From 448e665cf63b64a67d01c72c8290df3b295c7cdd Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 29 May 2020 19:19:23 +0000 Subject: [PATCH 15/21] Fix up tests --- .../DynamicDependencyMemberSignatureWildcard.cs | 2 +- .../DynamicDependencies/DynamicDependencyMethod.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs index 98e5ad250f52..677843e64610 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMemberSignatureWildcard.cs @@ -5,7 +5,7 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies { - [LogContains ("IL2073: Unresolved member '*' in DynamicDependencyAttribute")] + [LogContains ("IL2037: No members were resolved for '*' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMemberSignatureWildcard::Dependency()'")] [SetupCompileBefore ("library.dll", new[] { "Dependencies/DynamicDependencyMethodInAssemblyLibrary.cs" })] public class DynamicDependencyMemberSignatureWildcard { diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs index c70d71ede31f..863f02b00de3 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs @@ -5,10 +5,10 @@ namespace Mono.Linker.Tests.Cases.DynamicDependencies { - [LogContains ("IL2037: Unresolved member 'MissingMethod' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] - [LogContains ("IL2037: Unresolved member 'Dependency2``1(``0,System.Int32,System.Object)' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] - [LogContains ("IL2037: Unresolved member '#ctor()' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] - [LogContains ("IL2037: Unresolved member '#cctor()' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] + [LogContains ("IL2037: No members were resolved for 'MissingMethod' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] + [LogContains ("IL2037: No members were resolved for 'Dependency2``1(``0,System.Int32,System.Object)' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] + [LogContains ("IL2037: No members were resolved for '#ctor()' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] + [LogContains ("IL2037: No members were resolved for '#cctor()' in DynamicDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.DynamicDependencies.DynamicDependencyMethod/B::Broken()'")] class DynamicDependencyMethod { public static void Main () From 1136f0a2ce65c8436930bf4e422f8d9a2348c046 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Mon, 1 Jun 2020 22:52:06 +0000 Subject: [PATCH 16/21] Make PreserveDependency deprecated We will keep supporting it for now, and remove support for it once runtime has been converted to DynamicDependency --- docs/error-codes.md | 2 +- .../DynamicDependencyLookupStep.cs | 6 +-- src/linker/Linker.Steps/MarkStep.cs | 4 -- src/linker/Linker/DependencyInfo.cs | 2 - ...serveDependencyPreservesInterfaceMethod.cs | 3 -- ...ted.cs => PreserveDependencyDeprecated.cs} | 53 +++++++++++-------- .../PreserveDependencyField.cs | 3 -- .../PreserveDependencyFromCopiedAssembly.cs | 3 -- .../PreserveDependencyKeptOption.cs | 3 -- ...eserveDependencyMemberSignatureWildcard.cs | 3 -- .../PreserveDependencyMethod.cs | 4 -- .../PreserveDependencyMethodInAssembly.cs | 3 -- ...DependencyMethodInNonReferencedAssembly.cs | 3 -- ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 3 -- ...cyOnUnusedMethodInNonReferencedAssembly.cs | 3 -- ...NonReferencedAssemblyWithCopyUsedAction.cs | 3 -- ...dInNonReferencedAssemblyWithEmbeddedXml.cs | 3 -- .../WorksWithPreserveDependency.cs | 3 -- 18 files changed, 34 insertions(+), 73 deletions(-) rename test/Mono.Linker.Tests.Cases/PreserveDependencies/{PreserveDependencyMethodUnsupported.cs => PreserveDependencyDeprecated.cs} (58%) diff --git a/docs/error-codes.md b/docs/error-codes.md index bf6a68948432..b3d95dad80a3 100644 --- a/docs/error-codes.md +++ b/docs/error-codes.md @@ -187,7 +187,7 @@ error and warning codes. - 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. -#### `IL2033`: Unsupported PreserveDependencyAttribute on 'member'. Use DynamicDependencyAttribute instead. +#### `IL2033`: Deprecated PreserveDependencyAttribute on 'member'. Use DynamicDependencyAttribute instead. - PreserveDependencyAttribute was an internal attribute that was never officially supported. Instead, use the similar DynamicDependencyAttribute. diff --git a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs index 99c18c1dfcda..7c0d44f329e9 100644 --- a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs +++ b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs @@ -60,9 +60,9 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) continue; #if FEATURE_ILLINK Context.LogMessage (MessageContainer.CreateWarningMessage (Context, - $"Unsupported PreserveDependencyAttribute on '{member}'. Use DynamicDependencyAttribute instead.", + $"Deprecated PreserveDependencyAttribute on '{member}'. Use DynamicDependencyAttribute instead.", 2033, MessageOrigin.TryGetOrigin (member))); -#else +#endif if (ca.ConstructorArguments.Count != 3) continue; @@ -73,7 +73,6 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) if (assembly == null) continue; ProcessReferences (assembly); -#endif } var dynamicDependencies = Context.Annotations.GetLinkerAttributes (member); @@ -93,7 +92,6 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) ProcessReferences (assembly); } - } public static bool IsPreserveDependencyAttribute (TypeReference tr) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 7567c18c02a2..3152a2b5bf4c 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -562,10 +562,8 @@ protected virtual bool ProcessLinkerSpecialAttribute (CustomAttribute ca, ICusto if (!((isPreserveDependency || isDynamicDependency) && provider is MemberReference mr)) return false; -#if !FEATURE_ILLINK if (isPreserveDependency) MarkUserDependency (mr, ca); -#endif if (_context.KeepDependencyAttributes || Annotations.GetAction (mr.Module.Assembly) != AssemblyAction.Link) { MarkCustomAttribute (ca, reason); @@ -695,7 +693,6 @@ protected virtual bool IsUserDependencyMarker (TypeReference type) return DynamicDependencyLookupStep.IsPreserveDependencyAttribute (type); } -#if !FEATURE_ILLINK protected virtual void MarkUserDependency (MemberReference context, CustomAttribute ca) { if (!DynamicDependency.ShouldProcess (_context, ca)) @@ -814,7 +811,6 @@ bool MarkDependencyField (TypeDefinition type, string name, in DependencyInfo re return false; } -#endif // !FEATURE_ILLINK void LazyMarkCustomAttributes (ICustomAttributeProvider provider, ModuleDefinition module) { diff --git a/src/linker/Linker/DependencyInfo.cs b/src/linker/Linker/DependencyInfo.cs index 63a9be6f3b50..07db29568726 100644 --- a/src/linker/Linker/DependencyInfo.cs +++ b/src/linker/Linker/DependencyInfo.cs @@ -110,9 +110,7 @@ public enum DependencyKind // Linker-specific behavior (preservation hints, patterns, user inputs, linker outputs, etc.) DynamicDependency = 67, // DynamicDependency attribute -> member -#if !FEATURE_ILLINK PreservedDependency = 67, // PreserveDependency attribute -> member -#endif AccessedViaReflection = 68, // method -> detected member accessed via reflection from that method PreservedMethod = 69, // type/method -> preserved method (explicitly preserved in Annotations by XML or other steps) TypePreserve = 70, // type -> field/method preserved for the type (explicitly set in Annotations by XML or other steps) diff --git a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/PreserveDependencyPreservesInterfaceMethod.cs b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/PreserveDependencyPreservesInterfaceMethod.cs index 23872ac9aa92..db4a57a8401a 100644 --- a/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/PreserveDependencyPreservesInterfaceMethod.cs +++ b/test/Mono.Linker.Tests.Cases/Inheritance.Interfaces/OnReferenceType/NoKeptCtor/PreserveDependencyPreservesInterfaceMethod.cs @@ -7,9 +7,6 @@ namespace Mono.Linker.Tests.Cases.Inheritance.Interfaces.OnReferenceType.NoKeptC /// /// The interface can still be removed in this case because PreserveDependency is just preserving Foo() on the current type /// -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "../../../PreserveDependencies/Dependencies/PreserveDependencyAttribute.cs" })] public class PreserveDependencyPreservesInterfaceMethod { diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodUnsupported.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyDeprecated.cs similarity index 58% rename from test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodUnsupported.cs rename to test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyDeprecated.cs index d2668f364b1f..a5cbc2d99d91 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodUnsupported.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyDeprecated.cs @@ -4,16 +4,15 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { - #if !NETCOREAPP - [IgnoreTestCase ("This test checks that PreserveDependency correctly issues a warning on .NET Core where it is unsupported.")] + [IgnoreTestCase ("This test checks that PreserveDependency correctly issues a warning on .NET Core where it is deprecated.")] #endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] - [LogContains ("IL2029: Unsupported PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethodUnsupported/B::Method()'. Use DynamicDependencyAttribute instead.")] - [LogContains ("IL2029: Unsupported PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethodUnsupported/B::SameContext()'. Use DynamicDependencyAttribute instead.")] - [LogContains ("IL2029: Unsupported PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethodUnsupported/B::Broken()'. Use DynamicDependencyAttribute instead.")] - [LogContains ("IL2029: Unsupported PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethodUnsupported/B::Conditional()'. Use DynamicDependencyAttribute instead.")] - class PreserveDependencyMethodUnsupported + [LogContains ("IL2033: Deprecated PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated/B::Method()'. Use DynamicDependencyAttribute instead.")] + [LogContains ("IL2033: Deprecated PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated/B::SameContext()'. Use DynamicDependencyAttribute instead.")] + [LogContains ("IL2033: Deprecated PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated/B::Broken()'. Use DynamicDependencyAttribute instead.")] + [LogContains ("IL2033: Deprecated PreserveDependencyAttribute on 'System.Void Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated/B::Conditional()'. Use DynamicDependencyAttribute instead.")] + class PreserveDependencyDeprecated { public static void Main () { @@ -28,22 +27,24 @@ public static void Main () [KeptMember (".ctor()")] class B { + [Kept] int field; + [Kept] void Method2 (out sbyte arg) { arg = 1; } [Kept] - [PreserveDependency ("Dependency1()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] - [PreserveDependency ("Dependency2`1 ( T[] , System.Int32 ) ", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] - [PreserveDependency (".ctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] // To avoid lazy body marking stubbing - [PreserveDependency ("field", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] - [PreserveDependency ("NextOne (Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+Nested&)", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+Nested")] - [PreserveDependency (".cctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+Nested")] + [PreserveDependency ("Dependency1()", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] + [PreserveDependency ("Dependency2`1 ( T[] , System.Int32 ) ", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] + [PreserveDependency (".ctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] // To avoid lazy body marking stubbing + [PreserveDependency ("field", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] + [PreserveDependency ("NextOne (Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated+Nested&)", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated+Nested")] + [PreserveDependency (".cctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated+Nested")] // Dependency on a property itself should be expressed as a dependency on one or both accessor methods - [PreserveDependency ("get_Property()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + [PreserveDependency ("get_Property()", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] public static void Method () { } @@ -57,17 +58,17 @@ public static void SameContext () [Kept] [PreserveDependency ("MissingType", "Mono.Linker.Tests.Cases.PreserveDependencies.MissingType")] - [PreserveDependency ("MissingMethod", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] - [PreserveDependency ("Dependency2`1 (T, System.Int32, System.Object)", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + [PreserveDependency ("MissingMethod", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] + [PreserveDependency ("Dependency2`1 (T, System.Int32, System.Object)", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] [PreserveDependency ("")] - [PreserveDependency (".ctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyMethod+NestedStruct")] - [PreserveDependency (".cctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported")] + [PreserveDependency (".ctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.PreserveDependencyDeprecated+NestedStruct")] + [PreserveDependency (".cctor()", "Mono.Linker.Tests.Cases.PreserveDependencies.D")] public static void Broken () { } [Kept] - [PreserveDependency ("ConditionalTest()", "Mono.Linker.Tests.Cases.PreserveDependencies.CUnsupported", Condition = "don't have it")] + [PreserveDependency ("ConditionalTest()", "Mono.Linker.Tests.Cases.PreserveDependencies.D", Condition = "don't have it")] public static void Conditional () { } @@ -75,10 +76,12 @@ public static void Conditional () class Nested { + [Kept] private static void NextOne (ref Nested arg1) { } + [Kept] static Nested () { @@ -96,10 +99,13 @@ public NestedStruct (string name) } } - class CUnsupported + [KeptMember (".ctor()")] + class D { + [Kept] internal string field; + [Kept] internal void Dependency1 () { } @@ -108,14 +114,17 @@ internal void Dependency1 (long arg1) { } + [Kept] internal void Dependency2 (T[] arg1, int arg2) { } - internal string Property { get; set; } + [Kept] + [KeptBackingField] + internal string Property { [Kept] get; set; } internal void ConditionalTest () { } } -} \ No newline at end of file +} diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyField.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyField.cs index 6cba30a0c889..ea451e8121ae 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyField.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyField.cs @@ -4,9 +4,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] public class PreserveDependencyField { diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyFromCopiedAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyFromCopiedAssembly.cs index ad772bfb8a0d..78e896cd3990 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyFromCopiedAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyFromCopiedAssembly.cs @@ -4,9 +4,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupLinkerAction ("copy", "lib")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("lib.dll", new[] { "Dependencies/PreserveDependencyInCopyAssembly.cs" }, new[] { "FakeSystemAssembly.dll" })] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyKeptOption.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyKeptOption.cs index af9a41d886f0..cc46a7fb6413 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyKeptOption.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyKeptOption.cs @@ -4,9 +4,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupLinkerArgument ("--keep-dep-attributes", "true")] [KeptTypeInAssembly ("FakeSystemAssembly.dll", typeof (PreserveDependencyAttribute))] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMemberSignatureWildcard.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMemberSignatureWildcard.cs index 727e996f383c..61d9d4d768cf 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMemberSignatureWildcard.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMemberSignatureWildcard.cs @@ -4,9 +4,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies.PreserveDependencyMethodInAssemblyLibrary", ".ctor()")] [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies.PreserveDependencyMethodInAssemblyLibrary", "Foo()")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs index 9e139b58af9f..009802148f4f 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethod.cs @@ -4,10 +4,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { - -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [LogContains ("Could not resolve 'Mono.Linker.Tests.Cases.PreserveDependencies.MissingType' type dependency")] [LogContains ("Could not resolve dependency member 'MissingMethod' declared in type 'Mono.Linker.Tests.Cases.PreserveDependencies.C'")] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs index 8e74ea629298..8f5ca86d6721 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInAssembly.cs @@ -4,9 +4,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [KeptMemberInAssembly ("library.dll", "Mono.Linker.Tests.Cases.PreserveDependencies.Dependencies.PreserveDependencyMethodInAssemblyLibrary", ".ctor()")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyMethodInAssemblyLibrary.cs" })] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssembly.cs index a922c88343f3..a035815ea8e1 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssembly.cs @@ -5,9 +5,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("base.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyBase.cs" })] [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs index 5fe3521febd8..b27d68c0ba95 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -8,9 +8,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies /// /// This is an acceptable bug with the currently implementation. Embedded link xml files will not be processed /// -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [IgnoreDescriptors (false)] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("base.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyBase.cs" })] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssembly.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssembly.cs index 1824af98edea..3c74c120c437 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssembly.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssembly.cs @@ -5,9 +5,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("base.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyBase.cs" })] [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyLibrary.cs" }, references: new[] { "base.dll" }, addAsReference: false)] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs index 09b294013a51..f29043cb2a61 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction.cs @@ -4,9 +4,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupLinkerUserAction ("copyused")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("library.dll", new[] { "Dependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithCopyUsedAction_Lib.cs" }, addAsReference: false)] diff --git a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs index 83317c767e1f..010f200b8865 100644 --- a/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs +++ b/test/Mono.Linker.Tests.Cases/PreserveDependencies/PreserveDependencyOnUnusedMethodInNonReferencedAssemblyWithEmbeddedXml.cs @@ -8,9 +8,6 @@ namespace Mono.Linker.Tests.Cases.PreserveDependencies /// /// This test is here to ensure that link xml embedded in an assembly used by a [PreserveDependency] is not processed if the dependency is not used /// -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [IgnoreDescriptors (false)] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "Dependencies/PreserveDependencyAttribute.cs" })] [SetupCompileBefore ("base.dll", new[] { "Dependencies/PreserveDependencyMethodInNonReferencedAssemblyBase.cs" })] diff --git a/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs index 28c544fa0f65..5f4cad1d26bd 100644 --- a/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs +++ b/test/Mono.Linker.Tests.Cases/UnreachableBody/WorksWithPreserveDependency.cs @@ -4,9 +4,6 @@ namespace Mono.Linker.Tests.Cases.UnreachableBody { -#if NETCOREAPP - [IgnoreTestCase ("PreserveDependencyAttribute is not supported on .NET Core")] -#endif [SetupLinkerArgument ("--enable-opt", "unreachablebodies")] [SetupCompileBefore ("FakeSystemAssembly.dll", new[] { "../PreserveDependencies/Dependencies/PreserveDependencyAttribute.cs" })] public class WorksWithPreserveDependency From c287d2a84c10cb2b10d36810c4704fedafdda981 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 5 Jun 2020 17:38:05 +0000 Subject: [PATCH 17/21] PR feedback - Remove left-over dead code, imports - Fix typos - Don't respect Condition on DynamicDependencyAttribute --- src/linker/Linker.Steps/MarkStep.cs | 6 +- src/linker/Linker/AssemblyUtilities.cs | 2 - src/linker/Linker/DynamicDependency.cs | 10 ++- .../Linker/LinkerAttributesInformation.cs | 82 ------------------- src/linker/Linker/TypeDefinitionExtensions.cs | 2 - .../DynamicDependencyAttribute.cs | 2 +- .../DynamicDependencyMethod.cs | 2 + 7 files changed, 13 insertions(+), 93 deletions(-) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 3152a2b5bf4c..f90b67e21574 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -580,11 +580,11 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference Debug.Assert (context is MethodDefinition || context is FieldDefinition); var member = context as IMemberDefinition; AssemblyDefinition assembly; - if (dynamicDependency.AssemblyName is string assemblyName) { - assembly = _context.GetLoadedAssembly (assemblyName); + if (dynamicDependency.AssemblyName != null) { + assembly = _context.GetLoadedAssembly (dynamicDependency.AssemblyName); if (assembly == null) { _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Unresolved assembly '{assemblyName}' in DynamicDependencyAttribute on '{context}'", + $"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{context}'", 2035, MessageOrigin.TryGetOrigin (member))); return; } diff --git a/src/linker/Linker/AssemblyUtilities.cs b/src/linker/Linker/AssemblyUtilities.cs index 6aaa0a90e23b..9eda057e92a9 100644 --- a/src/linker/Linker/AssemblyUtilities.cs +++ b/src/linker/Linker/AssemblyUtilities.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Diagnostics; using Mono.Cecil; namespace Mono.Linker diff --git a/src/linker/Linker/DynamicDependency.cs b/src/linker/Linker/DynamicDependency.cs index 4d478d6dde94..28491f3c1fdf 100644 --- a/src/linker/Linker/DynamicDependency.cs +++ b/src/linker/Linker/DynamicDependency.cs @@ -60,13 +60,17 @@ public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, string typ public static DynamicDependency? ProcessAttribute (LinkContext context, ICustomAttributeProvider provider, CustomAttribute customAttribute) { - if (!(provider is MethodDefinition || provider is FieldDefinition)) + if (!(provider is IMemberDefinition member)) return null; - var member = provider as IMemberDefinition; - if (!ShouldProcess (context, customAttribute)) + if (!(member is MethodDefinition || member is FieldDefinition)) return null; + // Don't honor the Condition until we have figured out the behavior for DynamicDependencyAttribute: + // https://github.com/mono/linker/issues/1231 + // if (!ShouldProcess (context, customAttribute)) + // return null; + var dynamicDependency = GetDynamicDependency (context, customAttribute); if (dynamicDependency != null) return dynamicDependency; diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index 1ca5a54a8338..51579d735fe1 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -87,87 +87,5 @@ static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, 2028, MessageOrigin.TryGetOrigin (method, 0)); return null; } - - static DynamicDependency ProcessDynamicDependencyAttribute (LinkContext context, ICustomAttributeProvider provider, CustomAttribute customAttribute) - { - if (!(provider is MethodDefinition || provider is FieldDefinition)) - return null; - var member = provider as IMemberDefinition; - - if (!ShouldProcessDependencyAttribute (context, customAttribute)) - return null; - - var dynamicDependency = GetDynamicDependency (context, customAttribute); - if (dynamicDependency != null) - return dynamicDependency; - - context.LogMessage (MessageContainer.CreateWarningMessage (context, - $"Invalid DynamicDependencyAttribute on '{member}'", - 2034, MessageOrigin.TryGetOrigin (member))); - return null; - } - - static DynamicDependency GetDynamicDependency (LinkContext context, CustomAttribute ca) - { - var args = ca.ConstructorArguments; - if (args.Count > 3) - return null; - - // First argument is string or DynamicallyAccessedMemberTypes - string memberSignature = args[0].Value as string; - if (args.Count == 1) - return memberSignature == null ? null : new DynamicDependency (memberSignature); - DynamicallyAccessedMemberTypes? memberTypes = null; - if (memberSignature == null) { - var argType = args[0].Type; - if (!(argType.Namespace == "System.Diagnostics.CodeAnalysis" && argType.Name == "DynamicallyAccessedMemberTypes")) - return null; - try { - memberTypes = (DynamicallyAccessedMemberTypes) args[0].Value; - } catch (InvalidCastException) { } - if (memberTypes == null) - return null; - } - - // Second argument is Type for ctors with two args, string for ctors with three args - if (args.Count == 2) { - if (!(args[1].Value is TypeReference type)) - return null; - return memberSignature == null ? new DynamicDependency (memberTypes.Value, type) : new DynamicDependency (memberSignature, type); - } - Debug.Assert (args.Count == 3); - if (!(args[1].Value is string typeName)) - return null; - - // Third argument is assembly name - if (!(args[2].Value is string assemblyName)) - return null; - - var dynamicDependency = memberSignature == null ? new DynamicDependency (memberTypes.Value, typeName, assemblyName) : new DynamicDependency (memberSignature, typeName, assemblyName); - dynamicDependency.OriginalAttribute = ca; - - return dynamicDependency; - } - - public static bool ShouldProcessDependencyAttribute (LinkContext context, CustomAttribute ca) - { - if (ca.HasProperties && ca.Properties[0].Name == "Condition") { - var condition = ca.Properties[0].Argument.Value as string; - switch (condition) { - case "": - case null: - return true; - case "DEBUG": - if (!context.KeepMembersForDebugger) - return false; - - break; - default: - // Don't have yet a way to match the general condition so everything is excluded - return false; - } - } - return true; - } } } diff --git a/src/linker/Linker/TypeDefinitionExtensions.cs b/src/linker/Linker/TypeDefinitionExtensions.cs index 75539251fa72..d33b37013b1e 100644 --- a/src/linker/Linker/TypeDefinitionExtensions.cs +++ b/src/linker/Linker/TypeDefinitionExtensions.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using Mono.Cecil; namespace Mono.Linker diff --git a/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs b/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs index f7d594ef2a17..b029c6cc949e 100644 --- a/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs +++ b/src/linker/System.Diagnostics.CodeAnalysis/DynamicDependencyAttribute.cs @@ -6,7 +6,7 @@ namespace System.Diagnostics.CodeAnalysis { - /// This is a n internal version of copy of the attribute in the framework at https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs + /// This is an internal version of the attribute in the framework at https://github.com/dotnet/runtime/blob/master/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/DynamicDependencyAttribute.cs /// We currently only use the type as a generic parameter, so the implementation isn't copied. internal sealed class DynamicDependencyAttribute : Attribute { diff --git a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs index 863f02b00de3..9a1085fd3a89 100644 --- a/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs +++ b/test/Mono.Linker.Tests.Cases/DynamicDependencies/DynamicDependencyMethod.cs @@ -138,6 +138,8 @@ internal void Dependency2 (T[] arg1, int arg2) [KeptBackingField] internal string Property { [Kept] get; set; } + // For now, Condition has no effect: https://github.com/mono/linker/issues/1231 + [Kept] internal void ConditionalTest () { } From 82eca9c6b0e73623c2420cbf8571520d2843b2c7 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 5 Jun 2020 18:39:22 +0000 Subject: [PATCH 18/21] Use new logging helpers --- .../DynamicDependencyLookupStep.cs | 8 ++---- src/linker/Linker.Steps/MarkStep.cs | 28 ++++++------------- src/linker/Linker/Annotations.cs | 4 +-- .../Linker/LinkerAttributesInformation.cs | 2 +- src/linker/Linker/MessageOrigin.cs | 6 ++-- 5 files changed, 15 insertions(+), 33 deletions(-) diff --git a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs index 7c0d44f329e9..1fc37225aa91 100644 --- a/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs +++ b/src/linker/Linker.Steps/DynamicDependencyLookupStep.cs @@ -59,9 +59,7 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) if (!IsPreserveDependencyAttribute (ca.AttributeType)) continue; #if FEATURE_ILLINK - Context.LogMessage (MessageContainer.CreateWarningMessage (Context, - $"Deprecated PreserveDependencyAttribute on '{member}'. Use DynamicDependencyAttribute instead.", - 2033, MessageOrigin.TryGetOrigin (member))); + Context.LogWarning ($"Deprecated PreserveDependencyAttribute on '{member}'. Use DynamicDependencyAttribute instead.", 2033, MessageOrigin.TryGetOrigin (member)); #endif if (ca.ConstructorArguments.Count != 3) continue; @@ -84,9 +82,7 @@ void ProcessDynamicDependencyAttributes (IMemberDefinition member) var assembly = Context.Resolve (new AssemblyNameReference (dynamicDependency.AssemblyName, new Version ())); if (assembly == null) { - Context.LogMessage (MessageContainer.CreateWarningMessage (Context, - $"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{member}'", - 2035, MessageOrigin.TryGetOrigin (member))); + Context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{member}'", 2035, MessageOrigin.TryGetOrigin (member)); continue; } diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index f90b67e21574..563346c5a174 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -378,7 +378,7 @@ void ProcessQueue () } catch (Exception e) when (!(e is LinkerFatalErrorException)) { throw new LinkerFatalErrorException ( MessageContainer.CreateErrorMessage ($"Error processing method '{method.FullName}' in assembly '{method.Module.Name}'", 1005, - origin: MessageOrigin.TryGetOrigin (method, 0)), e); + origin: MessageOrigin.TryGetOrigin (method)), e); } } } @@ -583,9 +583,7 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (dynamicDependency.AssemblyName != null) { assembly = _context.GetLoadedAssembly (dynamicDependency.AssemblyName); if (assembly == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{context}'", - 2035, MessageOrigin.TryGetOrigin (member))); + _context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{context}'", 2035, MessageOrigin.TryGetOrigin (member)); return; } } else { @@ -597,25 +595,19 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (dynamicDependency.TypeName is string typeName) { type = DocumentationSignatureParser.GetTypeByDocumentationSignature (assembly, typeName); if (type == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", - 2036, MessageOrigin.TryGetOrigin (member))); + _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (member)); return; } } else if (dynamicDependency.Type is TypeReference typeReference) { type = typeReference.Resolve (); if (type == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Unresolved type '{typeReference}' in DynamicDependencyAtribute on '{context}'", - 2036, MessageOrigin.TryGetOrigin (member))); + _context.LogWarning ($"Unresolved type '{typeReference}' in DynamicDependencyAtribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (member)); return; } } else { type = context.DeclaringType.Resolve (); if (type == null) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute on '{context}'", - 2036, MessageOrigin.TryGetOrigin (member))); + _context.LogWarning ($"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (member)); return; } } @@ -624,18 +616,14 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (dynamicDependency.MemberSignature is string memberSignature) { members = DocumentationSignatureParser.GetMembersByDocumentationSignature (type, memberSignature); if (!members.Any ()) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"No members were resolved for '{memberSignature}' in DynamicDependencyAttribute on '{context}'", - 2037, MessageOrigin.TryGetOrigin (member))); + _context.LogWarning ($"No members were resolved for '{memberSignature}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (member)); return; } } else { var memberTypes = dynamicDependency.MemberTypes; members = DynamicallyAccessedMembersBinder.GetDynamicallyAccessedMembers (type, memberTypes); if (!members.Any ()) { - _context.LogMessage (MessageContainer.CreateWarningMessage (_context, - $"No members were resolved for '{memberTypes}' in DynamicDependencyAttribute on '{context}'", - 2037, MessageOrigin.TryGetOrigin (member))); + _context.LogWarning ($"No members were resolved for '{memberTypes}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (member)); return; } } @@ -2389,7 +2377,7 @@ void MarkNewCodeDependencies (MethodDefinition method) var baseType = method.DeclaringType.BaseType.Resolve (); if (!MarkDefaultConstructor (baseType, new DependencyInfo (DependencyKind.BaseDefaultCtorForStubbedMethod, method))) throw new LinkerFatalErrorException (MessageContainer.CreateErrorMessage ($"Cannot stub constructor on '{method.DeclaringType}' when base type does not have default constructor", - 1006, origin: MessageOrigin.TryGetOrigin (method, 0))); + 1006, origin: MessageOrigin.TryGetOrigin (method))); break; diff --git a/src/linker/Linker/Annotations.cs b/src/linker/Linker/Annotations.cs index f1ab366be4e0..63d948878a0b 100644 --- a/src/linker/Linker/Annotations.cs +++ b/src/linker/Linker/Annotations.cs @@ -460,9 +460,7 @@ public bool TryGetLinkerAttribute (IMemberDefinition member, out T attribute) { var attributes = GetLinkerAttributes (member); if (attributes.Count () > 1) { - context.LogMessage (MessageContainer.CreateWarningMessage (context, - $"Attribute '{typeof (T).FullName}' should only be used once on '{member}'.", - 2027, MessageOrigin.TryGetOrigin (member, 0))); + context.LogWarning ($"Attribute '{typeof (T).FullName}' should only be used once on '{member}'.", 2027, MessageOrigin.TryGetOrigin (member)); } Debug.Assert (attributes.Count () <= 1); diff --git a/src/linker/Linker/LinkerAttributesInformation.cs b/src/linker/Linker/LinkerAttributesInformation.cs index 51579d735fe1..3f4f562a1871 100644 --- a/src/linker/Linker/LinkerAttributesInformation.cs +++ b/src/linker/Linker/LinkerAttributesInformation.cs @@ -84,7 +84,7 @@ static Attribute ProcessRequiresUnreferencedCodeAttribute (LinkContext context, } context.LogWarning ($"Attribute '{typeof (RequiresUnreferencedCodeAttribute).FullName}' on '{method}' doesn't have a required constructor argument.", - 2028, MessageOrigin.TryGetOrigin (method, 0)); + 2028, MessageOrigin.TryGetOrigin (method)); return null; } } diff --git a/src/linker/Linker/MessageOrigin.cs b/src/linker/Linker/MessageOrigin.cs index 10f0e446971c..76a17c4f37bc 100644 --- a/src/linker/Linker/MessageOrigin.cs +++ b/src/linker/Linker/MessageOrigin.cs @@ -26,12 +26,12 @@ public MessageOrigin (string fileName, int sourceLine = 0, int sourceColumn = 0) MemberDefinition = null; } - public MessageOrigin (IMemberDefinition memberDefinition, int sourceLine = 0, int sourceColumn = 0) + public MessageOrigin (IMemberDefinition memberDefinition) { FileName = null; MemberDefinition = memberDefinition; - SourceLine = sourceLine; - SourceColumn = sourceColumn; + SourceLine = 0; + SourceColumn = 0; } private MessageOrigin (string fileName, IMemberDefinition memberDefinition, int sourceLine = 0, int sourceColumn = 0) From ce02105d88c0610d524cd79c38db2bef07b3c542 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 5 Jun 2020 21:17:43 +0000 Subject: [PATCH 19/21] More PR feedback --- src/linker/Linker.Steps/MarkStep.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index 563346c5a174..da9c39a1bb52 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -578,12 +578,11 @@ protected virtual bool ProcessLinkerSpecialAttribute (CustomAttribute ca, ICusto void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference context) { Debug.Assert (context is MethodDefinition || context is FieldDefinition); - var member = context as IMemberDefinition; AssemblyDefinition assembly; if (dynamicDependency.AssemblyName != null) { assembly = _context.GetLoadedAssembly (dynamicDependency.AssemblyName); if (assembly == null) { - _context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{context}'", 2035, MessageOrigin.TryGetOrigin (member)); + _context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{context}'", 2035, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); return; } } else { @@ -595,19 +594,19 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (dynamicDependency.TypeName is string typeName) { type = DocumentationSignatureParser.GetTypeByDocumentationSignature (assembly, typeName); if (type == null) { - _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (member)); + _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); return; } } else if (dynamicDependency.Type is TypeReference typeReference) { type = typeReference.Resolve (); if (type == null) { - _context.LogWarning ($"Unresolved type '{typeReference}' in DynamicDependencyAtribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (member)); + _context.LogWarning ($"Unresolved type '{typeReference}' in DynamicDependencyAtribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); return; } } else { type = context.DeclaringType.Resolve (); if (type == null) { - _context.LogWarning ($"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (member)); + _context.LogWarning ($"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); return; } } @@ -616,14 +615,14 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (dynamicDependency.MemberSignature is string memberSignature) { members = DocumentationSignatureParser.GetMembersByDocumentationSignature (type, memberSignature); if (!members.Any ()) { - _context.LogWarning ($"No members were resolved for '{memberSignature}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (member)); + _context.LogWarning ($"No members were resolved for '{memberSignature}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); return; } } else { var memberTypes = dynamicDependency.MemberTypes; members = DynamicallyAccessedMembersBinder.GetDynamicallyAccessedMembers (type, memberTypes); if (!members.Any ()) { - _context.LogWarning ($"No members were resolved for '{memberTypes}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (member)); + _context.LogWarning ($"No members were resolved for '{memberTypes}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); return; } } From 291ec0c962059d12285a657b45ca03ca9d1c6425 Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 5 Jun 2020 21:27:53 +0000 Subject: [PATCH 20/21] Use Resolve () instead --- src/linker/Linker.Steps/MarkStep.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index da9c39a1bb52..79571bfa1464 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -582,7 +582,7 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (dynamicDependency.AssemblyName != null) { assembly = _context.GetLoadedAssembly (dynamicDependency.AssemblyName); if (assembly == null) { - _context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{context}'", 2035, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); + _context.LogWarning ($"Unresolved assembly '{dynamicDependency.AssemblyName}' in DynamicDependencyAttribute on '{context}'", 2035, MessageOrigin.TryGetOrigin (context.Resolve ())); return; } } else { @@ -594,19 +594,19 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (dynamicDependency.TypeName is string typeName) { type = DocumentationSignatureParser.GetTypeByDocumentationSignature (assembly, typeName); if (type == null) { - _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); + _context.LogWarning ($"Unresolved type '{typeName}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context.Resolve ())); return; } } else if (dynamicDependency.Type is TypeReference typeReference) { type = typeReference.Resolve (); if (type == null) { - _context.LogWarning ($"Unresolved type '{typeReference}' in DynamicDependencyAtribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); + _context.LogWarning ($"Unresolved type '{typeReference}' in DynamicDependencyAtribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context.Resolve ())); return; } } else { type = context.DeclaringType.Resolve (); if (type == null) { - _context.LogWarning ($"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); + _context.LogWarning ($"Unresolved type '{context.DeclaringType}' in DynamicDependencyAttribute on '{context}'", 2036, MessageOrigin.TryGetOrigin (context.Resolve ())); return; } } @@ -615,14 +615,14 @@ void MarkDynamicDependency (DynamicDependency dynamicDependency, MemberReference if (dynamicDependency.MemberSignature is string memberSignature) { members = DocumentationSignatureParser.GetMembersByDocumentationSignature (type, memberSignature); if (!members.Any ()) { - _context.LogWarning ($"No members were resolved for '{memberSignature}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); + _context.LogWarning ($"No members were resolved for '{memberSignature}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (context.Resolve ())); return; } } else { var memberTypes = dynamicDependency.MemberTypes; members = DynamicallyAccessedMembersBinder.GetDynamicallyAccessedMembers (type, memberTypes); if (!members.Any ()) { - _context.LogWarning ($"No members were resolved for '{memberTypes}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (context as IMemberDefinition)); + _context.LogWarning ($"No members were resolved for '{memberTypes}' in DynamicDependencyAttribute on '{context}'", 2037, MessageOrigin.TryGetOrigin (context.Resolve ())); return; } } From ddf6b6dd154e946c29731ed0a7ce4264094a8d4d Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Fri, 5 Jun 2020 21:50:00 +0000 Subject: [PATCH 21/21] Update one more logging callsite --- src/linker/Linker/DynamicDependency.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/linker/Linker/DynamicDependency.cs b/src/linker/Linker/DynamicDependency.cs index 28491f3c1fdf..5f683d25ab31 100644 --- a/src/linker/Linker/DynamicDependency.cs +++ b/src/linker/Linker/DynamicDependency.cs @@ -75,9 +75,7 @@ public DynamicDependency (DynamicallyAccessedMemberTypes memberTypes, string typ if (dynamicDependency != null) return dynamicDependency; - context.LogMessage (MessageContainer.CreateWarningMessage (context, - $"Invalid DynamicDependencyAttribute on '{member}'", - 2030, MessageOrigin.TryGetOrigin (member))); + context.LogWarning ($"Invalid DynamicDependencyAttribute on '{member}'", 2030, MessageOrigin.TryGetOrigin (member)); return null; }