**** Merged from MCS ****
[mono-project.git] / mcs / tools / corcompare / mono-api-diff.cs
blob665e52cb3db7039129358a6574d2c98cf5507d0b
1 //
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.
4 //
5 // Authors:
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //
8 // (C) 2003 Novell, Inc (http://www.novell.com)
9 //
11 using System;
12 using System.Collections;
13 using System.IO;
14 using System.Reflection;
15 using System.Text;
16 using System.Xml;
18 namespace Mono.AssemblyCompare
20 class Driver
22 static int Main (string [] args)
24 if (args.Length != 2)
25 return 1;
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;
33 doc.WriteTo (writer);
35 return 0;
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 ();
45 try {
46 result.LoadData (node);
47 } catch (Exception e) {
48 Console.Error.WriteLine ("Error loading {0}: {1}\n{2}", file, e.Message, e);
49 Environment.Exit (1);
52 return result;
56 class Counters
58 public int Present;
59 public int PresentTotal;
60 public int Missing;
61 public int MissingTotal;
62 public int Todo;
63 public int TodoTotal;
65 public int Extra;
66 public int ExtraTotal;
67 public int Warning;
68 public int WarningTotal;
69 public int ErrorTotal;
71 public Counters ()
75 public void AddPartialToPartial (Counters other)
77 Present += other.Present;
78 Extra += other.Extra;
79 Missing += other.Missing;
81 Todo += other.Todo;
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;
118 public int Total {
119 get { return Present + Missing; }
122 public int AbsTotal {
123 get { return PresentTotal + MissingTotal; }
126 public int Ok {
127 get { return Present - Todo; }
130 public int OkTotal {
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);
148 sw.WriteLine ("--");
149 return sw.GetStringBuilder ().ToString ();
153 abstract class XMLData
155 protected XmlDocument document;
156 protected Counters counters;
157 bool haveWarnings;
159 public XMLData ()
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);
174 list.Add (data);
177 return (object []) list.ToArray (type);
180 protected void AddAttribute (XmlNode node, string name, string value)
182 XmlAttribute attr = document.CreateAttribute (name);
183 attr.Value = value;
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 ());
208 if (counters.Ok > 0)
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)
252 counters.Warning++;
253 haveWarnings = true;
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)
284 if (node == null)
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);
296 LoadExtraData (key, n);
301 protected virtual bool CheckIfAdd (string value, XmlNode node)
303 return true;
306 protected virtual void LoadExtraData (string name, XmlNode node)
310 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
312 this.document = doc;
313 if (group == null)
314 group = doc.CreateElement (GroupName, null);
316 Hashtable okeys = null;
317 if (other != null && ((XMLNameGroup) other).keys != null) {
318 okeys = ((XMLNameGroup) other).keys;
321 XmlNode node = null;
322 bool onull = (okeys == null);
323 if (keys != null) {
324 foreach (DictionaryEntry entry in keys) {
325 node = doc.CreateElement (Name, null);
326 group.AppendChild (node);
327 string key = (string) entry.Key;
328 string name = (string) entry.Value;
329 AddAttribute (node, "name", name);
331 if (!onull && HasKey (key, okeys)) {
332 CompareToInner (key, node, (XMLNameGroup) other);
333 okeys.Remove (key);
334 counters.Present++;
335 } else {
336 AddAttribute (node, "presence", "missing");
337 counters.Missing++;
342 if (!onull && okeys.Count != 0) {
343 foreach (string value in okeys.Values) {
344 node = doc.CreateElement (Name, null);
345 AddAttribute (node, "name", (string) value);
346 AddAttribute (node, "presence", "extra");
347 group.AppendChild (node);
348 counters.Extra++;
352 if (group.HasChildNodes)
353 parent.AppendChild (group);
356 protected virtual void CompareToInner (string name, XmlNode node, XMLNameGroup other)
360 public virtual string GetNodeKey (string name, XmlNode node)
362 return name;
365 public virtual bool HasKey (string key, Hashtable other)
367 return other.ContainsKey (key);
370 public abstract string GroupName { get; }
371 public abstract string Name { get; }
374 class XMLAssembly : XMLData
376 XMLAttributes attributes;
377 XMLNamespace [] namespaces;
378 string name;
379 string version;
381 public override void LoadData (XmlNode node)
383 if (node == null)
384 throw new ArgumentNullException ("node");
386 name = node.Attributes ["name"].Value;
387 version = node.Attributes ["version"].Value;
388 XmlNode atts = node.FirstChild;
389 attributes = new XMLAttributes ();
390 if (atts.Name == "attributes") {
391 attributes.LoadData (atts);
392 atts = atts.NextSibling;
395 if (atts == null || atts.Name != "namespaces") {
396 Console.Error.WriteLine ("Warning: no namespaces found!");
397 return;
400 namespaces = (XMLNamespace []) LoadRecursive (atts.ChildNodes, typeof (XMLNamespace));
403 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
405 XMLAssembly assembly = (XMLAssembly) other;
407 XmlNode childA = doc.CreateElement ("assembly", null);
408 AddAttribute (childA, "name", name);
409 AddAttribute (childA, "version", version);
410 if (name != assembly.name)
411 AddWarning (childA, "Assembly names not equal: {0}, {1}", name, assembly.name);
413 if (version != assembly.version)
414 AddWarning (childA, "Assembly version not equal: {0}, {1}", version, assembly.version);
416 parent.AppendChild (childA);
418 attributes.CompareTo (doc, childA, assembly.attributes);
419 counters.AddPartialToPartial (attributes.Counters);
421 CompareNamespaces (childA, assembly.namespaces);
422 if (assembly.attributes != null && assembly.attributes.IsTodo) {
423 counters.Todo++;
424 counters.TodoTotal++;
425 counters.ErrorTotal++;
426 AddAttribute (childA, "error", "todo");
427 if (assembly.attributes.Comment != null)
428 AddAttribute (childA, "comment", assembly.attributes.Comment);
431 AddCountersAttributes (childA);
434 void CompareNamespaces (XmlNode parent, XMLNamespace [] other)
436 ArrayList newNS = new ArrayList ();
437 XmlNode group = document.CreateElement ("namespaces", null);
438 parent.AppendChild (group);
440 Hashtable oh = CreateHash (other);
441 XmlNode node = null;
442 int count = (namespaces == null) ? 0 : namespaces.Length;
443 for (int i = 0; i < count; i++) {
444 XMLNamespace xns = namespaces [i];
446 node = document.CreateElement ("namespace", null);
447 newNS.Add (node);
448 AddAttribute (node, "name", xns.Name);
450 if (oh.ContainsKey (xns.Name)) {
451 int idx = (int) oh [xns.Name];
452 xns.CompareTo (document, node, other [idx]);
453 other [idx] = null;
454 xns.AddCountersAttributes (node);
455 counters.Present++;
456 counters.PresentTotal++;
457 counters.AddPartialToTotal (xns.Counters);
458 } else {
459 AddAttribute (node, "presence", "missing");
460 counters.Missing++;
461 counters.MissingTotal++;
465 if (other != null) {
466 count = other.Length;
467 for (int i = 0; i < count; i++) {
468 XMLNamespace n = other [i];
469 if (n == null)
470 continue;
472 node = document.CreateElement ("namespace", null);
473 newNS.Add (node);
474 AddAttribute (node, "name", n.Name);
475 AddExtra (node);
476 counters.ExtraTotal++;
480 XmlNode [] nodes = (XmlNode []) newNS.ToArray (typeof (XmlNode));
481 Array.Sort (nodes, XmlNodeComparer.Default);
482 foreach (XmlNode nn in nodes)
483 group.AppendChild (nn);
486 static Hashtable CreateHash (XMLNamespace [] other)
488 Hashtable result = new Hashtable ();
489 if (other != null) {
490 int i = 0;
491 foreach (XMLNamespace n in other) {
492 result [n.Name] = i++;
496 return result;
499 public XmlDocument CompareAndGetDocument (XMLAssembly other)
501 XmlDocument doc = new XmlDocument ();
502 this.document = doc;
503 XmlNode parent = doc.CreateElement ("assemblies", null);
504 doc.AppendChild (parent);
506 CompareTo (doc, parent, other);
508 XmlNode decl = doc.CreateXmlDeclaration ("1.0", null, null);
509 doc.InsertBefore (decl, doc.DocumentElement);
511 return doc;
515 class XMLNamespace : XMLData
517 string name;
518 XMLClass [] types;
520 public override void LoadData (XmlNode node)
522 if (node == null)
523 throw new ArgumentNullException ("node");
525 if (node.Name != "namespace")
526 throw new FormatException ("Expecting <namespace>");
528 name = node.Attributes ["name"].Value;
529 XmlNode classes = node.FirstChild;
530 if (classes == null) {
531 Console.Error.WriteLine ("Warning: no classes for {0}", node.Attributes ["name"]);
532 return;
535 if (classes.Name != "classes")
536 throw new FormatException ("Expecting <classes>. Got <" + classes.Name + ">");
538 types = (XMLClass []) LoadRecursive (classes.ChildNodes, typeof (XMLClass));
541 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
543 this.document = doc;
544 XMLNamespace nspace = (XMLNamespace) other;
546 XmlNode childA = doc.CreateElement ("classes", null);
547 parent.AppendChild (childA);
549 CompareTypes (childA, nspace.types);
552 void CompareTypes (XmlNode parent, XMLClass [] other)
554 ArrayList newNodes = new ArrayList ();
555 Hashtable oh = CreateHash (other);
556 XmlNode node = null;
557 int count = (types == null) ? 0 : types.Length;
558 for (int i = 0; i < count; i++) {
559 XMLClass xclass = types [i];
561 node = document.CreateElement ("class", null);
562 newNodes.Add (node);
563 AddAttribute (node, "name", xclass.Name);
564 AddAttribute (node, "type", xclass.Type);
566 if (oh.ContainsKey (xclass.Name)) {
567 int idx = (int) oh [xclass.Name];
568 xclass.CompareTo (document, node, other [idx]);
569 other [idx] = null;
570 counters.AddPartialToPartial (xclass.Counters);
571 } else {
572 AddAttribute (node, "presence", "missing");
573 counters.Missing++;
574 counters.MissingTotal++;
578 if (other != null) {
579 count = other.Length;
580 for (int i = 0; i < count; i++) {
581 XMLClass c = other [i];
582 if (c == null || c.Name.EndsWith ("TODOAttribute"))
583 continue;
585 node = document.CreateElement ("class", null);
586 newNodes.Add (node);
587 AddAttribute (node, "name", c.Name);
588 AddAttribute (node, "type", c.Type);
589 AddExtra (node);
590 counters.Extra++;
591 counters.ExtraTotal++;
595 XmlNode [] nodes = (XmlNode []) newNodes.ToArray (typeof (XmlNode));
596 Array.Sort (nodes, XmlNodeComparer.Default);
597 foreach (XmlNode nn in nodes)
598 parent.AppendChild (nn);
601 static Hashtable CreateHash (XMLClass [] other)
603 Hashtable result = new Hashtable ();
604 if (other != null) {
605 int i = 0;
606 foreach (XMLClass c in other) {
607 result [c.Name] = i++;
611 return result;
614 public string Name {
615 get { return name; }
619 class XMLClass : XMLData
621 string name;
622 string type;
623 string baseName;
624 bool isSealed;
625 bool isSerializable;
626 bool isAbstract;
627 string charSet;
628 string layout;
629 XMLAttributes attributes;
630 XMLInterfaces interfaces;
631 XMLFields fields;
632 XMLConstructors constructors;
633 XMLProperties properties;
634 XMLEvents events;
635 XMLMethods methods;
636 XMLClass [] nested;
638 public override void LoadData (XmlNode node)
640 if (node == null)
641 throw new ArgumentNullException ("node");
643 name = node.Attributes ["name"].Value;
644 type = node.Attributes ["type"].Value;
645 XmlAttribute xatt = node.Attributes ["base"];
646 if (xatt != null)
647 baseName = xatt.Value;
649 xatt = node.Attributes ["sealed"];
650 isSealed = (xatt != null && xatt.Value == "true");
652 xatt = node.Attributes ["abstract"];
653 isAbstract = (xatt != null && xatt.Value == "true");
655 xatt = node.Attributes["serializable"];
656 isSerializable = (xatt != null && xatt.Value == "true");
658 xatt = node.Attributes["charset"];
659 if (xatt != null)
660 charSet = xatt.Value;
662 xatt = node.Attributes["layout"];
663 if (xatt != null)
664 layout = xatt.Value;
666 XmlNode child = node.FirstChild;
667 if (child == null) {
668 // Console.Error.WriteLine ("Empty class {0} {1}", name, type);
669 return;
672 if (child.Name == "attributes") {
673 attributes = new XMLAttributes ();
674 attributes.LoadData (child);
675 child = child.NextSibling;
678 if (child != null && child.Name == "interfaces") {
679 interfaces = new XMLInterfaces ();
680 interfaces.LoadData (child);
681 child = child.NextSibling;
684 if (child != null && child.Name == "fields") {
685 fields = new XMLFields ();
686 fields.LoadData (child);
687 child = child.NextSibling;
690 if (child != null && child.Name == "constructors") {
691 constructors = new XMLConstructors ();
692 constructors.LoadData (child);
693 child = child.NextSibling;
696 if (child != null && child.Name == "properties") {
697 properties = new XMLProperties ();
698 properties.LoadData (child);
699 child = child.NextSibling;
702 if (child != null && child.Name == "events") {
703 events = new XMLEvents ();
704 events.LoadData (child);
705 child = child.NextSibling;
708 if (child != null && child.Name == "methods") {
709 methods = new XMLMethods ();
710 methods.LoadData (child);
711 child = child.NextSibling;
714 if (child == null)
715 return;
717 if (child.Name != "classes") {
718 Console.WriteLine ("name: {0} type: {1} {2}", name, type, child.NodeType);
719 throw new FormatException ("Expecting <classes>. Got <" + child.Name + ">");
722 nested = (XMLClass []) LoadRecursive (child.ChildNodes, typeof (XMLClass));
725 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
727 this.document = doc;
728 XMLClass oclass = (XMLClass) other;
730 if (attributes != null || oclass.attributes != null) {
731 if (attributes == null)
732 attributes = new XMLAttributes ();
734 attributes.CompareTo (doc, parent, oclass.attributes);
735 counters.AddPartialToPartial (attributes.Counters);
736 if (oclass.attributes != null && oclass.attributes.IsTodo) {
737 counters.Todo++;
738 counters.TodoTotal++;
739 counters.ErrorTotal++;
740 AddAttribute (parent, "error", "todo");
741 if (oclass.attributes.Comment != null)
742 AddAttribute (parent, "comment", oclass.attributes.Comment);
746 if (type != oclass.type)
747 AddWarning (parent, "Class type is wrong: {0} != {1}", type, oclass.type);
749 if (baseName != oclass.baseName)
750 AddWarning (parent, "Base class is wrong: {0} != {1}", baseName, oclass.baseName);
752 if (isAbstract != oclass.isAbstract || isSealed != oclass.isSealed) {
753 if ((isAbstract && isSealed) || (!oclass.isAbstract && !oclass.isSealed))
754 AddWarning (parent, "Should {0}be static", isAbstract ? "" : "not ");
755 else if (isAbstract != oclass.isAbstract)
756 AddWarning (parent, "Should {0}be abstract", isAbstract ? "" : "not ");
757 else if (isSealed != oclass.isSealed)
758 AddWarning (parent, "Should {0}be sealed", isSealed ? "" : "not ");
761 if (isSerializable != oclass.isSerializable)
762 AddWarning (parent, "Should {0}be serializable", isSerializable ? "" : "not ");
764 if (charSet != oclass.charSet)
765 AddWarning (parent, "CharSet is wrong: {0} != {1}", charSet, oclass.charSet);
767 if (layout != oclass.layout)
768 AddWarning (parent, "Layout is wrong: {0} != {1}", layout, oclass.layout);
770 if (interfaces != null || oclass.interfaces != null) {
771 if (interfaces == null)
772 interfaces = new XMLInterfaces ();
774 interfaces.CompareTo (doc, parent, oclass.interfaces);
775 counters.AddPartialToPartial (interfaces.Counters);
778 if (fields != null || oclass.fields != null) {
779 if (fields == null)
780 fields = new XMLFields ();
782 fields.CompareTo (doc, parent, oclass.fields);
783 counters.AddPartialToPartial (fields.Counters);
786 if (constructors != null || oclass.constructors != null) {
787 if (constructors == null)
788 constructors = new XMLConstructors ();
790 constructors.CompareTo (doc, parent, oclass.constructors);
791 counters.AddPartialToPartial (constructors.Counters);
794 if (properties != null || oclass.properties != null) {
795 if (properties == null)
796 properties = new XMLProperties ();
798 properties.CompareTo (doc, parent, oclass.properties);
799 counters.AddPartialToPartial (properties.Counters);
802 if (events != null || oclass.events != null) {
803 if (events == null)
804 events = new XMLEvents ();
806 events.CompareTo (doc, parent, oclass.events);
807 counters.AddPartialToPartial (events.Counters);
810 if (methods != null || oclass.methods != null) {
811 if (methods == null)
812 methods = new XMLMethods ();
814 methods.CompareTo (doc, parent, oclass.methods);
815 counters.AddPartialToPartial (methods.Counters);
818 if (nested != null || oclass.nested != null) {
819 XmlNode n = doc.CreateElement ("classes", null);
820 parent.AppendChild (n);
821 CompareTypes (n, oclass.nested);
824 AddCountersAttributes (parent);
827 void CompareTypes (XmlNode parent, XMLClass [] other)
829 ArrayList newNodes = new ArrayList ();
830 Hashtable oh = CreateHash (other);
831 XmlNode node = null;
832 int count = (nested == null) ? 0 : nested.Length;
833 for (int i = 0; i < count; i++) {
834 XMLClass xclass = nested [i];
836 node = document.CreateElement ("nestedclass", null);
837 newNodes.Add (node);
838 AddAttribute (node, "name", xclass.Name);
839 AddAttribute (node, "type", xclass.Type);
841 if (oh.ContainsKey (xclass.Name)) {
842 int idx = (int) oh [xclass.Name];
843 xclass.CompareTo (document, node, other [idx]);
844 other [idx] = null;
845 counters.AddPartialToPartial (xclass.Counters);
846 } else {
847 // TODO: Should I count here?
848 AddAttribute (node, "presence", "missing");
849 counters.Missing++;
850 counters.MissingTotal++;
854 if (other != null) {
855 count = other.Length;
856 for (int i = 0; i < count; i++) {
857 XMLClass c = other [i];
858 if (c == null || c.Name.EndsWith ("TODOAttribute"))
859 continue;
861 node = document.CreateElement ("nestedclass", null);
862 newNodes.Add (node);
863 AddAttribute (node, "name", c.Name);
864 AddExtra (node);
865 counters.Extra++;
866 counters.ExtraTotal++;
870 XmlNode [] nodes = (XmlNode []) newNodes.ToArray (typeof (XmlNode));
871 Array.Sort (nodes, XmlNodeComparer.Default);
872 foreach (XmlNode nn in nodes)
873 parent.AppendChild (nn);
876 static Hashtable CreateHash (XMLClass [] other)
878 Hashtable result = new Hashtable ();
879 if (other != null) {
880 int i = 0;
881 foreach (XMLClass c in other) {
882 result [c.Name] = i++;
886 return result;
889 public string Name {
890 get { return name; }
893 public string Type {
894 get { return type; }
898 class XMLParameter : XMLData
900 string name;
901 string type;
902 string attrib;
903 string direction;
904 bool isUnsafe;
905 bool isOptional;
906 string defaultValue;
908 public override void LoadData (XmlNode node)
910 if (node == null)
911 throw new ArgumentNullException ("node");
913 if (node.Name != "parameter")
914 throw new ArgumentException ("Expecting <parameter>");
916 name = node.Attributes["name"].Value;
917 type = node.Attributes["type"].Value;
918 attrib = node.Attributes["attrib"].Value;
919 if (node.Attributes ["direction"] != null)
920 direction = node.Attributes["direction"].Value;
921 if (node.Attributes["unsafe"] != null)
922 isUnsafe = bool.Parse (node.Attributes["unsafe"].Value);
923 if (node.Attributes["optional"] != null)
924 isOptional = bool.Parse (node.Attributes["optional"].Value);
925 if (node.Attributes["defaultValue"] != null)
926 defaultValue = node.Attributes["defaultValue"].Value;
929 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
931 this.document = doc;
933 XMLParameter oparm = (XMLParameter) other;
935 if (type != oparm.type)
936 AddWarning (parent, "Parameter type is wrong: {0} != {1}", type, oparm.type);
938 if (attrib != oparm.attrib)
939 AddWarning (parent, "Parameter attributes wrong: {0} != {1}", attrib, oparm.attrib);
941 if (direction != oparm.direction)
942 AddWarning (parent, "Parameter direction wrong: {0} != {1}", direction, oparm.direction);
944 if (isUnsafe != oparm.isUnsafe)
945 AddWarning (parent, "Parameter unsafe wrong: {0} != {1}", isUnsafe, oparm.isUnsafe);
947 if (isOptional != oparm.isOptional)
948 AddWarning (parent, "Parameter optional wrong: {0} != {1}", isOptional, oparm.isOptional);
950 if (defaultValue != oparm.defaultValue)
951 AddWarning (parent, "Parameter default value wrong: {0} != {1}", defaultValue, oparm.defaultValue);
954 public string Name {
955 get { return name; }
959 class XMLAttributes : XMLNameGroup
961 bool isTodo;
962 string comment;
964 protected override bool CheckIfAdd (string value, XmlNode node)
966 if (value.EndsWith ("TODOAttribute")) {
967 isTodo = true;
968 XmlAttribute att = node.Attributes ["comment"];
969 if (att != null)
970 comment = att.Value;
972 return false;
975 return true;
978 public override string GetNodeKey (string name, XmlNode node)
980 string target = string.Empty;
981 if (node.Attributes["target"] != null)
982 target = node.Attributes["target"].Value;
983 int i = 0;
984 while (keys.ContainsKey (name)) {
985 name = String.Format ("{0} [{1}]:{1}", name, target, i++);
988 return name;
991 public override string GroupName {
992 get { return "attributes"; }
995 public override string Name {
996 get { return "attribute"; }
999 public bool IsTodo {
1000 get { return isTodo; }
1003 public string Comment {
1004 get { return comment; }
1008 class XMLInterfaces : XMLNameGroup
1010 public override string GroupName {
1011 get { return "interfaces"; }
1014 public override string Name {
1015 get { return "interface"; }
1019 abstract class XMLMember : XMLNameGroup
1021 Hashtable attributeMap;
1022 Hashtable access = new Hashtable ();
1024 protected override void LoadExtraData (string name, XmlNode node)
1026 XmlAttribute xatt = node.Attributes ["attrib"];
1027 if (xatt != null)
1028 access [name] = xatt.Value;
1030 XmlNode orig = node;
1032 node = node.FirstChild;
1033 while (node != null) {
1034 if (node != null && node.Name == "attributes") {
1035 XMLAttributes a = new XMLAttributes ();
1036 a.LoadData (node);
1037 if (attributeMap == null)
1038 attributeMap = new Hashtable ();
1040 attributeMap [name] = a;
1041 break;
1043 node = node.NextSibling;
1046 base.LoadExtraData (name, orig);
1049 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1051 base.CompareToInner (name, parent, other);
1052 XMLMember mb = other as XMLMember;
1053 XMLAttributes att = null;
1054 XMLAttributes oatt = null;
1055 if (attributeMap != null)
1056 att = attributeMap [name] as XMLAttributes;
1058 if (mb != null && mb.attributeMap != null)
1059 oatt = mb.attributeMap [name] as XMLAttributes;
1061 if (att != null || oatt != null) {
1062 if (att == null)
1063 att = new XMLAttributes ();
1065 att.CompareTo (document, parent, oatt);
1066 counters.AddPartialToPartial(att.Counters);
1067 if (oatt != null && oatt.IsTodo) {
1068 counters.Todo++;
1069 counters.ErrorTotal++;
1070 AddAttribute (parent, "error", "todo");
1071 if (oatt.Comment != null)
1072 AddAttribute (parent, "comment", oatt.Comment);
1076 if (!CheckAttributes)
1077 return;
1079 XMLMember member = (XMLMember) other;
1080 string acc = access [name] as string;
1081 if (acc == null)
1082 return;
1084 string oacc = null;
1085 if (member.access != null)
1086 oacc = member.access [name] as string;
1088 string accName = ConvertToString (Int32.Parse (acc));
1089 string oaccName = "";
1090 if (oacc != null)
1091 oaccName = ConvertToString (Int32.Parse (oacc));
1093 if (accName != oaccName)
1094 AddWarning (parent, "Incorrect attributes: '{0}' != '{1}'", accName, oaccName);
1097 protected virtual string ConvertToString (int att)
1099 return null;
1102 protected virtual bool CheckAttributes {
1103 get {
1104 return true;
1109 class XMLFields : XMLMember
1111 Hashtable fieldTypes;
1112 Hashtable fieldValues;
1114 protected override void LoadExtraData (string name, XmlNode node)
1116 XmlAttribute xatt = node.Attributes ["fieldtype"];
1117 if (xatt != null) {
1118 if (fieldTypes == null)
1119 fieldTypes = new Hashtable ();
1121 fieldTypes [name] = xatt.Value;
1124 xatt = node.Attributes ["value"];
1125 if (xatt != null) {
1126 if (fieldValues == null)
1127 fieldValues = new Hashtable ();
1129 fieldValues[name] = xatt.Value;
1132 base.LoadExtraData (name, node);
1135 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1137 base.CompareToInner (name, parent, other);
1138 XMLFields fields = (XMLFields) other;
1139 if (fieldTypes != null) {
1140 string ftype = fieldTypes [name] as string;
1141 string oftype = null;
1142 if (fields.fieldTypes != null)
1143 oftype = fields.fieldTypes [name] as string;
1145 if (ftype != oftype)
1146 AddWarning (parent, "Field type is {0} and should be {1}", oftype, ftype);
1148 if (fieldValues != null) {
1149 string fvalue = fieldValues [name] as string;
1150 string ofvalue = null;
1151 if (fields.fieldValues != null)
1152 ofvalue = fields.fieldValues [name] as string;
1154 if (fvalue != ofvalue)
1155 AddWarning (parent, "Field value is {0} and should be {1}", ofvalue, fvalue);
1159 protected override string ConvertToString (int att)
1161 FieldAttributes fa = (FieldAttributes) att;
1162 return fa.ToString ();
1165 protected override bool CheckAttributes {
1166 get {
1167 // FIXME: set this to true once bugs #60086 and
1168 // #60090 are fixed
1169 return false;
1173 public override string GroupName {
1174 get { return "fields"; }
1177 public override string Name {
1178 get { return "field"; }
1182 class XMLParameters : XMLNameGroup
1184 public override void LoadData (XmlNode node)
1186 if (node == null)
1187 throw new ArgumentNullException ("node");
1189 if (node.Name != GroupName)
1190 throw new FormatException (String.Format ("Expecting <{0}>", GroupName));
1192 keys = new Hashtable ();
1193 foreach (XmlNode n in node.ChildNodes) {
1194 string name = n.Attributes["name"].Value;
1195 string key = GetNodeKey (name, n);
1196 XMLParameter parm = new XMLParameter ();
1197 parm.LoadData (n);
1198 keys.Add (key, parm);
1199 LoadExtraData (key, n);
1203 public override string GroupName {
1204 get {
1205 return "parameters";
1209 public override string Name {
1210 get {
1211 return "parameter";
1215 public override string GetNodeKey (string name, XmlNode node)
1217 return node.Attributes["position"].Value;
1220 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
1222 this.document = doc;
1223 if (group == null)
1224 group = doc.CreateElement (GroupName, null);
1226 Hashtable okeys = null;
1227 if (other != null && ((XMLParameters) other).keys != null) {
1228 okeys = ((XMLParameters) other).keys;
1231 XmlNode node = null;
1232 bool onull = (okeys == null);
1233 if (keys != null) {
1234 foreach (DictionaryEntry entry in keys) {
1235 node = doc.CreateElement (Name, null);
1236 group.AppendChild (node);
1237 string key = (string) entry.Key;
1238 XMLParameter parm = (XMLParameter) entry.Value;
1239 AddAttribute (node, "name", parm.Name);
1241 if (!onull && HasKey (key, okeys)) {
1242 parm.CompareTo (document, node, okeys[key]);
1243 counters.AddPartialToPartial (parm.Counters);
1244 okeys.Remove (key);
1245 counters.Present++;
1246 } else {
1247 AddAttribute (node, "presence", "missing");
1248 counters.Missing++;
1253 if (!onull && okeys.Count != 0) {
1254 foreach (XMLParameter value in okeys.Values) {
1255 node = doc.CreateElement (Name, null);
1256 AddAttribute (node, "name", value.Name);
1257 AddAttribute (node, "presence", "extra");
1258 group.AppendChild (node);
1259 counters.Extra++;
1263 if (group.HasChildNodes)
1264 parent.AppendChild (group);
1268 class XMLProperties : XMLMember
1270 Hashtable nameToMethod = new Hashtable ();
1272 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1274 Counters copy = counters;
1275 counters = new Counters();
1277 XMLProperties oprop = other as XMLProperties;
1278 if (oprop != null) {
1279 XMLMethods m = nameToMethod [name] as XMLMethods;
1280 XMLMethods om = oprop.nameToMethod [name] as XMLMethods;
1281 if (m != null || om != null) {
1282 if (m == null)
1283 m = new XMLMethods ();
1285 m.CompareTo(document, parent, om);
1286 counters.AddPartialToPartial(m.Counters);
1290 base.CompareToInner (name, parent, other);
1291 AddCountersAttributes(parent);
1293 copy.AddPartialToPartial(counters);
1294 counters = copy;
1297 protected override void LoadExtraData (string name, XmlNode node)
1299 XmlNode orig = node;
1300 node = node.FirstChild;
1301 while (node != null) {
1302 if (node != null && node.Name == "methods") {
1303 XMLMethods m = new XMLMethods ();
1304 XmlNode parent = node.ParentNode;
1305 string key = GetNodeKey (name, parent);
1306 m.LoadData (node);
1307 nameToMethod [key] = m;
1308 break;
1310 node = node.NextSibling;
1313 base.LoadExtraData (name, orig);
1316 public override string GetNodeKey (string name, XmlNode node)
1318 XmlAttributeCollection atts = node.Attributes;
1319 return String.Format ("{0}:{1}:{2}", atts ["name"].Value,
1320 atts ["ptype"].Value,
1321 atts ["params"].Value);
1324 public override string GroupName {
1325 get { return "properties"; }
1328 public override string Name {
1329 get { return "property"; }
1333 class XMLEvents : XMLMember
1335 Hashtable eventTypes;
1337 protected override void LoadExtraData (string name, XmlNode node)
1339 XmlAttribute xatt = node.Attributes ["eventtype"];
1340 if (xatt != null) {
1341 if (eventTypes == null)
1342 eventTypes = new Hashtable ();
1344 eventTypes [name] = xatt.Value;
1347 base.LoadExtraData (name, node);
1350 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1352 Counters copy = counters;
1353 counters = new Counters ();
1355 try {
1356 base.CompareToInner (name, parent, other);
1357 AddCountersAttributes (parent);
1358 if (eventTypes == null)
1359 return;
1361 XMLEvents evt = (XMLEvents) other;
1362 string etype = eventTypes [name] as string;
1363 string oetype = null;
1364 if (evt.eventTypes != null)
1365 oetype = evt.eventTypes [name] as string;
1367 if (etype != oetype)
1368 AddWarning (parent, "Event type is {0} and should be {1}", oetype, etype);
1369 } finally {
1370 AddCountersAttributes (parent);
1371 copy.AddPartialToPartial (counters);
1372 counters = copy;
1376 protected override string ConvertToString (int att)
1378 EventAttributes ea = (EventAttributes) att;
1379 return ea.ToString ();
1382 public override string GroupName {
1383 get { return "events"; }
1386 public override string Name {
1387 get { return "event"; }
1391 class XMLMethods : XMLMember
1393 Hashtable returnTypes;
1394 Hashtable parameters;
1396 protected override void LoadExtraData (string name, XmlNode node)
1398 XmlAttribute xatt = node.Attributes ["returntype"];
1399 if (xatt != null) {
1400 if (returnTypes == null)
1401 returnTypes = new Hashtable ();
1403 returnTypes [name] = xatt.Value;
1406 XmlNode parametersNode = node.SelectSingleNode ("parameters");
1407 if (parametersNode != null) {
1408 if (parameters == null)
1409 parameters = new Hashtable ();
1411 XMLParameters parms = new XMLParameters ();
1412 parms.LoadData (parametersNode);
1414 parameters[name] = parms;
1417 base.LoadExtraData (name, node);
1420 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1422 // create backup of actual counters
1423 Counters copy = counters;
1424 // initialize counters for current method
1425 counters = new Counters();
1427 try {
1428 base.CompareToInner(name, parent, other);
1429 XMLMethods methods = (XMLMethods) other;
1430 if (returnTypes != null) {
1431 string rtype = returnTypes[name] as string;
1432 string ortype = null;
1433 if (methods.returnTypes != null)
1434 ortype = methods.returnTypes[name] as string;
1436 if (rtype != ortype)
1437 AddWarning (parent, "Return type is {0} and should be {1}", ortype, rtype);
1440 if (parameters != null) {
1441 XMLParameters parms = parameters[name] as XMLParameters;
1442 parms.CompareTo (document, parent, methods.parameters[name]);
1443 counters.AddPartialToPartial (parms.Counters);
1445 } finally {
1446 // output counter attributes in result document
1447 AddCountersAttributes(parent);
1449 // add temporary counters to actual counters
1450 copy.AddPartialToPartial(counters);
1451 // restore backup of actual counters
1452 counters = copy;
1456 protected override string ConvertToString (int att)
1458 MethodAttributes ma = (MethodAttributes) att;
1459 // ignore the HasSecurity attribute for now
1460 if ((ma & MethodAttributes.HasSecurity) != 0)
1461 ma = (MethodAttributes) (att - (int) MethodAttributes.HasSecurity);
1463 // ignore the RequireSecObject attribute for now
1464 if ((ma & MethodAttributes.RequireSecObject) != 0)
1465 ma = (MethodAttributes) (att - (int) MethodAttributes.RequireSecObject);
1467 // we don't care if the implementation is forwarded through PInvoke
1468 if ((ma & MethodAttributes.PinvokeImpl) != 0)
1469 ma = (MethodAttributes) (att - (int) MethodAttributes.PinvokeImpl);
1471 return ma.ToString ();
1474 protected override bool CheckAttributes {
1475 get {
1476 // FIXME: set this to true once bugs #60086 and
1477 // #60090 are fixed
1478 return false;
1482 public override string GroupName {
1483 get { return "methods"; }
1486 public override string Name {
1487 get { return "method"; }
1491 class XMLConstructors : XMLMethods
1493 public override string GroupName {
1494 get { return "constructors"; }
1497 public override string Name {
1498 get { return "constructor"; }
1502 class XmlNodeComparer : IComparer
1504 public static XmlNodeComparer Default = new XmlNodeComparer ();
1506 public int Compare (object a, object b)
1508 XmlNode na = (XmlNode) a;
1509 XmlNode nb = (XmlNode) b;
1510 return String.Compare (na.Attributes ["name"].Value, nb.Attributes ["name"].Value);