2 // mono-api-diff.cs - Compares 2 xml files produced by mono-api-info and
3 // produces a file suitable to build class status pages.
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (C) 2003 Novell, Inc (http://www.novell.com)
12 using System.Collections;
14 using System.Reflection;
18 namespace Mono.AssemblyCompare
22 static int Main (string [] args)
27 XMLAssembly ms = CreateXMLAssembly (args [0]);
28 XMLAssembly mono = CreateXMLAssembly (args [1]);
29 XmlDocument doc = ms.CompareAndGetDocument (mono);
31 XmlTextWriter writer = new XmlTextWriter (Console.Out);
32 writer.Formatting = Formatting.Indented;
38 static XMLAssembly CreateXMLAssembly (string file)
40 XmlDocument doc = new XmlDocument ();
41 doc.Load (File.OpenRead (file));
43 XmlNode node = doc.SelectSingleNode ("/assemblies/assembly");
44 XMLAssembly result = new XMLAssembly ();
46 result.LoadData (node);
47 } catch (Exception e) {
48 Console.Error.WriteLine ("Error loading {0}: {1}\n{2}", file, e.Message, e);
59 public int PresentTotal;
61 public int MissingTotal;
66 public int ExtraTotal;
68 public int WarningTotal;
69 public int ErrorTotal;
75 public void AddPartialToPartial (Counters other)
77 Present += other.Present;
79 Missing += other.Missing;
82 Warning += other.Warning;
83 AddPartialToTotal (other);
86 public void AddPartialToTotal (Counters other)
88 PresentTotal += other.Present;
89 ExtraTotal += other.Extra;
90 MissingTotal += other.Missing;
92 TodoTotal += other.Todo;
93 WarningTotal += other.Warning;
96 public void AddTotalToPartial (Counters other)
98 Present += other.PresentTotal;
99 Extra += other.ExtraTotal;
100 Missing += other.MissingTotal;
102 Todo += other.TodoTotal;
103 Warning += other.WarningTotal;
104 AddTotalToTotal (other);
107 public void AddTotalToTotal (Counters other)
109 PresentTotal += other.PresentTotal;
110 ExtraTotal += other.ExtraTotal;
111 MissingTotal += other.MissingTotal;
113 TodoTotal += other.TodoTotal;
114 WarningTotal += other.WarningTotal;
115 ErrorTotal += other.ErrorTotal;
119 get { return Present + Missing; }
122 public int AbsTotal {
123 get { return PresentTotal + MissingTotal; }
127 get { return Present - Todo; }
131 get { return PresentTotal - TodoTotal - ErrorTotal; }
134 public override string ToString ()
136 StringWriter sw = new StringWriter ();
137 sw.WriteLine ("Present: {0}", Present);
138 sw.WriteLine ("PresentTotal: {0}", PresentTotal);
139 sw.WriteLine ("Missing: {0}", Missing);
140 sw.WriteLine ("MissingTotal: {0}", MissingTotal);
141 sw.WriteLine ("Todo: {0}", Todo);
142 sw.WriteLine ("TodoTotal: {0}", TodoTotal);
143 sw.WriteLine ("Extra: {0}", Extra);
144 sw.WriteLine ("ExtraTotal: {0}", ExtraTotal);
145 sw.WriteLine ("Warning: {0}", Warning);
146 sw.WriteLine ("WarningTotal: {0}", WarningTotal);
147 sw.WriteLine ("ErrorTotal: {0}", ErrorTotal);
149 return sw.GetStringBuilder ().ToString ();
153 abstract class XMLData
155 protected XmlDocument document;
156 protected Counters counters;
161 counters = new Counters ();
164 public virtual void LoadData (XmlNode node)
168 protected object [] LoadRecursive (XmlNodeList nodeList, Type type)
170 ArrayList list = new ArrayList ();
171 foreach (XmlNode node in nodeList) {
172 XMLData data = (XMLData) Activator.CreateInstance (type);
173 data.LoadData (node);
177 return (object []) list.ToArray (type);
180 protected void AddAttribute (XmlNode node, string name, string value)
182 XmlAttribute attr = document.CreateAttribute (name);
184 node.Attributes.Append (attr);
187 protected void AddExtra (XmlNode node)
189 //TODO: count all the subnodes?
190 AddAttribute (node, "presence", "extra");
191 AddAttribute (node, "ok", "1");
192 AddAttribute (node, "ok_total", "1");
193 AddAttribute (node, "extra", "1");
194 AddAttribute (node, "extra_total", "1");
197 public void AddCountersAttributes (XmlNode node)
199 if (counters.Missing > 0)
200 AddAttribute (node, "missing", counters.Missing.ToString ());
202 if (counters.Present > 0)
203 AddAttribute (node, "present", counters.Present.ToString ());
205 if (counters.Extra > 0)
206 AddAttribute (node, "extra", counters.Extra.ToString ());
209 AddAttribute (node, "ok", counters.Ok.ToString ());
211 if (counters.Total > 0) {
212 int percent = (100 * counters.Ok / counters.Total);
213 AddAttribute (node, "complete", percent.ToString ());
216 if (counters.Todo > 0)
217 AddAttribute (node, "todo", counters.Todo.ToString ());
219 if (counters.Warning > 0)
220 AddAttribute (node, "warning", counters.Warning.ToString ());
222 if (counters.MissingTotal > 0)
223 AddAttribute (node, "missing_total", counters.MissingTotal.ToString ());
225 if (counters.PresentTotal > 0)
226 AddAttribute (node, "present_total", counters.PresentTotal.ToString ());
228 if (counters.ExtraTotal > 0)
229 AddAttribute (node, "extra_total", counters.ExtraTotal.ToString ());
231 if (counters.OkTotal > 0)
232 AddAttribute (node, "ok_total", counters.OkTotal.ToString ());
234 if (counters.AbsTotal > 0) {
235 int percent = (100 * counters.OkTotal / counters.AbsTotal);
236 AddAttribute (node, "complete_total", percent.ToString ());
239 if (counters.TodoTotal > 0) {
240 AddAttribute (node, "todo_total", counters.TodoTotal.ToString ());
241 //TODO: should be different on error. check error cases in corcompare.
242 AddAttribute (node, "error_total", counters.Todo.ToString ());
245 if (counters.WarningTotal > 0)
246 AddAttribute (node, "warning_total", counters.WarningTotal.ToString ());
250 protected void AddWarning (XmlNode parent, string fmt, params object [] args)
254 XmlNode warnings = parent.SelectSingleNode ("warnings");
255 if (warnings == null) {
256 warnings = document.CreateElement ("warnings", null);
257 parent.AppendChild (warnings);
260 AddAttribute (parent, "error", "warning");
261 XmlNode warning = document.CreateElement ("warning", null);
262 AddAttribute (warning, "text", String.Format (fmt, args));
263 warnings.AppendChild (warning);
266 public bool HaveWarnings {
267 get { return haveWarnings; }
270 public Counters Counters {
271 get { return counters; }
274 public abstract void CompareTo (XmlDocument doc, XmlNode parent, object other);
277 abstract class XMLNameGroup : XMLData
279 protected XmlNode group;
280 protected Hashtable keys;
282 public override void LoadData (XmlNode node)
285 throw new ArgumentNullException ("node");
287 if (node.Name != GroupName)
288 throw new FormatException (String.Format ("Expecting <{0}>", GroupName));
290 keys = new Hashtable ();
291 foreach (XmlNode n in node.ChildNodes) {
292 string name = n.Attributes ["name"].Value;
293 if (CheckIfAdd (name, n)) {
294 string key = GetNodeKey (name, n);
295 //keys.Add (key, name);
297 LoadExtraData (key, n);
302 protected virtual bool CheckIfAdd (string value, XmlNode node)
307 protected virtual void LoadExtraData (string name, XmlNode node)
311 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
315 group = doc.CreateElement (GroupName, null);
317 Hashtable okeys = null;
318 if (other != null && ((XMLNameGroup) other).keys != null) {
319 okeys = ((XMLNameGroup) other).keys;
323 bool onull = (okeys == null);
325 foreach (DictionaryEntry entry in keys) {
326 node = doc.CreateElement (Name, null);
327 group.AppendChild (node);
328 string key = (string) entry.Key;
329 string name = (string) entry.Value;
330 AddAttribute (node, "name", name);
332 if (!onull && HasKey (key, okeys)) {
333 CompareToInner (key, node, (XMLNameGroup) other);
337 AddAttribute (node, "presence", "missing");
343 if (!onull && okeys.Count != 0) {
344 foreach (string value in okeys.Values) {
345 node = doc.CreateElement (Name, null);
346 AddAttribute (node, "name", (string) value);
347 AddAttribute (node, "presence", "extra");
348 group.AppendChild (node);
353 if (group.HasChildNodes)
354 parent.AppendChild (group);
357 protected virtual void CompareToInner (string name, XmlNode node, XMLNameGroup other)
361 public virtual string GetNodeKey (string name, XmlNode node)
366 public virtual bool HasKey (string key, Hashtable other)
368 return other.ContainsKey (key);
371 public abstract string GroupName { get; }
372 public abstract string Name { get; }
375 class XMLAssembly : XMLData
377 XMLAttributes attributes;
378 XMLNamespace [] namespaces;
382 public override void LoadData (XmlNode node)
385 throw new ArgumentNullException ("node");
387 name = node.Attributes ["name"].Value;
388 version = node.Attributes ["version"].Value;
389 XmlNode atts = node.FirstChild;
390 attributes = new XMLAttributes ();
391 if (atts.Name == "attributes") {
392 attributes.LoadData (atts);
393 atts = atts.NextSibling;
396 if (atts == null || atts.Name != "namespaces") {
397 Console.Error.WriteLine ("Warning: no namespaces found!");
401 namespaces = (XMLNamespace []) LoadRecursive (atts.ChildNodes, typeof (XMLNamespace));
404 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
406 XMLAssembly assembly = (XMLAssembly) other;
408 XmlNode childA = doc.CreateElement ("assembly", null);
409 AddAttribute (childA, "name", name);
410 AddAttribute (childA, "version", version);
411 if (name != assembly.name)
412 AddWarning (childA, "Assembly names not equal: {0}, {1}", name, assembly.name);
414 if (version != assembly.version)
415 AddWarning (childA, "Assembly version not equal: {0}, {1}", version, assembly.version);
417 parent.AppendChild (childA);
419 attributes.CompareTo (doc, childA, assembly.attributes);
420 counters.AddPartialToPartial (attributes.Counters);
422 CompareNamespaces (childA, assembly.namespaces);
423 if (assembly.attributes != null && assembly.attributes.IsTodo) {
425 counters.TodoTotal++;
426 counters.ErrorTotal++;
427 AddAttribute (childA, "error", "todo");
428 if (assembly.attributes.Comment != null)
429 AddAttribute (childA, "comment", assembly.attributes.Comment);
432 AddCountersAttributes (childA);
435 void CompareNamespaces (XmlNode parent, XMLNamespace [] other)
437 ArrayList newNS = new ArrayList ();
438 XmlNode group = document.CreateElement ("namespaces", null);
439 parent.AppendChild (group);
441 Hashtable oh = CreateHash (other);
443 int count = (namespaces == null) ? 0 : namespaces.Length;
444 for (int i = 0; i < count; i++) {
445 XMLNamespace xns = namespaces [i];
447 node = document.CreateElement ("namespace", null);
449 AddAttribute (node, "name", xns.Name);
451 if (oh.ContainsKey (xns.Name)) {
452 int idx = (int) oh [xns.Name];
453 xns.CompareTo (document, node, other [idx]);
455 xns.AddCountersAttributes (node);
457 counters.PresentTotal++;
458 counters.AddPartialToTotal (xns.Counters);
460 AddAttribute (node, "presence", "missing");
462 counters.MissingTotal++;
467 count = other.Length;
468 for (int i = 0; i < count; i++) {
469 XMLNamespace n = other [i];
473 node = document.CreateElement ("namespace", null);
475 AddAttribute (node, "name", n.Name);
477 counters.ExtraTotal++;
481 XmlNode [] nodes = (XmlNode []) newNS.ToArray (typeof (XmlNode));
482 Array.Sort (nodes, XmlNodeComparer.Default);
483 foreach (XmlNode nn in nodes)
484 group.AppendChild (nn);
487 static Hashtable CreateHash (XMLNamespace [] other)
489 Hashtable result = new Hashtable ();
492 foreach (XMLNamespace n in other) {
493 result [n.Name] = i++;
500 public XmlDocument CompareAndGetDocument (XMLAssembly other)
502 XmlDocument doc = new XmlDocument ();
504 XmlNode parent = doc.CreateElement ("assemblies", null);
505 doc.AppendChild (parent);
507 CompareTo (doc, parent, other);
509 XmlNode decl = doc.CreateXmlDeclaration ("1.0", null, null);
510 doc.InsertBefore (decl, doc.DocumentElement);
516 class XMLNamespace : XMLData
521 public override void LoadData (XmlNode node)
524 throw new ArgumentNullException ("node");
526 if (node.Name != "namespace")
527 throw new FormatException ("Expecting <namespace>");
529 name = node.Attributes ["name"].Value;
530 XmlNode classes = node.FirstChild;
531 if (classes == null) {
532 Console.Error.WriteLine ("Warning: no classes for {0}", node.Attributes ["name"]);
536 if (classes.Name != "classes")
537 throw new FormatException ("Expecting <classes>. Got <" + classes.Name + ">");
539 types = (XMLClass []) LoadRecursive (classes.ChildNodes, typeof (XMLClass));
542 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
545 XMLNamespace nspace = (XMLNamespace) other;
547 XmlNode childA = doc.CreateElement ("classes", null);
548 parent.AppendChild (childA);
550 CompareTypes (childA, nspace.types);
553 void CompareTypes (XmlNode parent, XMLClass [] other)
555 ArrayList newNodes = new ArrayList ();
556 Hashtable oh = CreateHash (other);
558 int count = (types == null) ? 0 : types.Length;
559 for (int i = 0; i < count; i++) {
560 XMLClass xclass = types [i];
562 node = document.CreateElement ("class", null);
564 AddAttribute (node, "name", xclass.Name);
565 AddAttribute (node, "type", xclass.Type);
567 if (oh.ContainsKey (xclass.Name)) {
568 int idx = (int) oh [xclass.Name];
569 xclass.CompareTo (document, node, other [idx]);
571 counters.AddPartialToPartial (xclass.Counters);
573 AddAttribute (node, "presence", "missing");
575 counters.MissingTotal++;
580 count = other.Length;
581 for (int i = 0; i < count; i++) {
582 XMLClass c = other [i];
583 if (c == null || c.Name.EndsWith ("TODOAttribute"))
586 node = document.CreateElement ("class", null);
588 AddAttribute (node, "name", c.Name);
589 AddAttribute (node, "type", c.Type);
592 counters.ExtraTotal++;
596 XmlNode [] nodes = (XmlNode []) newNodes.ToArray (typeof (XmlNode));
597 Array.Sort (nodes, XmlNodeComparer.Default);
598 foreach (XmlNode nn in nodes)
599 parent.AppendChild (nn);
602 static Hashtable CreateHash (XMLClass [] other)
604 Hashtable result = new Hashtable ();
607 foreach (XMLClass c in other) {
608 result [c.Name] = i++;
620 class XMLClass : XMLData
630 XMLAttributes attributes;
631 XMLInterfaces interfaces;
632 XMLGenericTypeConstraints genericConstraints;
634 XMLConstructors constructors;
635 XMLProperties properties;
640 public override void LoadData (XmlNode node)
643 throw new ArgumentNullException ("node");
645 name = node.Attributes ["name"].Value;
646 type = node.Attributes ["type"].Value;
647 XmlAttribute xatt = node.Attributes ["base"];
649 baseName = xatt.Value;
651 xatt = node.Attributes ["sealed"];
652 isSealed = (xatt != null && xatt.Value == "true");
654 xatt = node.Attributes ["abstract"];
655 isAbstract = (xatt != null && xatt.Value == "true");
657 xatt = node.Attributes["serializable"];
658 isSerializable = (xatt != null && xatt.Value == "true");
660 xatt = node.Attributes["charset"];
662 charSet = xatt.Value;
664 xatt = node.Attributes["layout"];
668 XmlNode child = node.FirstChild;
670 // Console.Error.WriteLine ("Empty class {0} {1}", name, type);
674 if (child.Name == "attributes") {
675 attributes = new XMLAttributes ();
676 attributes.LoadData (child);
677 child = child.NextSibling;
680 if (child != null && child.Name == "interfaces") {
681 interfaces = new XMLInterfaces ();
682 interfaces.LoadData (child);
683 child = child.NextSibling;
686 if (child != null && child.Name == "generic-type-constraints") {
687 genericConstraints = new XMLGenericTypeConstraints ();
688 genericConstraints.LoadData (child);
689 child = child.NextSibling;
692 if (child != null && child.Name == "fields") {
693 fields = new XMLFields ();
694 fields.LoadData (child);
695 child = child.NextSibling;
698 if (child != null && child.Name == "constructors") {
699 constructors = new XMLConstructors ();
700 constructors.LoadData (child);
701 child = child.NextSibling;
704 if (child != null && child.Name == "properties") {
705 properties = new XMLProperties ();
706 properties.LoadData (child);
707 child = child.NextSibling;
710 if (child != null && child.Name == "events") {
711 events = new XMLEvents ();
712 events.LoadData (child);
713 child = child.NextSibling;
716 if (child != null && child.Name == "methods") {
717 methods = new XMLMethods ();
718 methods.LoadData (child);
719 child = child.NextSibling;
725 if (child.Name != "classes") {
726 Console.WriteLine ("name: {0} type: {1} {2}", name, type, child.NodeType);
727 throw new FormatException ("Expecting <classes>. Got <" + child.Name + ">");
730 nested = (XMLClass []) LoadRecursive (child.ChildNodes, typeof (XMLClass));
733 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
736 XMLClass oclass = (XMLClass) other;
738 if (attributes != null || oclass.attributes != null) {
739 if (attributes == null)
740 attributes = new XMLAttributes ();
742 attributes.CompareTo (doc, parent, oclass.attributes);
743 counters.AddPartialToPartial (attributes.Counters);
744 if (oclass.attributes != null && oclass.attributes.IsTodo) {
746 counters.TodoTotal++;
747 counters.ErrorTotal++;
748 AddAttribute (parent, "error", "todo");
749 if (oclass.attributes.Comment != null)
750 AddAttribute (parent, "comment", oclass.attributes.Comment);
754 if (type != oclass.type)
755 AddWarning (parent, "Class type is wrong: {0} != {1}", type, oclass.type);
757 if (baseName != oclass.baseName)
758 AddWarning (parent, "Base class is wrong: {0} != {1}", baseName, oclass.baseName);
760 if (isAbstract != oclass.isAbstract || isSealed != oclass.isSealed) {
761 if ((isAbstract && isSealed) || (oclass.isAbstract && oclass.isSealed))
762 AddWarning (parent, "Should {0}be static", (isAbstract && isSealed) ? "" : "not ");
763 else if (isAbstract != oclass.isAbstract)
764 AddWarning (parent, "Should {0}be abstract", isAbstract ? "" : "not ");
765 else if (isSealed != oclass.isSealed)
766 AddWarning (parent, "Should {0}be sealed", isSealed ? "" : "not ");
769 if (isSerializable != oclass.isSerializable)
770 AddWarning (parent, "Should {0}be serializable", isSerializable ? "" : "not ");
772 if (charSet != oclass.charSet)
773 AddWarning (parent, "CharSet is wrong: {0} != {1}", charSet, oclass.charSet);
775 if (layout != oclass.layout)
776 AddWarning (parent, "Layout is wrong: {0} != {1}", layout, oclass.layout);
778 if (interfaces != null || oclass.interfaces != null) {
779 if (interfaces == null)
780 interfaces = new XMLInterfaces ();
782 interfaces.CompareTo (doc, parent, oclass.interfaces);
783 counters.AddPartialToPartial (interfaces.Counters);
786 if (genericConstraints != null || oclass.genericConstraints != null) {
787 if (genericConstraints == null)
788 genericConstraints = new XMLGenericTypeConstraints ();
790 genericConstraints.CompareTo (doc, parent, oclass.genericConstraints);
791 counters.AddPartialToPartial (genericConstraints.Counters);
794 if (fields != null || oclass.fields != null) {
796 fields = new XMLFields ();
798 fields.CompareTo (doc, parent, oclass.fields);
799 counters.AddPartialToPartial (fields.Counters);
802 if (constructors != null || oclass.constructors != null) {
803 if (constructors == null)
804 constructors = new XMLConstructors ();
806 constructors.CompareTo (doc, parent, oclass.constructors);
807 counters.AddPartialToPartial (constructors.Counters);
810 if (properties != null || oclass.properties != null) {
811 if (properties == null)
812 properties = new XMLProperties ();
814 properties.CompareTo (doc, parent, oclass.properties);
815 counters.AddPartialToPartial (properties.Counters);
818 if (events != null || oclass.events != null) {
820 events = new XMLEvents ();
822 events.CompareTo (doc, parent, oclass.events);
823 counters.AddPartialToPartial (events.Counters);
826 if (methods != null || oclass.methods != null) {
828 methods = new XMLMethods ();
830 methods.CompareTo (doc, parent, oclass.methods);
831 counters.AddPartialToPartial (methods.Counters);
834 if (nested != null || oclass.nested != null) {
835 XmlNode n = doc.CreateElement ("classes", null);
836 parent.AppendChild (n);
837 CompareTypes (n, oclass.nested);
840 AddCountersAttributes (parent);
843 void CompareTypes (XmlNode parent, XMLClass [] other)
845 ArrayList newNodes = new ArrayList ();
846 Hashtable oh = CreateHash (other);
848 int count = (nested == null) ? 0 : nested.Length;
849 for (int i = 0; i < count; i++) {
850 XMLClass xclass = nested [i];
852 node = document.CreateElement ("nestedclass", null);
854 AddAttribute (node, "name", xclass.Name);
855 AddAttribute (node, "type", xclass.Type);
857 if (oh.ContainsKey (xclass.Name)) {
858 int idx = (int) oh [xclass.Name];
859 xclass.CompareTo (document, node, other [idx]);
861 counters.AddPartialToPartial (xclass.Counters);
863 // TODO: Should I count here?
864 AddAttribute (node, "presence", "missing");
866 counters.MissingTotal++;
871 count = other.Length;
872 for (int i = 0; i < count; i++) {
873 XMLClass c = other [i];
874 if (c == null || c.Name.EndsWith ("TODOAttribute"))
877 node = document.CreateElement ("nestedclass", null);
879 AddAttribute (node, "name", c.Name);
882 counters.ExtraTotal++;
886 XmlNode [] nodes = (XmlNode []) newNodes.ToArray (typeof (XmlNode));
887 Array.Sort (nodes, XmlNodeComparer.Default);
888 foreach (XmlNode nn in nodes)
889 parent.AppendChild (nn);
892 static Hashtable CreateHash (XMLClass [] other)
894 Hashtable result = new Hashtable ();
897 foreach (XMLClass c in other) {
898 result [c.Name] = i++;
914 class XMLParameter : XMLData
924 public override void LoadData (XmlNode node)
927 throw new ArgumentNullException ("node");
929 if (node.Name != "parameter")
930 throw new ArgumentException ("Expecting <parameter>");
932 name = node.Attributes["name"].Value;
933 type = node.Attributes["type"].Value;
934 attrib = node.Attributes["attrib"].Value;
935 if (node.Attributes ["direction"] != null)
936 direction = node.Attributes["direction"].Value;
937 if (node.Attributes["unsafe"] != null)
938 isUnsafe = bool.Parse (node.Attributes["unsafe"].Value);
939 if (node.Attributes["optional"] != null)
940 isOptional = bool.Parse (node.Attributes["optional"].Value);
941 if (node.Attributes["defaultValue"] != null)
942 defaultValue = node.Attributes["defaultValue"].Value;
945 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
949 XMLParameter oparm = (XMLParameter) other;
951 if (type != oparm.type)
952 AddWarning (parent, "Parameter type is wrong: {0} != {1}", type, oparm.type);
954 if (attrib != oparm.attrib)
955 AddWarning (parent, "Parameter attributes wrong: {0} != {1}", attrib, oparm.attrib);
957 if (direction != oparm.direction)
958 AddWarning (parent, "Parameter direction wrong: {0} != {1}", direction, oparm.direction);
960 if (isUnsafe != oparm.isUnsafe)
961 AddWarning (parent, "Parameter unsafe wrong: {0} != {1}", isUnsafe, oparm.isUnsafe);
963 if (isOptional != oparm.isOptional)
964 AddWarning (parent, "Parameter optional wrong: {0} != {1}", isOptional, oparm.isOptional);
966 if (defaultValue != oparm.defaultValue)
967 AddWarning (parent, "Parameter default value wrong: {0} != {1}", (defaultValue == null) ? "(no default value)" : defaultValue, (oparm.defaultValue == null) ? "(no default value)" : oparm.defaultValue);
975 class XMLAttributeProperties: XMLNameGroup
977 static Hashtable ignored_properties;
978 static XMLAttributeProperties ()
980 ignored_properties = new Hashtable ();
981 ignored_properties.Add ("System.Reflection.AssemblyKeyFileAttribute", "KeyFile");
982 ignored_properties.Add ("System.Reflection.AssemblyCompanyAttribute", "Company");
983 ignored_properties.Add ("System.Reflection.AssemblyConfigurationAttribute", "Configuration");
984 ignored_properties.Add ("System.Reflection.AssemblyCopyrightAttribute", "Copyright");
985 ignored_properties.Add ("System.Reflection.AssemblyProductAttribute", "Product");
986 ignored_properties.Add ("System.Reflection.AssemblyTrademarkAttribute", "Trademark");
987 ignored_properties.Add ("System.Reflection.AssemblyInformationalVersionAttribute", "InformationalVersion");
989 ignored_properties.Add ("System.ObsoleteAttribute", "Message");
990 ignored_properties.Add ("System.IO.IODescriptionAttribute", "Description");
991 ignored_properties.Add ("System.Diagnostics.MonitoringDescriptionAttribute", "Description");
994 Hashtable properties = new Hashtable ();
997 public XMLAttributeProperties (string attribute)
999 this.attribute = attribute;
1002 public override void LoadData(XmlNode node)
1005 throw new ArgumentNullException ("node");
1007 if (node.ChildNodes == null)
1010 string ignored = ignored_properties [attribute] as string;
1012 foreach (XmlNode n in node.ChildNodes) {
1013 string name = n.Attributes ["name"].Value;
1014 if (ignored == name)
1017 if (n.Attributes ["null"] != null) {
1018 properties.Add (name, null);
1021 string value = n.Attributes ["value"].Value;
1022 properties.Add (name, value);
1026 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
1028 this.document = doc;
1030 Hashtable other_properties = ((XMLAttributeProperties)other).properties;
1031 foreach (DictionaryEntry de in other_properties) {
1032 object other_value = properties [de.Key];
1034 if (de.Value == null) {
1035 if (other_value != null)
1036 AddWarning (parent, "Property '{0}' is 'null' and should be '{1}'", de.Key, other_value);
1040 if (de.Value.Equals (other_value))
1043 AddWarning (parent, "Property '{0}' is '{1}' and should be '{2}'",
1044 de.Key, de.Value, other_value == null ? "null" : other_value);
1048 public override string GroupName {
1050 return "properties";
1054 public override string Name {
1061 class XMLAttributes : XMLNameGroup
1063 Hashtable properties = new Hashtable ();
1068 protected override bool CheckIfAdd (string value, XmlNode node)
1070 if (value.EndsWith ("TODOAttribute")) {
1073 XmlNode pNode = node.SelectSingleNode ("properties");
1074 if (pNode.ChildNodes [0].Attributes ["value"] != null) {
1075 comment = pNode.ChildNodes [0].Attributes ["value"].Value;
1083 protected override void CompareToInner (string name, XmlNode node, XMLNameGroup other)
1085 XMLAttributeProperties other_prop = ((XMLAttributes)other).properties [name] as XMLAttributeProperties;
1086 XMLAttributeProperties this_prop = properties [name] as XMLAttributeProperties;
1087 if (other_prop == null || this_prop == null)
1090 this_prop.CompareTo (document, node, other_prop);
1091 counters.AddPartialToPartial (this_prop.Counters);
1094 public override string GetNodeKey (string name, XmlNode node)
1098 // if multiple attributes with the same name (type) exist, then we
1099 // cannot be sure which attributes correspond, so we must use the
1100 // name of the attribute (type) and the name/value of its properties
1103 XmlNodeList attributes = node.ParentNode.SelectNodes("attribute[@name='" + name + "']");
1104 if (attributes.Count > 1) {
1105 ArrayList keyParts = new ArrayList ();
1107 XmlNodeList properties = node.SelectNodes ("properties/property");
1108 foreach (XmlNode property in properties) {
1109 XmlAttributeCollection attrs = property.Attributes;
1110 if (attrs["value"] != null) {
1111 keyParts.Add (attrs["name"].Value + "=" + attrs["value"].Value);
1113 keyParts.Add (attrs["name"].Value + "=");
1117 // sort properties by name, as order of properties in XML is
1121 // insert name (type) of attribute
1122 keyParts.Insert (0, name);
1124 StringBuilder sb = new StringBuilder ();
1125 foreach (string value in keyParts) {
1129 key = sb.ToString ();
1137 protected override void LoadExtraData(string name, XmlNode node)
1139 XmlNode pNode = node.SelectSingleNode ("properties");
1141 if (name.EndsWith ("TODOAttribute")) {
1143 if (pNode.ChildNodes [0].Attributes ["value"] != null) {
1144 comment = pNode.ChildNodes [0].Attributes ["value"].Value;
1149 if (pNode != null) {
1150 XMLAttributeProperties p = new XMLAttributeProperties (name);
1153 properties[name] = p;
1157 public override string GroupName {
1158 get { return "attributes"; }
1161 public override string Name {
1162 get { return "attribute"; }
1165 public bool IsTodo {
1166 get { return isTodo; }
1169 public string Comment {
1170 get { return comment; }
1174 class XMLInterfaces : XMLNameGroup
1176 public override string GroupName {
1177 get { return "interfaces"; }
1180 public override string Name {
1181 get { return "interface"; }
1185 abstract class XMLGenericGroup : XMLNameGroup
1189 protected override void LoadExtraData (string name, XmlNode node)
1191 attributes = ((XmlElement) node).GetAttribute ("generic-attribute");
1194 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1196 base.CompareToInner (name, parent, other);
1198 XMLGenericGroup g = (XMLGenericGroup) other;
1199 if (attributes != g.attributes)
1200 AddWarning (parent, "Incorrect generic attributes: '{0}' != '{1}'", attributes, g.attributes);
1204 class XMLGenericTypeConstraints : XMLGenericGroup
1206 public override string GroupName {
1207 get { return "generic-type-constraints"; }
1210 public override string Name {
1211 get { return "generic-type-constraint"; }
1215 class XMLGenericMethodConstraints : XMLGenericGroup
1217 public override string GroupName {
1218 get { return "generic-method-constraints"; }
1221 public override string Name {
1222 get { return "generic-method-constraint"; }
1226 abstract class XMLMember : XMLNameGroup
1228 Hashtable attributeMap;
1229 Hashtable access = new Hashtable ();
1231 protected override void LoadExtraData (string name, XmlNode node)
1233 XmlAttribute xatt = node.Attributes ["attrib"];
1235 access [name] = xatt.Value;
1237 XmlNode orig = node;
1239 node = node.FirstChild;
1240 while (node != null) {
1241 if (node != null && node.Name == "attributes") {
1242 XMLAttributes a = new XMLAttributes ();
1244 if (attributeMap == null)
1245 attributeMap = new Hashtable ();
1247 attributeMap [name] = a;
1250 node = node.NextSibling;
1253 base.LoadExtraData (name, orig);
1256 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1258 base.CompareToInner (name, parent, other);
1259 XMLMember mb = other as XMLMember;
1260 XMLAttributes att = null;
1261 XMLAttributes oatt = null;
1262 if (attributeMap != null)
1263 att = attributeMap [name] as XMLAttributes;
1265 if (mb != null && mb.attributeMap != null)
1266 oatt = mb.attributeMap [name] as XMLAttributes;
1268 if (att != null || oatt != null) {
1270 att = new XMLAttributes ();
1272 att.CompareTo (document, parent, oatt);
1273 counters.AddPartialToPartial(att.Counters);
1274 if (oatt != null && oatt.IsTodo) {
1276 counters.ErrorTotal++;
1277 AddAttribute (parent, "error", "todo");
1278 if (oatt.Comment != null)
1279 AddAttribute (parent, "comment", oatt.Comment);
1283 XMLMember member = (XMLMember) other;
1284 string acc = access [name] as string;
1289 if (member.access != null)
1290 oacc = member.access [name] as string;
1292 string accName = ConvertToString (Int32.Parse (acc));
1293 string oaccName = "";
1295 oaccName = ConvertToString (Int32.Parse (oacc));
1297 if (accName != oaccName)
1298 AddWarning (parent, "Incorrect attributes: '{0}' != '{1}'", accName, oaccName);
1301 protected virtual string ConvertToString (int att)
1307 class XMLFields : XMLMember
1309 Hashtable fieldTypes;
1310 Hashtable fieldValues;
1312 protected override void LoadExtraData (string name, XmlNode node)
1314 XmlAttribute xatt = node.Attributes ["fieldtype"];
1316 if (fieldTypes == null)
1317 fieldTypes = new Hashtable ();
1319 fieldTypes [name] = xatt.Value;
1322 xatt = node.Attributes ["value"];
1324 if (fieldValues == null)
1325 fieldValues = new Hashtable ();
1327 fieldValues[name] = xatt.Value;
1330 base.LoadExtraData (name, node);
1333 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1335 base.CompareToInner (name, parent, other);
1336 XMLFields fields = (XMLFields) other;
1337 if (fieldTypes != null) {
1338 string ftype = fieldTypes [name] as string;
1339 string oftype = null;
1340 if (fields.fieldTypes != null)
1341 oftype = fields.fieldTypes [name] as string;
1343 if (ftype != oftype)
1344 AddWarning (parent, "Field type is {0} and should be {1}", oftype, ftype);
1346 if (fieldValues != null) {
1347 string fvalue = fieldValues [name] as string;
1348 string ofvalue = null;
1349 if (fields.fieldValues != null)
1350 ofvalue = fields.fieldValues [name] as string;
1352 if (fvalue != ofvalue)
1353 AddWarning (parent, "Field value is {0} and should be {1}", ofvalue, fvalue);
1357 protected override string ConvertToString (int att)
1359 FieldAttributes fa = (FieldAttributes) att;
1360 return fa.ToString ();
1363 public override string GroupName {
1364 get { return "fields"; }
1367 public override string Name {
1368 get { return "field"; }
1372 class XMLParameters : XMLNameGroup
1374 public override void LoadData (XmlNode node)
1377 throw new ArgumentNullException ("node");
1379 if (node.Name != GroupName)
1380 throw new FormatException (String.Format ("Expecting <{0}>", GroupName));
1382 keys = new Hashtable ();
1383 foreach (XmlNode n in node.ChildNodes) {
1384 string name = n.Attributes["name"].Value;
1385 string key = GetNodeKey (name, n);
1386 XMLParameter parm = new XMLParameter ();
1388 keys.Add (key, parm);
1389 LoadExtraData (key, n);
1393 public override string GroupName {
1395 return "parameters";
1399 public override string Name {
1405 public override string GetNodeKey (string name, XmlNode node)
1407 return node.Attributes["position"].Value;
1410 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
1412 this.document = doc;
1414 group = doc.CreateElement (GroupName, null);
1416 Hashtable okeys = null;
1417 if (other != null && ((XMLParameters) other).keys != null) {
1418 okeys = ((XMLParameters) other).keys;
1421 XmlNode node = null;
1422 bool onull = (okeys == null);
1424 foreach (DictionaryEntry entry in keys) {
1425 node = doc.CreateElement (Name, null);
1426 group.AppendChild (node);
1427 string key = (string) entry.Key;
1428 XMLParameter parm = (XMLParameter) entry.Value;
1429 AddAttribute (node, "name", parm.Name);
1431 if (!onull && HasKey (key, okeys)) {
1432 parm.CompareTo (document, node, okeys[key]);
1433 counters.AddPartialToPartial (parm.Counters);
1437 AddAttribute (node, "presence", "missing");
1443 if (!onull && okeys.Count != 0) {
1444 foreach (XMLParameter value in okeys.Values) {
1445 node = doc.CreateElement (Name, null);
1446 AddAttribute (node, "name", value.Name);
1447 AddAttribute (node, "presence", "extra");
1448 group.AppendChild (node);
1453 if (group.HasChildNodes)
1454 parent.AppendChild (group);
1458 class XMLProperties : XMLMember
1460 Hashtable nameToMethod = new Hashtable ();
1462 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1464 Counters copy = counters;
1465 counters = new Counters();
1467 XMLProperties oprop = other as XMLProperties;
1468 if (oprop != null) {
1469 XMLMethods m = nameToMethod [name] as XMLMethods;
1470 XMLMethods om = oprop.nameToMethod [name] as XMLMethods;
1471 if (m != null || om != null) {
1473 m = new XMLMethods ();
1475 m.CompareTo(document, parent, om);
1476 counters.AddPartialToPartial(m.Counters);
1480 base.CompareToInner (name, parent, other);
1481 AddCountersAttributes(parent);
1483 copy.AddPartialToPartial(counters);
1487 protected override void LoadExtraData (string name, XmlNode node)
1489 XmlNode orig = node;
1490 node = node.FirstChild;
1491 while (node != null) {
1492 if (node != null && node.Name == "methods") {
1493 XMLMethods m = new XMLMethods ();
1494 XmlNode parent = node.ParentNode;
1495 string key = GetNodeKey (name, parent);
1497 nameToMethod [key] = m;
1500 node = node.NextSibling;
1503 base.LoadExtraData (name, orig);
1506 public override string GetNodeKey (string name, XmlNode node)
1508 XmlAttributeCollection atts = node.Attributes;
1509 return String.Format ("{0}:{1}:{2}", atts ["name"].Value,
1510 atts ["ptype"].Value,
1511 atts ["params"].Value);
1514 public override string GroupName {
1515 get { return "properties"; }
1518 public override string Name {
1519 get { return "property"; }
1523 class XMLEvents : XMLMember
1525 Hashtable eventTypes;
1527 protected override void LoadExtraData (string name, XmlNode node)
1529 XmlAttribute xatt = node.Attributes ["eventtype"];
1531 if (eventTypes == null)
1532 eventTypes = new Hashtable ();
1534 eventTypes [name] = xatt.Value;
1537 base.LoadExtraData (name, node);
1540 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1542 Counters copy = counters;
1543 counters = new Counters ();
1546 base.CompareToInner (name, parent, other);
1547 AddCountersAttributes (parent);
1548 if (eventTypes == null)
1551 XMLEvents evt = (XMLEvents) other;
1552 string etype = eventTypes [name] as string;
1553 string oetype = null;
1554 if (evt.eventTypes != null)
1555 oetype = evt.eventTypes [name] as string;
1557 if (etype != oetype)
1558 AddWarning (parent, "Event type is {0} and should be {1}", oetype, etype);
1560 AddCountersAttributes (parent);
1561 copy.AddPartialToPartial (counters);
1566 protected override string ConvertToString (int att)
1568 EventAttributes ea = (EventAttributes) att;
1569 return ea.ToString ();
1572 public override string GroupName {
1573 get { return "events"; }
1576 public override string Name {
1577 get { return "event"; }
1581 class XMLMethods : XMLMember
1583 Hashtable returnTypes;
1584 Hashtable parameters;
1585 Hashtable genericConstraints;
1586 Hashtable signatureFlags;
1597 protected override void LoadExtraData (string name, XmlNode node)
1599 XmlAttribute xatt = node.Attributes ["returntype"];
1601 if (returnTypes == null)
1602 returnTypes = new Hashtable ();
1604 returnTypes [name] = xatt.Value;
1607 SignatureFlags flags = SignatureFlags.None;
1608 if (((XmlElement) node).GetAttribute ("abstract") == "true")
1609 flags |= SignatureFlags.Abstract;
1610 if (((XmlElement) node).GetAttribute ("static") == "true")
1611 flags |= SignatureFlags.Static;
1612 if (((XmlElement) node).GetAttribute ("virtual") == "true")
1613 flags |= SignatureFlags.Virtual;
1614 if (flags != SignatureFlags.None) {
1615 if (signatureFlags == null)
1616 signatureFlags = new Hashtable ();
1617 signatureFlags [name] = flags;
1620 XmlNode parametersNode = node.SelectSingleNode ("parameters");
1621 if (parametersNode != null) {
1622 if (parameters == null)
1623 parameters = new Hashtable ();
1625 XMLParameters parms = new XMLParameters ();
1626 parms.LoadData (parametersNode);
1628 parameters[name] = parms;
1631 XmlNode genericNode = node.SelectSingleNode ("generic-method-constraints");
1632 if (genericNode != null) {
1633 if (genericConstraints == null)
1634 genericConstraints = new Hashtable ();
1635 XMLGenericMethodConstraints csts = new XMLGenericMethodConstraints ();
1636 csts.LoadData (genericNode);
1637 genericConstraints [name] = csts;
1640 base.LoadExtraData (name, node);
1643 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1645 // create backup of actual counters
1646 Counters copy = counters;
1647 // initialize counters for current method
1648 counters = new Counters();
1651 base.CompareToInner(name, parent, other);
1652 XMLMethods methods = (XMLMethods) other;
1654 SignatureFlags flags = signatureFlags != null &&
1655 signatureFlags.ContainsKey (name) ?
1656 (SignatureFlags) signatureFlags [name] :
1657 SignatureFlags.None;
1658 SignatureFlags oflags = methods.signatureFlags != null &&
1659 methods.signatureFlags.ContainsKey (name) ?
1660 (SignatureFlags) methods.signatureFlags [name] :
1661 SignatureFlags.None;
1663 if (flags!= oflags) {
1664 if (flags == SignatureFlags.None)
1665 AddWarning (parent, String.Format ("should not be {0}", oflags));
1666 else if (oflags == SignatureFlags.None)
1667 AddWarning (parent, String.Format ("should be {0}", flags));
1669 AddWarning (parent, String.Format ("{0} and should be {1}", oflags, flags));
1672 if (returnTypes != null) {
1673 string rtype = returnTypes[name] as string;
1674 string ortype = null;
1675 if (methods.returnTypes != null)
1676 ortype = methods.returnTypes[name] as string;
1678 if (rtype != ortype)
1679 AddWarning (parent, "Return type is {0} and should be {1}", ortype, rtype);
1682 if (parameters != null) {
1683 XMLParameters parms = parameters[name] as XMLParameters;
1684 parms.CompareTo (document, parent, methods.parameters[name]);
1685 counters.AddPartialToPartial (parms.Counters);
1688 // output counter attributes in result document
1689 AddCountersAttributes(parent);
1691 // add temporary counters to actual counters
1692 copy.AddPartialToPartial(counters);
1693 // restore backup of actual counters
1698 protected override string ConvertToString (int att)
1700 MethodAttributes ma = (MethodAttributes) att;
1701 // ignore ReservedMasks
1702 ma &= ~ MethodAttributes.ReservedMask;
1703 ma &= ~ MethodAttributes.VtableLayoutMask;
1704 if ((ma & MethodAttributes.FamORAssem) != 0)
1705 ma = (ma & ~ MethodAttributes.FamORAssem) | MethodAttributes.Family;
1707 // ignore the HasSecurity attribute for now
1708 if ((ma & MethodAttributes.HasSecurity) != 0)
1709 ma = (MethodAttributes) (att - (int) MethodAttributes.HasSecurity);
1711 // ignore the RequireSecObject attribute for now
1712 if ((ma & MethodAttributes.RequireSecObject) != 0)
1713 ma = (MethodAttributes) (att - (int) MethodAttributes.RequireSecObject);
1715 // we don't care if the implementation is forwarded through PInvoke
1716 if ((ma & MethodAttributes.PinvokeImpl) != 0)
1717 ma = (MethodAttributes) (att - (int) MethodAttributes.PinvokeImpl);
1719 return ma.ToString ();
1722 public override string GroupName {
1723 get { return "methods"; }
1726 public override string Name {
1727 get { return "method"; }
1731 class XMLConstructors : XMLMethods
1733 public override string GroupName {
1734 get { return "constructors"; }
1737 public override string Name {
1738 get { return "constructor"; }
1742 class XmlNodeComparer : IComparer
1744 public static XmlNodeComparer Default = new XmlNodeComparer ();
1746 public int Compare (object a, object b)
1748 XmlNode na = (XmlNode) a;
1749 XmlNode nb = (XmlNode) b;
1750 return String.Compare (na.Attributes ["name"].Value, nb.Attributes ["name"].Value);