From d21bbefe55230c2cbf9ba4ade2bcd76aff36a1b2 Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Wed, 27 Jan 2016 12:56:23 +0100 Subject: [PATCH 1/1] [mono-api-info] Use XmlWriter instead of XmlDocument to make this faster. Generating all the API references (in parallel) for Xamarin.iOS goes from 5.5s to 4.5s. --- mcs/tools/corcompare/mono-api-info.cs | 530 ++++++++++++++------------ 1 file changed, 295 insertions(+), 235 deletions(-) diff --git a/mcs/tools/corcompare/mono-api-info.cs b/mcs/tools/corcompare/mono-api-info.cs index 0886d14b3bd..29cc3e58a6d 100644 --- a/mcs/tools/corcompare/mono-api-info.cs +++ b/mcs/tools/corcompare/mono-api-info.cs @@ -93,18 +93,20 @@ namespace CorCompare } } - XmlDocument doc = new XmlDocument (); - acoll.Document = doc; - acoll.DoOutput (); - - TextWriter outputStream = null; + StreamWriter outputStream = null; if (!string.IsNullOrEmpty (output)) outputStream = new StreamWriter (output); try { - var writer = new WellFormedXmlWriter (new XmlTextWriter (outputStream ?? Console.Out) { Formatting = Formatting.Indented }); - XmlNode decl = doc.CreateXmlDeclaration ("1.0", "utf-8", null); - doc.InsertBefore (decl, doc.DocumentElement); - doc.WriteTo (writer); + TextWriter outStream = outputStream ?? Console.Out; + var settings = new XmlWriterSettings (); + settings.Indent = true; + var textWriter = XmlWriter.Create (outStream, settings); + var writer = new WellFormedXmlWriter (textWriter); + writer.WriteStartDocument (); + acoll.Writer = writer; + acoll.DoOutput (); + writer.WriteEndDocument (); + writer.Flush (); } finally { if (outputStream != null) outputStream.Dispose (); @@ -131,7 +133,7 @@ namespace CorCompare class AssemblyCollection { - XmlDocument document; + XmlWriter writer; List assemblies = new List (); public AssemblyCollection () @@ -152,19 +154,19 @@ namespace CorCompare public void DoOutput () { - if (document == null) + if (writer == null) throw new InvalidOperationException ("Document not set"); - XmlNode nassemblies = document.CreateElement ("assemblies", null); - document.AppendChild (nassemblies); + writer.WriteStartElement ("assemblies"); foreach (AssemblyDefinition a in assemblies) { - AssemblyData data = new AssemblyData (document, nassemblies, a); + AssemblyData data = new AssemblyData (writer, a); data.DoOutput (); } + writer.WriteEndElement (); } - public XmlDocument Document { - set { document = value; } + public XmlWriter Writer { + set { writer = value; } } AssemblyDefinition LoadAssembly (string assembly) @@ -183,22 +185,18 @@ namespace CorCompare abstract class BaseData { - protected XmlDocument document; - protected XmlNode parent; + protected XmlWriter writer; - protected BaseData (XmlDocument doc, XmlNode parent) + protected BaseData (XmlWriter writer) { - this.document = doc; - this.parent = parent; + this.writer = writer; } public abstract void DoOutput (); - protected void AddAttribute (XmlNode node, string name, string value) + protected void AddAttribute (string name, string value) { - XmlAttribute attr = document.CreateAttribute (name); - attr.Value = value; - node.Attributes.Append (attr); + writer.WriteAttributeString (name, value); } } @@ -206,38 +204,34 @@ namespace CorCompare { AssemblyDefinition ass; - public TypeForwardedToData (XmlDocument document, XmlNode parent, AssemblyDefinition ass) - : base (document, parent) + public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass) + : base (writer) { this.ass = ass; } public override void DoOutput () { - XmlNode natts = parent.SelectSingleNode("attributes"); - if (natts == null) { - natts = document.CreateElement ("attributes", null); - parent.AppendChild (natts); - } - foreach (ExportedType type in ass.MainModule.ExportedTypes) { if (((uint)type.Attributes & 0x200000u) == 0) continue; - XmlNode node = document.CreateElement ("attribute"); - AddAttribute (node, "name", typeof (TypeForwardedToAttribute).FullName); - XmlNode properties = node.AppendChild (document.CreateElement ("properties")); - XmlNode property = properties.AppendChild (document.CreateElement ("property")); - AddAttribute (property, "name", "Destination"); - AddAttribute (property, "value", Utils.CleanupTypeName (type.FullName)); - natts.AppendChild (node); + writer.WriteStartElement ("attribute"); + AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName); + writer.WriteStartElement ("properties"); + writer.WriteStartElement ("property"); + AddAttribute ("name", "Destination"); + AddAttribute ("value", Utils.CleanupTypeName (type.FullName)); + writer.WriteEndElement (); // properties + writer.WriteEndElement (); // properties + writer.WriteEndElement (); // attribute } } - public static void OutputForwarders (XmlDocument document, XmlNode parent, AssemblyDefinition ass) + public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass) { - TypeForwardedToData tftd = new TypeForwardedToData (document, parent, ass); + TypeForwardedToData tftd = new TypeForwardedToData (writer, ass); tftd.DoOutput (); } } @@ -246,28 +240,23 @@ namespace CorCompare { AssemblyDefinition ass; - public AssemblyData (XmlDocument document, XmlNode parent, AssemblyDefinition ass) - : base (document, parent) + public AssemblyData (XmlWriter writer, AssemblyDefinition ass) + : base (writer) { this.ass = ass; } public override void DoOutput () { - if (document == null) + if (writer == null) throw new InvalidOperationException ("Document not set"); - XmlNode nassembly = document.CreateElement ("assembly", null); + writer.WriteStartElement ("assembly"); AssemblyNameDefinition aname = ass.Name; - AddAttribute (nassembly, "name", aname.Name); - AddAttribute (nassembly, "version", aname.Version.ToString ()); - parent.AppendChild (nassembly); + AddAttribute ("name", aname.Name); + AddAttribute ("version", aname.Version.ToString ()); - if (!Driver.FollowForwarders) { - TypeForwardedToData.OutputForwarders (document, nassembly, ass); - } - - AttributeData.OutputAttributes (document, nassembly, ass); + AttributeData.OutputAttributes (writer, ass); var types = new List (); if (ass.MainModule.Types != null) { @@ -285,17 +274,16 @@ namespace CorCompare } if (types.Count == 0) { + writer.WriteEndElement (); // assembly return; } types.Sort (TypeReferenceComparer.Default); - XmlNode nss = document.CreateElement ("namespaces", null); - nassembly.AppendChild (nss); + writer.WriteStartElement ("namespaces"); string current_namespace = "$%&$&"; - XmlNode ns = null; - XmlNode classes = null; + bool in_namespace = false; foreach (TypeDefinition t in types) { if (string.IsNullOrEmpty (t.Namespace)) continue; @@ -308,16 +296,30 @@ namespace CorCompare if (t.Namespace != current_namespace) { current_namespace = t.Namespace; - ns = document.CreateElement ("namespace", null); - AddAttribute (ns, "name", current_namespace); - nss.AppendChild (ns); - classes = document.CreateElement ("classes", null); - ns.AppendChild (classes); + if (in_namespace) { + writer.WriteEndElement (); // classes + writer.WriteEndElement (); // namespace + } else { + in_namespace = true; + } + writer.WriteStartElement ("namespace"); + AddAttribute ("name", current_namespace); + writer.WriteStartElement ("classes"); } - TypeData bd = new TypeData (document, classes, t); + TypeData bd = new TypeData (writer, t); bd.DoOutput (); + + } + + if (in_namespace) { + writer.WriteEndElement (); // classes + writer.WriteEndElement (); // namespace } + + writer.WriteEndElement (); // namespaces + + writer.WriteEndElement (); // assembly } } @@ -325,31 +327,42 @@ namespace CorCompare { MemberReference [] members; - public MemberData (XmlDocument document, XmlNode parent, MemberReference [] members) - : base (document, parent) + public MemberData (XmlWriter writer, MemberReference [] members) + : base (writer) { this.members = members; } + protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member) + { + return null; + } + public override void DoOutput () { - XmlNode mclass = document.CreateElement (ParentTag, null); - parent.AppendChild (mclass); + writer.WriteStartElement (ParentTag); foreach (MemberReference member in members) { - XmlNode mnode = document.CreateElement (Tag, null); - mclass.AppendChild (mnode); - AddAttribute (mnode, "name", GetName (member)); + writer.WriteStartElement (Tag); + AddAttribute ("name", GetName (member)); if (!NoMemberAttributes) - AddAttribute (mnode, "attrib", GetMemberAttributes (member)); + AddAttribute ("attrib", GetMemberAttributes (member)); + AddExtraAttributes (member); - AttributeData.OutputAttributes (document, mnode, (ICustomAttributeProvider) member); + AttributeData.OutputAttributes (writer, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member)); - AddExtraData (mnode, member); + AddExtraData (member); + writer.WriteEndElement (); // Tag } + + writer.WriteEndElement (); // ParentTag } - protected virtual void AddExtraData (XmlNode p, MemberReference memberDefenition) + protected virtual void AddExtraData (MemberReference memberDefenition) + { + } + + protected virtual void AddExtraAttributes (MemberReference memberDefinition) { } @@ -376,39 +389,42 @@ namespace CorCompare get { return "NoTAG"; } } - public static void OutputGenericParameters (XmlDocument document, XmlNode nclass, IGenericParameterProvider provider) + public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider) { if (provider.GenericParameters.Count == 0) return; var gparameters = provider.GenericParameters; - XmlElement ngeneric = document.CreateElement ("generic-parameters"); - nclass.AppendChild (ngeneric); + writer.WriteStartElement ("generic-parameters"); foreach (GenericParameter gp in gparameters) { - XmlElement nparam = document.CreateElement ("generic-parameter"); - nparam.SetAttribute ("name", gp.Name); - nparam.SetAttribute ("attributes", ((int) gp.Attributes).ToString ()); - - AttributeData.OutputAttributes (document, nparam, gp); + writer.WriteStartElement ("generic-parameter"); + writer.WriteAttributeString ("name", gp.Name); + writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ()); - ngeneric.AppendChild (nparam); + AttributeData.OutputAttributes (writer, gp); var constraints = gp.Constraints; - if (constraints.Count == 0) + if (constraints.Count == 0) { + writer.WriteEndElement (); // generic-parameter continue; + } - XmlElement nconstraint = document.CreateElement ("generic-parameter-constraints"); + writer.WriteStartElement ("generic-parameter-constraints"); foreach (TypeReference constraint in constraints) { - XmlElement ncons = document.CreateElement ("generic-parameter-constraint"); - ncons.SetAttribute ("name", Utils.CleanupTypeName (constraint)); - nconstraint.AppendChild (ncons); + writer.WriteStartElement ("generic-parameter-constraint"); + writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint)); + writer.WriteEndElement (); // generic-parameter-constraint } - nparam.AppendChild (nconstraint); + writer.WriteEndElement (); // generic-parameter-constraints + + writer.WriteEndElement (); // generic-parameter } + + writer.WriteEndElement (); // generic-parameters } } @@ -416,112 +432,107 @@ namespace CorCompare { TypeDefinition type; - public TypeData (XmlDocument document, XmlNode parent, TypeDefinition type) - : base (document, parent, null) + public TypeData (XmlWriter writer, TypeDefinition type) + : base (writer, null) { this.type = type; } public override void DoOutput () { - if (document == null) + if (writer == null) throw new InvalidOperationException ("Document not set"); - XmlNode nclass = document.CreateElement ("class", null); - AddAttribute (nclass, "name", type.Name); + writer.WriteStartElement ("class"); + AddAttribute ("name", type.Name); string classType = GetClassType (type); - AddAttribute (nclass, "type", classType); + AddAttribute ("type", classType); if (type.BaseType != null) - AddAttribute (nclass, "base", Utils.CleanupTypeName (type.BaseType)); + AddAttribute ("base", Utils.CleanupTypeName (type.BaseType)); if (type.IsSealed) - AddAttribute (nclass, "sealed", "true"); + AddAttribute ("sealed", "true"); if (type.IsAbstract) - AddAttribute (nclass, "abstract", "true"); + AddAttribute ("abstract", "true"); if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum) - AddAttribute (nclass, "serializable", "true"); + AddAttribute ("serializable", "true"); string charSet = GetCharSet (type); - AddAttribute (nclass, "charset", charSet); + AddAttribute ("charset", charSet); string layout = GetLayout (type); if (layout != null) - AddAttribute (nclass, "layout", layout); + AddAttribute ("layout", layout); if (type.PackingSize >= 0) { - AddAttribute (nclass, "pack", type.PackingSize.ToString ()); + AddAttribute ("pack", type.PackingSize.ToString ()); } if (type.ClassSize >= 0) { - AddAttribute (nclass, "size", type.ClassSize.ToString ()); + AddAttribute ("size", type.ClassSize.ToString ()); } - parent.AppendChild (nclass); + if (type.IsEnum) { + var value_type = GetEnumValueField (type); + if (value_type == null) + throw new NotSupportedException (); - AttributeData.OutputAttributes (document, nclass, type); + AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType)); + } - XmlNode ifaces = null; + AttributeData.OutputAttributes (writer, type); - foreach (TypeReference iface in TypeHelper.GetInterfaces (type).OrderBy (s => s.FullName)) { - if (!TypeHelper.IsPublic (iface)) - // we're only interested in public interfaces - continue; + var ifaces = TypeHelper.GetInterfaces (type). + Where ((iface) => TypeHelper.IsPublic (iface)). // we're only interested in public interfaces + OrderBy (s => s.FullName); - if (ifaces == null) { - ifaces = document.CreateElement ("interfaces", null); - nclass.AppendChild (ifaces); + if (ifaces.Any ()) { + writer.WriteStartElement ("interfaces"); + foreach (TypeReference iface in ifaces) { + writer.WriteStartElement ("interface"); + AddAttribute ("name", Utils.CleanupTypeName (iface)); + writer.WriteEndElement (); // interface } - - XmlNode iface_node = document.CreateElement ("interface", null); - AddAttribute (iface_node, "name", Utils.CleanupTypeName (iface)); - ifaces.AppendChild (iface_node); + writer.WriteEndElement (); // interfaces } - MemberData.OutputGenericParameters (document, nclass, type); + MemberData.OutputGenericParameters (writer, type); ArrayList members = new ArrayList (); FieldDefinition [] fields = GetFields (type); if (fields.Length > 0) { Array.Sort (fields, MemberReferenceComparer.Default); - FieldData fd = new FieldData (document, nclass, fields); + FieldData fd = new FieldData (writer, fields); members.Add (fd); } - if (type.IsEnum) { - var value_type = GetEnumValueField (type); - if (value_type == null) - throw new NotSupportedException (); - - AddAttribute (nclass, "enumtype", Utils.CleanupTypeName (value_type.FieldType)); - } - if (!Driver.AbiMode) { MethodDefinition [] ctors = GetConstructors (type); if (ctors.Length > 0) { Array.Sort (ctors, MethodDefinitionComparer.Default); - members.Add (new ConstructorData (document, nclass, ctors)); + members.Add (new ConstructorData (writer, ctors)); } PropertyDefinition[] properties = GetProperties (type); if (properties.Length > 0) { Array.Sort (properties, PropertyDefinitionComparer.Default); - members.Add (new PropertyData (document, nclass, properties)); + members.Add (new PropertyData (writer, properties)); } EventDefinition [] events = GetEvents (type); if (events.Length > 0) { Array.Sort (events, MemberReferenceComparer.Default); - members.Add (new EventData (document, nclass, events)); + members.Add (new EventData (writer, events)); } MethodDefinition [] methods = GetMethods (type); if (methods.Length > 0) { Array.Sort (methods, MethodDefinitionComparer.Default); - members.Add (new MethodData (document, nclass, methods)); + members.Add (new MethodData (writer, methods)); } } @@ -547,13 +558,15 @@ namespace CorCompare var nestedArray = nested.ToArray (); Array.Sort (nestedArray, TypeReferenceComparer.Default); - XmlNode classes = document.CreateElement ("classes", null); - nclass.AppendChild (classes); + writer.WriteStartElement ("classes"); foreach (TypeDefinition t in nestedArray) { - TypeData td = new TypeData (document, classes, t); + TypeData td = new TypeData (writer, t); td.DoOutput (); } + writer.WriteEndElement (); // classes } + + writer.WriteEndElement (); // class } static FieldReference GetEnumValueField (TypeDefinition type) @@ -758,8 +771,8 @@ namespace CorCompare class FieldData : MemberData { - public FieldData (XmlDocument document, XmlNode parent, FieldDefinition [] members) - : base (document, parent, members) + public FieldData (XmlWriter writer, FieldDefinition [] members) + : base (writer, members) { } @@ -775,11 +788,12 @@ namespace CorCompare return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture); } - protected override void AddExtraData (XmlNode p, MemberReference memberDefenition) + protected override void AddExtraAttributes (MemberReference memberDefinition) { - base.AddExtraData (p, memberDefenition); - FieldDefinition field = (FieldDefinition) memberDefenition; - AddAttribute (p, "fieldtype", Utils.CleanupTypeName (field.FieldType)); + base.AddExtraAttributes (memberDefinition); + + FieldDefinition field = (FieldDefinition) memberDefinition; + AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType)); if (field.IsLiteral) { object value = field.Constant;//object value = field.GetValue (null); @@ -791,11 +805,11 @@ namespace CorCompare // stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture); //} //else { - stringValue = Convert.ToString (value, CultureInfo.InvariantCulture); + stringValue = Convert.ToString (value, CultureInfo.InvariantCulture); //} if (stringValue != null) - AddAttribute (p, "value", stringValue); + AddAttribute ("value", stringValue); } } @@ -810,8 +824,8 @@ namespace CorCompare class PropertyData : MemberData { - public PropertyData (XmlDocument document, XmlNode parent, PropertyDefinition [] members) - : base (document, parent, members) + public PropertyData (XmlWriter writer, PropertyDefinition [] members) + : base (writer, members) { } @@ -821,15 +835,13 @@ namespace CorCompare return prop.Name; } - protected override void AddExtraData (XmlNode p, MemberReference memberDefenition) + MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters) { - base.AddExtraData (p, memberDefenition); - PropertyDefinition prop = (PropertyDefinition) memberDefenition; - AddAttribute (p, "ptype", Utils.CleanupTypeName (prop.PropertyType)); MethodDefinition _get = prop.GetMethod; MethodDefinition _set = prop.SetMethod; bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get)); bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set)); + haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1); MethodDefinition [] methods; if (haveGet && haveSet) { @@ -840,16 +852,41 @@ namespace CorCompare methods = new MethodDefinition [] { _set }; } else { //odd - return; + return null; } - if (haveGet || _set.Parameters.Count > 1) { + return methods; + } + + protected override void AddExtraAttributes (MemberReference memberDefinition) + { + base.AddExtraAttributes (memberDefinition); + + PropertyDefinition prop = (PropertyDefinition) memberDefinition; + AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType)); + + bool haveParameters; + MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters); + + if (methods != null && haveParameters) { string parms = Parameters.GetSignature (methods [0].Parameters); if (!string.IsNullOrEmpty (parms)) - AddAttribute (p, "params", parms); + AddAttribute ("params", parms); } - MethodData data = new MethodData (document, p, methods); + } + + protected override void AddExtraData (MemberReference memberDefenition) + { + base.AddExtraData (memberDefenition); + + bool haveParameters; + MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters); + + if (methods == null) + return; + + MethodData data = new MethodData (writer, methods); //data.NoMemberAttributes = true; data.DoOutput (); } @@ -871,8 +908,8 @@ namespace CorCompare class EventData : MemberData { - public EventData (XmlDocument document, XmlNode parent, EventDefinition [] members) - : base (document, parent, members) + public EventData (XmlWriter writer, EventDefinition [] members) + : base (writer, members) { } @@ -888,11 +925,12 @@ namespace CorCompare return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture); } - protected override void AddExtraData (XmlNode p, MemberReference memberDefenition) + protected override void AddExtraAttributes (MemberReference memberDefinition) { - base.AddExtraData (p, memberDefenition); - EventDefinition evt = (EventDefinition) memberDefenition; - AddAttribute (p, "eventtype", Utils.CleanupTypeName (evt.EventType)); + base.AddExtraAttributes (memberDefinition); + + EventDefinition evt = (EventDefinition) memberDefinition; + AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType)); } public override string ParentTag { @@ -908,8 +946,8 @@ namespace CorCompare { bool noAtts; - public MethodData (XmlDocument document, XmlNode parent, MethodDefinition [] members) - : base (document, parent, members) + public MethodData (XmlWriter writer, MethodDefinition [] members) + : base (writer, members) { } @@ -928,34 +966,50 @@ namespace CorCompare return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture); } - protected override void AddExtraData (XmlNode p, MemberReference memberDefenition) + protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member) { - base.AddExtraData (p, memberDefenition); + var mbase = (MethodDefinition) member; + return mbase.MethodReturnType; + } - if (!(memberDefenition is MethodDefinition)) - return; + protected override void AddExtraAttributes (MemberReference memberDefinition) + { + base.AddExtraAttributes (memberDefinition); - MethodDefinition mbase = (MethodDefinition) memberDefenition; + if (!(memberDefinition is MethodDefinition)) + return; - ParameterData parms = new ParameterData (document, p, mbase.Parameters); - parms.DoOutput (); + MethodDefinition mbase = (MethodDefinition) memberDefinition; if (mbase.IsAbstract) - AddAttribute (p, "abstract", "true"); + AddAttribute ("abstract", "true"); if (mbase.IsVirtual) - AddAttribute (p, "virtual", "true"); + AddAttribute ("virtual", "true"); if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot) - AddAttribute (p, "sealed", "true"); + AddAttribute ("sealed", "true"); if (mbase.IsStatic) - AddAttribute (p, "static", "true"); - + AddAttribute ("static", "true"); string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType); if (rettype != "System.Void" || !mbase.IsConstructor) - AddAttribute (p, "returntype", (rettype)); + AddAttribute ("returntype", (rettype)); +// +// if (mbase.MethodReturnType.HasCustomAttributes) +// AttributeData.OutputAttributes (writer, mbase.MethodReturnType); + } + + protected override void AddExtraData (MemberReference memberDefenition) + { + base.AddExtraData (memberDefenition); - AttributeData.OutputAttributes (document, p, mbase.MethodReturnType); + if (!(memberDefenition is MethodDefinition)) + return; - MemberData.OutputGenericParameters (document, p, mbase); + MethodDefinition mbase = (MethodDefinition) memberDefenition; + + ParameterData parms = new ParameterData (writer, mbase.Parameters); + parms.DoOutput (); + + MemberData.OutputGenericParameters (writer, mbase); } public override bool NoMemberAttributes { @@ -974,8 +1028,8 @@ namespace CorCompare class ConstructorData : MethodData { - public ConstructorData (XmlDocument document, XmlNode parent, MethodDefinition [] members) - : base (document, parent, members) + public ConstructorData (XmlWriter writer, MethodDefinition [] members) + : base (writer, members) { } @@ -992,23 +1046,20 @@ namespace CorCompare { private IList parameters; - public ParameterData (XmlDocument document, XmlNode parent, IList parameters) - : base (document, parent) + public ParameterData (XmlWriter writer, IList parameters) + : base (writer) { this.parameters = parameters; } public override void DoOutput () { - XmlNode parametersNode = document.CreateElement ("parameters"); - parent.AppendChild (parametersNode); - + writer.WriteStartElement ("parameters"); foreach (ParameterDefinition parameter in parameters) { - XmlNode paramNode = document.CreateElement ("parameter"); - parametersNode.AppendChild (paramNode); - AddAttribute (paramNode, "name", parameter.Name); - AddAttribute (paramNode, "position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture)); - AddAttribute (paramNode, "attrib", ((int) parameter.Attributes).ToString()); + writer.WriteStartElement ("parameter"); + AddAttribute ("name", parameter.Name); + AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture)); + AddAttribute ("attrib", ((int) parameter.Attributes).ToString()); string direction = "in"; @@ -1016,84 +1067,96 @@ namespace CorCompare direction = parameter.IsOut ? "out" : "ref"; TypeReference t = parameter.ParameterType; - AddAttribute (paramNode, "type", Utils.CleanupTypeName (t)); + AddAttribute ("type", Utils.CleanupTypeName (t)); if (parameter.IsOptional) { - AddAttribute (paramNode, "optional", "true"); + AddAttribute ("optional", "true"); if (parameter.HasConstant) - AddAttribute (paramNode, "defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ()); + AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ()); } if (direction != "in") - AddAttribute (paramNode, "direction", direction); + AddAttribute ("direction", direction); - AttributeData.OutputAttributes (document, paramNode, parameter); + AttributeData.OutputAttributes (writer, parameter); + writer.WriteEndElement (); // parameter } + writer.WriteEndElement (); // parameters } } class AttributeData : BaseData { - IList atts; + IList providers; - AttributeData (XmlDocument doc, XmlNode parent, IList attributes) - : base (doc, parent) + AttributeData (XmlWriter writer, IList providers) + : base (writer) { - atts = attributes; + this.providers = providers; } public override void DoOutput () { - if (document == null) + if (writer == null) throw new InvalidOperationException ("Document not set"); - if (atts == null || atts.Count == 0) + if (providers == null || providers.Count == 0) + return; + + if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes)) return; - XmlNode natts = parent.SelectSingleNode("attributes"); - if (natts == null) { - natts = document.CreateElement ("attributes", null); - parent.AppendChild (natts); - } + writer.WriteStartElement ("attributes"); - foreach (var att in atts.OrderBy ((a) => a.Constructor.DeclaringType.FullName)) { - string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType); - if (SkipAttribute (att)) + foreach (var provider in providers) { + if (provider == null) + continue; + + if (!provider.HasCustomAttributes) continue; - XmlNode node = document.CreateElement ("attribute"); - AddAttribute (node, "name", attName); - - XmlNode properties = null; - Dictionary attribute_mapping = CreateAttributeMapping (att); + var ass = provider as AssemblyDefinition; + if (ass != null && !Driver.FollowForwarders) + TypeForwardedToData.OutputForwarders (writer, ass); - foreach (string name in attribute_mapping.Keys) { - if (name == "TypeId") + foreach (var att in provider.CustomAttributes.OrderBy ((a) => a.Constructor.DeclaringType.FullName)) { + string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType); + if (SkipAttribute (att)) continue; - if (properties == null) { - properties = node.AppendChild (document.CreateElement ("properties")); - } + writer.WriteStartElement ("attribute"); + AddAttribute ("name", attName); - object o = attribute_mapping [name]; + var attribute_mapping = CreateAttributeMapping (att).Where ((kvp) => kvp.Key != "TypeId"); - XmlNode n = properties.AppendChild (document.CreateElement ("property")); - AddAttribute (n, "name", name); + if (attribute_mapping.Any ()) { + writer.WriteStartElement ("properties"); + foreach (var kvp in attribute_mapping) { + string name = kvp.Key; + object o = kvp.Value; - if (o == null) { - AddAttribute (n, "value", "null"); - continue; + writer.WriteStartElement ("property"); + AddAttribute ("name", name); + + if (o == null) { + AddAttribute ("value", "null"); + } else { + string value = o.ToString (); + if (attName.EndsWith ("GuidAttribute")) + value = value.ToUpper (); + AddAttribute ("value", value); + } + + writer.WriteEndElement (); // property + } + writer.WriteEndElement (); // properties } - - string value = o.ToString (); - if (attName.EndsWith ("GuidAttribute")) - value = value.ToUpper (); - AddAttribute (n, "value", value); + writer.WriteEndElement (); // attribute } - - natts.AppendChild (node); } + + writer.WriteEndElement (); // attributes } static Dictionary CreateAttributeMapping (CustomAttribute attribute) @@ -1348,12 +1411,9 @@ namespace CorCompare || type_name.EndsWith ("TODOAttribute"); } - public static void OutputAttributes (XmlDocument doc, XmlNode parent, ICustomAttributeProvider provider) + public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers) { - if (!provider.HasCustomAttributes) - return; - - AttributeData ad = new AttributeData (doc, parent, provider.CustomAttributes); + AttributeData ad = new AttributeData (writer, providers); ad.DoOutput (); } } -- 2.25.1