diff --git a/tools/dotnet-linker/ApplyPreserveAttributeBase.cs b/tools/dotnet-linker/ApplyPreserveAttributeBase.cs index 33ecb654bf15..22875192d13d 100644 --- a/tools/dotnet-linker/ApplyPreserveAttributeBase.cs +++ b/tools/dotnet-linker/ApplyPreserveAttributeBase.cs @@ -24,6 +24,7 @@ namespace Mono.Tuner { public abstract class ApplyPreserveAttributeBase : ConfigurationAwareSubStep { AppBundleRewriter? abr; + Queue deferredActions = new (); protected override string Name { get => "Apply Preserve Attribute"; } @@ -32,16 +33,7 @@ public abstract class ApplyPreserveAttributeBase : ConfigurationAwareSubStep { // set 'removeAttribute' to true if you want the preserved attribute to be removed from the final assembly protected abstract bool IsPreservedAttribute (ICustomAttributeProvider provider, CustomAttribute attribute, out bool removeAttribute); - public override SubStepTargets Targets { - get { - return SubStepTargets.Type - | SubStepTargets.Field - | SubStepTargets.Method - | SubStepTargets.Property - | SubStepTargets.Event - | SubStepTargets.Assembly; - } - } + public override SubStepTargets Targets => SubStepTargets.Assembly; public override void Initialize (LinkContext context) { @@ -51,6 +43,51 @@ public override void Initialize (LinkContext context) abr = Configuration.AppBundleRewriter; } + protected override void Process (AssemblyDefinition assembly) + { + BrowseTypes (assembly.MainModule.Types); + ProcessDeferredActions (); + } + + void BrowseTypes (IEnumerable types) + { + foreach (TypeDefinition type in types) { + ProcessType (type); + + if (type.HasFields) { + foreach (FieldDefinition field in type.Fields) + ProcessField (field); + } + + if (type.HasMethods) { + foreach (MethodDefinition method in type.Methods) + ProcessMethod (method); + } + + if (type.HasProperties) { + foreach (PropertyDefinition property in type.Properties) + ProcessProperty (property); + } + + if (type.HasEvents) { + foreach (EventDefinition @event in type.Events) + ProcessEvent (@event); + } + + if (type.HasNestedTypes) { + BrowseTypes (type.NestedTypes); + } + } + } + + void ProcessDeferredActions () + { + while (deferredActions.Count > 0) { + var action = deferredActions.Dequeue (); + action.Invoke (); + } + } + public override bool IsActiveFor (AssemblyDefinition assembly) { return Annotations.GetAction (assembly) == AssemblyAction.Link; @@ -205,13 +242,7 @@ protected void PreserveType (TypeDefinition type, bool allMembers) MethodDefinition GetOrCreateModuleConstructor (ModuleDefinition @module) { var moduleType = @module.GetModuleType (); - var moduleConstructor = moduleType.GetTypeConstructor (); - if (moduleConstructor is null) { - moduleConstructor = moduleType.AddMethod (".cctor", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.Static, abr!.System_Void); - moduleConstructor.CreateBody (out var il); - il.Emit (OpCodes.Ret); - } - return moduleConstructor; + return GetOrCreateStaticConstructor (moduleType); } void AddDynamicDependencyAttribute (TypeDefinition type, bool allMembers) @@ -234,8 +265,7 @@ void AddConditionalDynamicDependencyAttribute (TypeDefinition onType, MethodDefi if (abr is null) return; - // I haven't found a way to express a conditional Preserve attribute using DynamicDependencyAttribute :/ - ErrorHelper.Warning (2112, Errors.MX2112 /* Unable to apply the conditional [Preserve] attribute on the member {0} */, forMethod.FullName); + deferredActions.Enqueue (() => AddDynamicDependencyAttributeToStaticConstructor (onType, forMethod)); } void AddDynamicDependencyAttribute (IMetadataTokenProvider provider) @@ -258,5 +288,34 @@ void AddDynamicDependencyAttribute (IMetadataTokenProvider provider) abr.ClearCurrentAssembly (); } + + void AddDynamicDependencyAttributeToStaticConstructor (TypeDefinition onType, MethodDefinition forMethod) + { + if (abr is null) + return; + + abr.ClearCurrentAssembly (); + abr.SetCurrentAssembly (onType.Module.Assembly); + + var cctor = GetOrCreateStaticConstructor (onType); + var signature = DocumentationComments.GetSignature (forMethod); + var attrib = abr.CreateDynamicDependencyAttribute (signature, onType); + cctor.CustomAttributes.Add (attrib); + Annotations.AddPreservedMethod (onType, cctor); + + abr.ClearCurrentAssembly (); + } + + MethodDefinition GetOrCreateStaticConstructor (TypeDefinition type) + { + var staticCtor = type.GetTypeConstructor (); + if (staticCtor is null) { + staticCtor = type.AddMethod (".cctor", MethodAttributes.Private | MethodAttributes.HideBySig | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName | MethodAttributes.Static, abr!.System_Void); + staticCtor.CreateBody (out var il); + il.Emit (OpCodes.Ret); + } + + return staticCtor; + } } } diff --git a/tools/mtouch/Errors.designer.cs b/tools/mtouch/Errors.designer.cs index da2396bce752..7b37da29920e 100644 --- a/tools/mtouch/Errors.designer.cs +++ b/tools/mtouch/Errors.designer.cs @@ -4003,15 +4003,6 @@ public static string MX2111 { } } - /// - /// Looks up a localized string similar to Unable to apply the conditional [Preserve] attribute on the member {0}.. - /// - public static string MX2112 { - get { - return ResourceManager.GetString("MX2112", resourceCulture); - } - } - /// /// Looks up a localized string similar to Could not {0} the assembly '{1}' /// . diff --git a/tools/mtouch/Errors.resx b/tools/mtouch/Errors.resx index 4e121a254354..c555054df824 100644 --- a/tools/mtouch/Errors.resx +++ b/tools/mtouch/Errors.resx @@ -1346,11 +1346,6 @@ - - - Unable to apply the conditional [Preserve] attribute on the member {0}. - -