// Copyright 2011-2013 Xamarin Inc. All rights reserved. using System; using System.Collections.Generic; using Mono.Cecil; using Mono.Linker; using Mono.Tuner; using Xamarin.Tuner; namespace Xamarin.Linker.Steps { public class MobileApplyPreserveAttribute : ApplyPreserveAttribute { bool is_sdk; DerivedLinkContext LinkContext { get { return (DerivedLinkContext) base.context; } } // System.ServiceModel.dll is an SDK assembly but it does contain types with [DataMember] attributes // just like System.Xml.dll contais [Xml*] attributes - we do not want to keep them unless the application // shows the feature is being used public override bool IsActiveFor (AssemblyDefinition assembly) { is_sdk = Profile.IsSdkAssembly (assembly); return base.IsActiveFor (assembly); } protected override bool IsPreservedAttribute (ICustomAttributeProvider provider, CustomAttribute attribute, out bool removeAttribute) { removeAttribute = false; TypeReference type = attribute.Constructor.DeclaringType; switch (type.Namespace) { case "System.Runtime.Serialization": bool srs = false; // http://bugzilla.xamarin.com/show_bug.cgi?id=1415 // http://msdn.microsoft.com/en-us/library/system.runtime.serialization.datamemberattribute.aspx if (provider is PropertyDefinition || provider is FieldDefinition || provider is EventDefinition) srs = (type.Name == "DataMemberAttribute"); else if (provider is TypeDefinition) srs = (type.Name == "DataContractAttribute"); if (srs) { MarkDefaultConstructor (provider, is_sdk ? LinkContext.DataContract : null); return !is_sdk; } break; case "System.Xml.Serialization": // http://msdn.microsoft.com/en-us/library/83y7df3e.aspx string name = type.Name; if ((name.StartsWith ("Xml", StringComparison.Ordinal) && name.EndsWith ("Attribute", StringComparison.Ordinal))) { // but we do not have to keep things that XML serialization will ignore anyway! if (name != "XmlIgnoreAttribute") { // the default constructor of the type *being used* is needed MarkDefaultConstructor (provider, is_sdk ? LinkContext.XmlSerialization : null); return !is_sdk; } } break; default: return base.IsPreservedAttribute (provider, attribute, out removeAttribute); } // keep them (provider and attribute) return false; } // xml serialization requires the default .ctor to be present void MarkDefaultConstructor (ICustomAttributeProvider provider, IList list) { if (list != null) { list.Add (provider); return; } TypeDefinition td = (provider as TypeDefinition); if (td == null) { PropertyDefinition pd = (provider as PropertyDefinition); if (pd != null) { MarkDefaultConstructor (pd.DeclaringType); MarkGenericType (pd.PropertyType as GenericInstanceType); td = pd.PropertyType.Resolve (); } else { FieldDefinition fd = (provider as FieldDefinition); if (fd != null) { MarkDefaultConstructor (fd.DeclaringType); MarkGenericType (fd.FieldType as GenericInstanceType); td = (fd.FieldType as TypeReference).Resolve (); } } } // e.g. property (see bug #5543) or field (see linkall unit tests) if (td != null) MarkDefaultConstructor (td); } void MarkGenericType (GenericInstanceType git) { if (git == null || !git.HasGenericArguments) return; foreach (TypeReference tr in git.GenericArguments) MarkDefaultConstructor (tr.Resolve ()); } void MarkDefaultConstructor (TypeDefinition type) { if ((type == null) || !type.HasMethods) return; foreach (MethodDefinition ctor in type.Methods) { if (!ctor.IsConstructor || ctor.IsStatic || ctor.HasParameters) continue; Annotations.AddPreservedMethod (type, ctor); } } } }