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)
\r
7 // Marek Safar (marek.safar@gmail.com)
9 // (C) 2003 Novell, Inc (http://www.novell.com)
13 using System.Collections;
15 using System.Reflection;
19 namespace Mono.AssemblyCompare
23 static int Main (string [] args)
28 XMLAssembly ms = CreateXMLAssembly (args [0]);
29 XMLAssembly mono = CreateXMLAssembly (args [1]);
30 XmlDocument doc = ms.CompareAndGetDocument (mono);
32 XmlTextWriter writer = new XmlTextWriter (Console.Out);
33 writer.Formatting = Formatting.Indented;
39 static XMLAssembly CreateXMLAssembly (string file)
41 XmlDocument doc = new XmlDocument ();
42 doc.Load (File.OpenRead (file));
44 XmlNode node = doc.SelectSingleNode ("/assemblies/assembly");
45 XMLAssembly result = new XMLAssembly ();
47 result.LoadData (node);
48 } catch (Exception e) {
49 Console.Error.WriteLine ("Error loading {0}: {1}\n{2}", file, e.Message, e);
60 public int PresentTotal;
62 public int MissingTotal;
67 public int ExtraTotal;
69 public int WarningTotal;
70 public int ErrorTotal;
76 public void AddPartialToPartial (Counters other)
78 Present += other.Present;
80 Missing += other.Missing;
83 Warning += other.Warning;
84 AddPartialToTotal (other);
87 public void AddPartialToTotal (Counters other)
89 PresentTotal += other.Present;
90 ExtraTotal += other.Extra;
91 MissingTotal += other.Missing;
93 TodoTotal += other.Todo;
94 WarningTotal += other.Warning;
97 public void AddTotalToPartial (Counters other)
99 Present += other.PresentTotal;
100 Extra += other.ExtraTotal;
101 Missing += other.MissingTotal;
103 Todo += other.TodoTotal;
104 Warning += other.WarningTotal;
105 AddTotalToTotal (other);
108 public void AddTotalToTotal (Counters other)
110 PresentTotal += other.PresentTotal;
111 ExtraTotal += other.ExtraTotal;
112 MissingTotal += other.MissingTotal;
114 TodoTotal += other.TodoTotal;
115 WarningTotal += other.WarningTotal;
116 ErrorTotal += other.ErrorTotal;
120 get { return Present + Missing; }
123 public int AbsTotal {
124 get { return PresentTotal + MissingTotal; }
128 get { return Present - Todo; }
132 get { return PresentTotal - TodoTotal - ErrorTotal; }
135 public override string ToString ()
137 StringWriter sw = new StringWriter ();
138 sw.WriteLine ("Present: {0}", Present);
139 sw.WriteLine ("PresentTotal: {0}", PresentTotal);
140 sw.WriteLine ("Missing: {0}", Missing);
141 sw.WriteLine ("MissingTotal: {0}", MissingTotal);
142 sw.WriteLine ("Todo: {0}", Todo);
143 sw.WriteLine ("TodoTotal: {0}", TodoTotal);
144 sw.WriteLine ("Extra: {0}", Extra);
145 sw.WriteLine ("ExtraTotal: {0}", ExtraTotal);
146 sw.WriteLine ("Warning: {0}", Warning);
147 sw.WriteLine ("WarningTotal: {0}", WarningTotal);
148 sw.WriteLine ("ErrorTotal: {0}", ErrorTotal);
150 return sw.GetStringBuilder ().ToString ();
154 abstract class XMLData
156 protected XmlDocument document;
157 protected Counters counters;
162 counters = new Counters ();
165 public virtual void LoadData (XmlNode node)
169 protected object [] LoadRecursive (XmlNodeList nodeList, Type type)
171 ArrayList list = new ArrayList ();
172 foreach (XmlNode node in nodeList) {
173 XMLData data = (XMLData) Activator.CreateInstance (type);
174 data.LoadData (node);
178 return (object []) list.ToArray (type);
181 protected void AddAttribute (XmlNode node, string name, string value)
183 XmlAttribute attr = document.CreateAttribute (name);
185 node.Attributes.Append (attr);
188 protected void AddExtra (XmlNode node)
190 //TODO: count all the subnodes?
191 AddAttribute (node, "presence", "extra");
192 AddAttribute (node, "ok", "1");
193 AddAttribute (node, "ok_total", "1");
194 AddAttribute (node, "extra", "1");
195 AddAttribute (node, "extra_total", "1");
198 public void AddCountersAttributes (XmlNode node)
200 if (counters.Missing > 0)
201 AddAttribute (node, "missing", counters.Missing.ToString ());
203 if (counters.Present > 0)
204 AddAttribute (node, "present", counters.Present.ToString ());
206 if (counters.Extra > 0)
207 AddAttribute (node, "extra", counters.Extra.ToString ());
210 AddAttribute (node, "ok", counters.Ok.ToString ());
212 if (counters.Total > 0) {
213 int percent = (100 * counters.Ok / counters.Total);
214 AddAttribute (node, "complete", percent.ToString ());
217 if (counters.Todo > 0)
218 AddAttribute (node, "todo", counters.Todo.ToString ());
220 if (counters.Warning > 0)
221 AddAttribute (node, "warning", counters.Warning.ToString ());
223 if (counters.MissingTotal > 0)
224 AddAttribute (node, "missing_total", counters.MissingTotal.ToString ());
226 if (counters.PresentTotal > 0)
227 AddAttribute (node, "present_total", counters.PresentTotal.ToString ());
229 if (counters.ExtraTotal > 0)
230 AddAttribute (node, "extra_total", counters.ExtraTotal.ToString ());
232 if (counters.OkTotal > 0)
233 AddAttribute (node, "ok_total", counters.OkTotal.ToString ());
235 if (counters.AbsTotal > 0) {
236 int percent = (100 * counters.OkTotal / counters.AbsTotal);
237 AddAttribute (node, "complete_total", percent.ToString ());
240 if (counters.TodoTotal > 0) {
241 AddAttribute (node, "todo_total", counters.TodoTotal.ToString ());
242 //TODO: should be different on error. check error cases in corcompare.
243 AddAttribute (node, "error_total", counters.Todo.ToString ());
246 if (counters.WarningTotal > 0)
247 AddAttribute (node, "warning_total", counters.WarningTotal.ToString ());
251 protected void AddWarning (XmlNode parent, string fmt, params object [] args)
255 XmlNode warnings = parent.SelectSingleNode ("warnings");
256 if (warnings == null) {
257 warnings = document.CreateElement ("warnings", null);
258 parent.AppendChild (warnings);
261 AddAttribute (parent, "error", "warning");
262 XmlNode warning = document.CreateElement ("warning", null);
263 AddAttribute (warning, "text", String.Format (fmt, args));
264 warnings.AppendChild (warning);
267 public bool HaveWarnings {
268 get { return haveWarnings; }
271 public Counters Counters {
272 get { return counters; }
275 public abstract void CompareTo (XmlDocument doc, XmlNode parent, object other);
278 abstract class XMLNameGroup : XMLData
280 protected XmlNode group;
281 protected Hashtable keys;
283 public override void LoadData (XmlNode node)
286 throw new ArgumentNullException ("node");
288 if (node.Name != GroupName)
289 throw new FormatException (String.Format ("Expecting <{0}>", GroupName));
291 keys = new Hashtable ();
292 foreach (XmlNode n in node.ChildNodes) {
293 string name = n.Attributes ["name"].Value;
294 if (CheckIfAdd (name, n)) {
295 string key = GetNodeKey (name, n);
296 //keys.Add (key, name);
298 LoadExtraData (key, n);
303 protected virtual bool CheckIfAdd (string value, XmlNode node)
308 protected virtual void LoadExtraData (string name, XmlNode node)
312 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
316 group = doc.CreateElement (GroupName, null);
318 Hashtable okeys = null;
319 if (other != null && ((XMLNameGroup) other).keys != null) {
320 okeys = ((XMLNameGroup) other).keys;
324 bool onull = (okeys == null);
326 foreach (DictionaryEntry entry in keys) {
327 node = doc.CreateElement (Name, null);
328 group.AppendChild (node);
329 string key = (string) entry.Key;
330 string name = (string) entry.Value;
331 AddAttribute (node, "name", name);
333 if (!onull && HasKey (key, okeys)) {
334 CompareToInner (key, node, (XMLNameGroup) other);
338 AddAttribute (node, "presence", "missing");
344 if (!onull && okeys.Count != 0) {
345 foreach (string value in okeys.Values) {
346 node = doc.CreateElement (Name, null);
347 AddAttribute (node, "name", (string) value);
348 AddAttribute (node, "presence", "extra");
349 group.AppendChild (node);
354 if (group.HasChildNodes)
355 parent.AppendChild (group);
358 protected virtual void CompareToInner (string name, XmlNode node, XMLNameGroup other)
362 public virtual string GetNodeKey (string name, XmlNode node)
367 public virtual bool HasKey (string key, Hashtable other)
369 return other.ContainsKey (key);
372 public abstract string GroupName { get; }
373 public abstract string Name { get; }
376 class XMLAssembly : XMLData
378 XMLAttributes attributes;
379 XMLNamespace [] namespaces;
383 public override void LoadData (XmlNode node)
386 throw new ArgumentNullException ("node");
388 name = node.Attributes ["name"].Value;
389 version = node.Attributes ["version"].Value;
390 XmlNode atts = node.FirstChild;
391 attributes = new XMLAttributes ();
392 if (atts.Name == "attributes") {
393 attributes.LoadData (atts);
394 atts = atts.NextSibling;
397 if (atts == null || atts.Name != "namespaces") {
398 Console.Error.WriteLine ("Warning: no namespaces found!");
402 namespaces = (XMLNamespace []) LoadRecursive (atts.ChildNodes, typeof (XMLNamespace));
405 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
407 XMLAssembly assembly = (XMLAssembly) other;
409 XmlNode childA = doc.CreateElement ("assembly", null);
410 AddAttribute (childA, "name", name);
411 AddAttribute (childA, "version", version);
412 if (name != assembly.name)
413 AddWarning (childA, "Assembly names not equal: {0}, {1}", name, assembly.name);
415 if (version != assembly.version)
416 AddWarning (childA, "Assembly version not equal: {0}, {1}", version, assembly.version);
418 parent.AppendChild (childA);
420 attributes.CompareTo (doc, childA, assembly.attributes);
421 counters.AddPartialToPartial (attributes.Counters);
423 CompareNamespaces (childA, assembly.namespaces);
424 if (assembly.attributes != null && assembly.attributes.IsTodo) {
426 counters.TodoTotal++;
427 counters.ErrorTotal++;
428 AddAttribute (childA, "error", "todo");
429 if (assembly.attributes.Comment != null)
430 AddAttribute (childA, "comment", assembly.attributes.Comment);
433 AddCountersAttributes (childA);
436 void CompareNamespaces (XmlNode parent, XMLNamespace [] other)
438 ArrayList newNS = new ArrayList ();
439 XmlNode group = document.CreateElement ("namespaces", null);
440 parent.AppendChild (group);
442 Hashtable oh = CreateHash (other);
444 int count = (namespaces == null) ? 0 : namespaces.Length;
445 for (int i = 0; i < count; i++) {
446 XMLNamespace xns = namespaces [i];
448 node = document.CreateElement ("namespace", null);
450 AddAttribute (node, "name", xns.Name);
452 if (oh.ContainsKey (xns.Name)) {
453 int idx = (int) oh [xns.Name];
454 xns.CompareTo (document, node, other [idx]);
456 xns.AddCountersAttributes (node);
458 counters.PresentTotal++;
459 counters.AddPartialToTotal (xns.Counters);
461 AddAttribute (node, "presence", "missing");
463 counters.MissingTotal++;
468 count = other.Length;
469 for (int i = 0; i < count; i++) {
470 XMLNamespace n = other [i];
474 node = document.CreateElement ("namespace", null);
476 AddAttribute (node, "name", n.Name);
478 counters.ExtraTotal++;
482 XmlNode [] nodes = (XmlNode []) newNS.ToArray (typeof (XmlNode));
483 Array.Sort (nodes, XmlNodeComparer.Default);
484 foreach (XmlNode nn in nodes)
485 group.AppendChild (nn);
488 static Hashtable CreateHash (XMLNamespace [] other)
490 Hashtable result = new Hashtable ();
493 foreach (XMLNamespace n in other) {
494 result [n.Name] = i++;
501 public XmlDocument CompareAndGetDocument (XMLAssembly other)
503 XmlDocument doc = new XmlDocument ();
505 XmlNode parent = doc.CreateElement ("assemblies", null);
506 doc.AppendChild (parent);
508 CompareTo (doc, parent, other);
510 XmlNode decl = doc.CreateXmlDeclaration ("1.0", null, null);
511 doc.InsertBefore (decl, doc.DocumentElement);
517 class XMLNamespace : XMLData
522 public override void LoadData (XmlNode node)
525 throw new ArgumentNullException ("node");
527 if (node.Name != "namespace")
528 throw new FormatException ("Expecting <namespace>");
530 name = node.Attributes ["name"].Value;
531 XmlNode classes = node.FirstChild;
532 if (classes == null) {
533 Console.Error.WriteLine ("Warning: no classes for {0}", node.Attributes ["name"]);
537 if (classes.Name != "classes")
538 throw new FormatException ("Expecting <classes>. Got <" + classes.Name + ">");
540 types = (XMLClass []) LoadRecursive (classes.ChildNodes, typeof (XMLClass));
543 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
546 XMLNamespace nspace = (XMLNamespace) other;
548 XmlNode childA = doc.CreateElement ("classes", null);
549 parent.AppendChild (childA);
551 CompareTypes (childA, nspace.types);
554 void CompareTypes (XmlNode parent, XMLClass [] other)
556 ArrayList newNodes = new ArrayList ();
557 Hashtable oh = CreateHash (other);
559 int count = (types == null) ? 0 : types.Length;
560 for (int i = 0; i < count; i++) {
561 XMLClass xclass = types [i];
563 node = document.CreateElement ("class", null);
565 AddAttribute (node, "name", xclass.Name);
566 AddAttribute (node, "type", xclass.Type);
568 if (oh.ContainsKey (xclass.Name)) {
569 int idx = (int) oh [xclass.Name];
570 xclass.CompareTo (document, node, other [idx]);
572 counters.AddPartialToPartial (xclass.Counters);
574 AddAttribute (node, "presence", "missing");
576 counters.MissingTotal++;
581 count = other.Length;
582 for (int i = 0; i < count; i++) {
583 XMLClass c = other [i];
584 if (c == null || c.Name.EndsWith ("TODOAttribute"))
587 node = document.CreateElement ("class", null);
589 AddAttribute (node, "name", c.Name);
590 AddAttribute (node, "type", c.Type);
593 counters.ExtraTotal++;
597 XmlNode [] nodes = (XmlNode []) newNodes.ToArray (typeof (XmlNode));
598 Array.Sort (nodes, XmlNodeComparer.Default);
599 foreach (XmlNode nn in nodes)
600 parent.AppendChild (nn);
603 static Hashtable CreateHash (XMLClass [] other)
605 Hashtable result = new Hashtable ();
608 foreach (XMLClass c in other) {
609 result [c.Name] = i++;
621 class XMLClass : XMLData
631 XMLAttributes attributes;
632 XMLInterfaces interfaces;
633 XMLGenericTypeConstraints genericConstraints;
635 XMLConstructors constructors;
636 XMLProperties properties;
641 public override void LoadData (XmlNode node)
644 throw new ArgumentNullException ("node");
646 name = node.Attributes ["name"].Value;
647 type = node.Attributes ["type"].Value;
648 XmlAttribute xatt = node.Attributes ["base"];
650 baseName = xatt.Value;
652 xatt = node.Attributes ["sealed"];
653 isSealed = (xatt != null && xatt.Value == "true");
655 xatt = node.Attributes ["abstract"];
656 isAbstract = (xatt != null && xatt.Value == "true");
658 xatt = node.Attributes["serializable"];
659 isSerializable = (xatt != null && xatt.Value == "true");
661 xatt = node.Attributes["charset"];
663 charSet = xatt.Value;
665 xatt = node.Attributes["layout"];
669 XmlNode child = node.FirstChild;
671 // Console.Error.WriteLine ("Empty class {0} {1}", name, type);
675 if (child.Name == "attributes") {
676 attributes = new XMLAttributes ();
677 attributes.LoadData (child);
678 child = child.NextSibling;
681 if (child != null && child.Name == "interfaces") {
682 interfaces = new XMLInterfaces ();
683 interfaces.LoadData (child);
684 child = child.NextSibling;
687 if (child != null && child.Name == "generic-type-constraints") {
688 genericConstraints = new XMLGenericTypeConstraints ();
689 genericConstraints.LoadData (child);
690 child = child.NextSibling;
693 if (child != null && child.Name == "fields") {
694 fields = new XMLFields ();
695 fields.LoadData (child);
696 child = child.NextSibling;
699 if (child != null && child.Name == "constructors") {
700 constructors = new XMLConstructors ();
701 constructors.LoadData (child);
702 child = child.NextSibling;
705 if (child != null && child.Name == "properties") {
706 properties = new XMLProperties ();
707 properties.LoadData (child);
708 child = child.NextSibling;
711 if (child != null && child.Name == "events") {
712 events = new XMLEvents ();
713 events.LoadData (child);
714 child = child.NextSibling;
717 if (child != null && child.Name == "methods") {
718 methods = new XMLMethods ();
719 methods.LoadData (child);
720 child = child.NextSibling;
726 if (child.Name != "classes") {
727 Console.WriteLine ("name: {0} type: {1} {2}", name, type, child.NodeType);
728 throw new FormatException ("Expecting <classes>. Got <" + child.Name + ">");
731 nested = (XMLClass []) LoadRecursive (child.ChildNodes, typeof (XMLClass));
734 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
737 XMLClass oclass = (XMLClass) other;
739 if (attributes != null || oclass.attributes != null) {
740 if (attributes == null)
741 attributes = new XMLAttributes ();
743 attributes.CompareTo (doc, parent, oclass.attributes);
744 counters.AddPartialToPartial (attributes.Counters);
745 if (oclass.attributes != null && oclass.attributes.IsTodo) {
747 counters.TodoTotal++;
748 counters.ErrorTotal++;
749 AddAttribute (parent, "error", "todo");
750 if (oclass.attributes.Comment != null)
751 AddAttribute (parent, "comment", oclass.attributes.Comment);
755 if (type != oclass.type)
756 AddWarning (parent, "Class type is wrong: {0} != {1}", type, oclass.type);
758 if (baseName != oclass.baseName)
759 AddWarning (parent, "Base class is wrong: {0} != {1}", baseName, oclass.baseName);
761 if (isAbstract != oclass.isAbstract || isSealed != oclass.isSealed) {
762 if ((isAbstract && isSealed) || (oclass.isAbstract && oclass.isSealed))
763 AddWarning (parent, "Should {0}be static", (isAbstract && isSealed) ? "" : "not ");
764 else if (isAbstract != oclass.isAbstract)
765 AddWarning (parent, "Should {0}be abstract", isAbstract ? "" : "not ");
766 else if (isSealed != oclass.isSealed)
767 AddWarning (parent, "Should {0}be sealed", isSealed ? "" : "not ");
770 if (isSerializable != oclass.isSerializable)
771 AddWarning (parent, "Should {0}be serializable", isSerializable ? "" : "not ");
773 if (charSet != oclass.charSet)
774 AddWarning (parent, "CharSet is wrong: {0} != {1}", charSet, oclass.charSet);
776 if (layout != oclass.layout)
777 AddWarning (parent, "Layout is wrong: {0} != {1}", layout, oclass.layout);
779 if (interfaces != null || oclass.interfaces != null) {
780 if (interfaces == null)
781 interfaces = new XMLInterfaces ();
783 interfaces.CompareTo (doc, parent, oclass.interfaces);
784 counters.AddPartialToPartial (interfaces.Counters);
787 if (genericConstraints != null || oclass.genericConstraints != null) {
788 if (genericConstraints == null)
789 genericConstraints = new XMLGenericTypeConstraints ();
791 genericConstraints.CompareTo (doc, parent, oclass.genericConstraints);
792 counters.AddPartialToPartial (genericConstraints.Counters);
795 if (fields != null || oclass.fields != null) {
797 fields = new XMLFields ();
799 fields.CompareTo (doc, parent, oclass.fields);
800 counters.AddPartialToPartial (fields.Counters);
803 if (constructors != null || oclass.constructors != null) {
804 if (constructors == null)
805 constructors = new XMLConstructors ();
807 constructors.CompareTo (doc, parent, oclass.constructors);
808 counters.AddPartialToPartial (constructors.Counters);
811 if (properties != null || oclass.properties != null) {
812 if (properties == null)
813 properties = new XMLProperties ();
815 properties.CompareTo (doc, parent, oclass.properties);
816 counters.AddPartialToPartial (properties.Counters);
819 if (events != null || oclass.events != null) {
821 events = new XMLEvents ();
823 events.CompareTo (doc, parent, oclass.events);
824 counters.AddPartialToPartial (events.Counters);
827 if (methods != null || oclass.methods != null) {
829 methods = new XMLMethods ();
831 methods.CompareTo (doc, parent, oclass.methods);
832 counters.AddPartialToPartial (methods.Counters);
835 if (nested != null || oclass.nested != null) {
836 XmlNode n = doc.CreateElement ("classes", null);
837 parent.AppendChild (n);
838 CompareTypes (n, oclass.nested);
841 AddCountersAttributes (parent);
844 void CompareTypes (XmlNode parent, XMLClass [] other)
846 ArrayList newNodes = new ArrayList ();
847 Hashtable oh = CreateHash (other);
849 int count = (nested == null) ? 0 : nested.Length;
850 for (int i = 0; i < count; i++) {
851 XMLClass xclass = nested [i];
853 node = document.CreateElement ("nestedclass", null);
855 AddAttribute (node, "name", xclass.Name);
856 AddAttribute (node, "type", xclass.Type);
858 if (oh.ContainsKey (xclass.Name)) {
859 int idx = (int) oh [xclass.Name];
860 xclass.CompareTo (document, node, other [idx]);
862 counters.AddPartialToPartial (xclass.Counters);
864 // TODO: Should I count here?
865 AddAttribute (node, "presence", "missing");
867 counters.MissingTotal++;
872 count = other.Length;
873 for (int i = 0; i < count; i++) {
874 XMLClass c = other [i];
875 if (c == null || c.Name.EndsWith ("TODOAttribute"))
878 node = document.CreateElement ("nestedclass", null);
880 AddAttribute (node, "name", c.Name);
883 counters.ExtraTotal++;
887 XmlNode [] nodes = (XmlNode []) newNodes.ToArray (typeof (XmlNode));
888 Array.Sort (nodes, XmlNodeComparer.Default);
889 foreach (XmlNode nn in nodes)
890 parent.AppendChild (nn);
893 static Hashtable CreateHash (XMLClass [] other)
895 Hashtable result = new Hashtable ();
898 foreach (XMLClass c in other) {
899 result [c.Name] = i++;
915 class XMLParameter : XMLData
924 XMLAttributes attributes;
926 public override void LoadData (XmlNode node)
929 throw new ArgumentNullException ("node");
931 if (node.Name != "parameter")
932 throw new ArgumentException ("Expecting <parameter>");
934 name = node.Attributes["name"].Value;
935 type = node.Attributes["type"].Value;
936 attrib = node.Attributes["attrib"].Value;
937 if (node.Attributes ["direction"] != null)
938 direction = node.Attributes["direction"].Value;
939 if (node.Attributes["unsafe"] != null)
940 isUnsafe = bool.Parse (node.Attributes["unsafe"].Value);
941 if (node.Attributes["optional"] != null)
942 isOptional = bool.Parse (node.Attributes["optional"].Value);
943 if (node.Attributes["defaultValue"] != null)
944 defaultValue = node.Attributes["defaultValue"].Value;
\r
946 XmlNode child = node.FirstChild;
\r
950 if (child.Name == "attributes") {
951 attributes = new XMLAttributes ();
952 attributes.LoadData (child);
953 child = child.NextSibling;
957 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
961 XMLParameter oparm = (XMLParameter) other;
963 if (type != oparm.type)
964 AddWarning (parent, "Parameter type is wrong: {0} != {1}", type, oparm.type);
966 if (attrib != oparm.attrib)
967 AddWarning (parent, "Parameter attributes wrong: {0} != {1}", attrib, oparm.attrib);
969 if (direction != oparm.direction)
970 AddWarning (parent, "Parameter direction wrong: {0} != {1}", direction, oparm.direction);
972 if (isUnsafe != oparm.isUnsafe)
973 AddWarning (parent, "Parameter unsafe wrong: {0} != {1}", isUnsafe, oparm.isUnsafe);
975 if (isOptional != oparm.isOptional)
976 AddWarning (parent, "Parameter optional wrong: {0} != {1}", isOptional, oparm.isOptional);
978 if (defaultValue != oparm.defaultValue)
979 AddWarning (parent, "Parameter default value wrong: {0} != {1}", (defaultValue == null) ? "(no default value)" : defaultValue, (oparm.defaultValue == null) ? "(no default value)" : oparm.defaultValue);
981 if (attributes != null || oparm.attributes != null) {
982 if (attributes == null)
983 attributes = new XMLAttributes ();
\r
985 attributes.CompareTo (doc, parent, oparm.attributes);
986 counters.AddPartialToPartial (attributes.Counters);
987 if (oparm.attributes != null && oparm.attributes.IsTodo) {
989 counters.TodoTotal++;
990 counters.ErrorTotal++;
991 AddAttribute (parent, "error", "todo");
\r
992 if (oparm.attributes.Comment != null)
\r
993 AddAttribute (parent, "comment", oparm.attributes.Comment);
1003 class XMLAttributeProperties: XMLNameGroup
1005 static Hashtable ignored_properties;
1006 static XMLAttributeProperties ()
1008 ignored_properties = new Hashtable ();
1009 ignored_properties.Add ("System.Reflection.AssemblyKeyFileAttribute", "KeyFile");
1010 ignored_properties.Add ("System.Reflection.AssemblyCompanyAttribute", "Company");
1011 ignored_properties.Add ("System.Reflection.AssemblyConfigurationAttribute", "Configuration");
1012 ignored_properties.Add ("System.Reflection.AssemblyCopyrightAttribute", "Copyright");
1013 ignored_properties.Add ("System.Reflection.AssemblyProductAttribute", "Product");
1014 ignored_properties.Add ("System.Reflection.AssemblyTrademarkAttribute", "Trademark");
1015 ignored_properties.Add ("System.Reflection.AssemblyInformationalVersionAttribute", "InformationalVersion");
1017 ignored_properties.Add ("System.ObsoleteAttribute", "Message");
1018 ignored_properties.Add ("System.IO.IODescriptionAttribute", "Description");
1019 ignored_properties.Add ("System.Diagnostics.MonitoringDescriptionAttribute", "Description");
1022 Hashtable properties = new Hashtable ();
1025 public XMLAttributeProperties (string attribute)
1027 this.attribute = attribute;
1030 public override void LoadData(XmlNode node)
1033 throw new ArgumentNullException ("node");
1035 if (node.ChildNodes == null)
1038 string ignored = ignored_properties [attribute] as string;
1040 foreach (XmlNode n in node.ChildNodes) {
1041 string name = n.Attributes ["name"].Value;
1042 if (ignored == name)
1045 if (n.Attributes ["null"] != null) {
1046 properties.Add (name, null);
1049 string value = n.Attributes ["value"].Value;
1050 properties.Add (name, value);
1054 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
1056 this.document = doc;
1058 Hashtable other_properties = ((XMLAttributeProperties)other).properties;
1059 foreach (DictionaryEntry de in other_properties) {
1060 object other_value = properties [de.Key];
1062 if (de.Value == null) {
1063 if (other_value != null)
1064 AddWarning (parent, "Property '{0}' is 'null' and should be '{1}'", de.Key, other_value);
1068 if (de.Value.Equals (other_value))
1071 AddWarning (parent, "Property '{0}' is '{1}' and should be '{2}'",
1072 de.Key, de.Value, other_value == null ? "null" : other_value);
1076 public override string GroupName {
1078 return "properties";
1082 public override string Name {
1089 class XMLAttributes : XMLNameGroup
1091 Hashtable properties = new Hashtable ();
1096 protected override bool CheckIfAdd (string value, XmlNode node)
1098 if (value.EndsWith ("TODOAttribute")) {
1101 XmlNode pNode = node.SelectSingleNode ("properties");
1102 if (pNode.ChildNodes [0].Attributes ["value"] != null) {
1103 comment = pNode.ChildNodes [0].Attributes ["value"].Value;
1111 protected override void CompareToInner (string name, XmlNode node, XMLNameGroup other)
1113 XMLAttributeProperties other_prop = ((XMLAttributes)other).properties [name] as XMLAttributeProperties;
1114 XMLAttributeProperties this_prop = properties [name] as XMLAttributeProperties;
1115 if (other_prop == null || this_prop == null)
1118 this_prop.CompareTo (document, node, other_prop);
1119 counters.AddPartialToPartial (this_prop.Counters);
1122 public override string GetNodeKey (string name, XmlNode node)
1126 // if multiple attributes with the same name (type) exist, then we
1127 // cannot be sure which attributes correspond, so we must use the
1128 // name of the attribute (type) and the name/value of its properties
1131 XmlNodeList attributes = node.ParentNode.SelectNodes("attribute[@name='" + name + "']");
1132 if (attributes.Count > 1) {
1133 ArrayList keyParts = new ArrayList ();
1135 XmlNodeList properties = node.SelectNodes ("properties/property");
1136 foreach (XmlNode property in properties) {
1137 XmlAttributeCollection attrs = property.Attributes;
1138 if (attrs["value"] != null) {
1139 keyParts.Add (attrs["name"].Value + "=" + attrs["value"].Value);
1141 keyParts.Add (attrs["name"].Value + "=");
1145 // sort properties by name, as order of properties in XML is
1149 // insert name (type) of attribute
1150 keyParts.Insert (0, name);
1152 StringBuilder sb = new StringBuilder ();
1153 foreach (string value in keyParts) {
1157 key = sb.ToString ();
1165 protected override void LoadExtraData(string name, XmlNode node)
1167 XmlNode pNode = node.SelectSingleNode ("properties");
1169 if (name.EndsWith ("TODOAttribute")) {
1171 if (pNode.ChildNodes [0].Attributes ["value"] != null) {
1172 comment = pNode.ChildNodes [0].Attributes ["value"].Value;
1177 if (pNode != null) {
1178 XMLAttributeProperties p = new XMLAttributeProperties (name);
1181 properties[name] = p;
1185 public override string GroupName {
1186 get { return "attributes"; }
1189 public override string Name {
1190 get { return "attribute"; }
1193 public bool IsTodo {
1194 get { return isTodo; }
1197 public string Comment {
1198 get { return comment; }
1202 class XMLInterfaces : XMLNameGroup
1204 public override string GroupName {
1205 get { return "interfaces"; }
1208 public override string Name {
1209 get { return "interface"; }
1213 abstract class XMLGenericGroup : XMLNameGroup
1217 protected override void LoadExtraData (string name, XmlNode node)
1219 attributes = ((XmlElement) node).GetAttribute ("generic-attribute");
1222 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1224 base.CompareToInner (name, parent, other);
1226 XMLGenericGroup g = (XMLGenericGroup) other;
1227 if (attributes != g.attributes)
1228 AddWarning (parent, "Incorrect generic attributes: '{0}' != '{1}'", attributes, g.attributes);
1232 class XMLGenericTypeConstraints : XMLGenericGroup
1234 public override string GroupName {
1235 get { return "generic-type-constraints"; }
1238 public override string Name {
1239 get { return "generic-type-constraint"; }
1243 class XMLGenericMethodConstraints : XMLGenericGroup
1245 public override string GroupName {
1246 get { return "generic-method-constraints"; }
1249 public override string Name {
1250 get { return "generic-method-constraint"; }
1254 abstract class XMLMember : XMLNameGroup
1256 Hashtable attributeMap;
1257 Hashtable access = new Hashtable ();
1259 protected override void LoadExtraData (string name, XmlNode node)
1261 XmlAttribute xatt = node.Attributes ["attrib"];
1263 access [name] = xatt.Value;
1265 XmlNode orig = node;
1267 node = node.FirstChild;
1268 while (node != null) {
1269 if (node != null && node.Name == "attributes") {
1270 XMLAttributes a = new XMLAttributes ();
1272 if (attributeMap == null)
1273 attributeMap = new Hashtable ();
1275 attributeMap [name] = a;
1278 node = node.NextSibling;
1281 base.LoadExtraData (name, orig);
1284 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1286 base.CompareToInner (name, parent, other);
1287 XMLMember mb = other as XMLMember;
1288 XMLAttributes att = null;
1289 XMLAttributes oatt = null;
1290 if (attributeMap != null)
1291 att = attributeMap [name] as XMLAttributes;
1293 if (mb != null && mb.attributeMap != null)
1294 oatt = mb.attributeMap [name] as XMLAttributes;
1296 if (att != null || oatt != null) {
1298 att = new XMLAttributes ();
1300 att.CompareTo (document, parent, oatt);
1301 counters.AddPartialToPartial(att.Counters);
1302 if (oatt != null && oatt.IsTodo) {
1304 counters.ErrorTotal++;
1305 AddAttribute (parent, "error", "todo");
1306 if (oatt.Comment != null)
1307 AddAttribute (parent, "comment", oatt.Comment);
1311 XMLMember member = (XMLMember) other;
1312 string acc = access [name] as string;
1317 if (member.access != null)
1318 oacc = member.access [name] as string;
1320 string accName = ConvertToString (Int32.Parse (acc));
1321 string oaccName = "";
1323 oaccName = ConvertToString (Int32.Parse (oacc));
1325 if (accName != oaccName)
1326 AddWarning (parent, "Incorrect attributes: '{0}' != '{1}'", accName, oaccName);
1329 protected virtual string ConvertToString (int att)
1335 class XMLFields : XMLMember
1337 Hashtable fieldTypes;
1338 Hashtable fieldValues;
1340 protected override void LoadExtraData (string name, XmlNode node)
1342 XmlAttribute xatt = node.Attributes ["fieldtype"];
1344 if (fieldTypes == null)
1345 fieldTypes = new Hashtable ();
1347 fieldTypes [name] = xatt.Value;
1350 xatt = node.Attributes ["value"];
1352 if (fieldValues == null)
1353 fieldValues = new Hashtable ();
1355 fieldValues[name] = xatt.Value;
1358 base.LoadExtraData (name, node);
1361 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1363 base.CompareToInner (name, parent, other);
1364 XMLFields fields = (XMLFields) other;
1365 if (fieldTypes != null) {
1366 string ftype = fieldTypes [name] as string;
1367 string oftype = null;
1368 if (fields.fieldTypes != null)
1369 oftype = fields.fieldTypes [name] as string;
1371 if (ftype != oftype)
1372 AddWarning (parent, "Field type is {0} and should be {1}", oftype, ftype);
1374 if (fieldValues != null) {
1375 string fvalue = fieldValues [name] as string;
1376 string ofvalue = null;
1377 if (fields.fieldValues != null)
1378 ofvalue = fields.fieldValues [name] as string;
1380 if (fvalue != ofvalue)
1381 AddWarning (parent, "Field value is {0} and should be {1}", ofvalue, fvalue);
1385 protected override string ConvertToString (int att)
1387 FieldAttributes fa = (FieldAttributes) att;
1388 return fa.ToString ();
1391 public override string GroupName {
1392 get { return "fields"; }
1395 public override string Name {
1396 get { return "field"; }
1400 class XMLParameters : XMLNameGroup
1402 public override void LoadData (XmlNode node)
1405 throw new ArgumentNullException ("node");
1407 if (node.Name != GroupName)
1408 throw new FormatException (String.Format ("Expecting <{0}>", GroupName));
1410 keys = new Hashtable ();
1411 foreach (XmlNode n in node.ChildNodes) {
1412 string name = n.Attributes["name"].Value;
1413 string key = GetNodeKey (name, n);
1414 XMLParameter parm = new XMLParameter ();
1416 keys.Add (key, parm);
1417 LoadExtraData (key, n);
1421 public override string GroupName {
1423 return "parameters";
1427 public override string Name {
1433 public override string GetNodeKey (string name, XmlNode node)
1435 return node.Attributes["position"].Value;
1438 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
1440 this.document = doc;
1442 group = doc.CreateElement (GroupName, null);
1444 Hashtable okeys = null;
1445 if (other != null && ((XMLParameters) other).keys != null) {
1446 okeys = ((XMLParameters) other).keys;
1449 XmlNode node = null;
1450 bool onull = (okeys == null);
1452 foreach (DictionaryEntry entry in keys) {
1453 node = doc.CreateElement (Name, null);
1454 group.AppendChild (node);
1455 string key = (string) entry.Key;
1456 XMLParameter parm = (XMLParameter) entry.Value;
1457 AddAttribute (node, "name", parm.Name);
1459 if (!onull && HasKey (key, okeys)) {
1460 parm.CompareTo (document, node, okeys[key]);
1461 counters.AddPartialToPartial (parm.Counters);
1465 AddAttribute (node, "presence", "missing");
1471 if (!onull && okeys.Count != 0) {
1472 foreach (XMLParameter value in okeys.Values) {
1473 node = doc.CreateElement (Name, null);
1474 AddAttribute (node, "name", value.Name);
1475 AddAttribute (node, "presence", "extra");
1476 group.AppendChild (node);
1481 if (group.HasChildNodes)
1482 parent.AppendChild (group);
1486 class XMLProperties : XMLMember
1488 Hashtable nameToMethod = new Hashtable ();
1490 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1492 Counters copy = counters;
1493 counters = new Counters();
1495 XMLProperties oprop = other as XMLProperties;
1496 if (oprop != null) {
1497 XMLMethods m = nameToMethod [name] as XMLMethods;
1498 XMLMethods om = oprop.nameToMethod [name] as XMLMethods;
1499 if (m != null || om != null) {
1501 m = new XMLMethods ();
1503 m.CompareTo(document, parent, om);
1504 counters.AddPartialToPartial(m.Counters);
1508 base.CompareToInner (name, parent, other);
1509 AddCountersAttributes(parent);
1511 copy.AddPartialToPartial(counters);
1515 protected override void LoadExtraData (string name, XmlNode node)
1517 XmlNode orig = node;
1518 node = node.FirstChild;
1519 while (node != null) {
1520 if (node != null && node.Name == "methods") {
1521 XMLMethods m = new XMLMethods ();
1522 XmlNode parent = node.ParentNode;
1523 string key = GetNodeKey (name, parent);
1525 nameToMethod [key] = m;
1528 node = node.NextSibling;
1531 base.LoadExtraData (name, orig);
1534 public override string GetNodeKey (string name, XmlNode node)
1536 XmlAttributeCollection atts = node.Attributes;
1537 return String.Format ("{0}:{1}:{2}", atts ["name"].Value,
1538 atts ["ptype"].Value,
1539 atts ["params"].Value);
1542 public override string GroupName {
1543 get { return "properties"; }
1546 public override string Name {
1547 get { return "property"; }
1551 class XMLEvents : XMLMember
1553 Hashtable eventTypes;
1555 protected override void LoadExtraData (string name, XmlNode node)
1557 XmlAttribute xatt = node.Attributes ["eventtype"];
1559 if (eventTypes == null)
1560 eventTypes = new Hashtable ();
1562 eventTypes [name] = xatt.Value;
1565 base.LoadExtraData (name, node);
1568 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1570 Counters copy = counters;
1571 counters = new Counters ();
1574 base.CompareToInner (name, parent, other);
1575 AddCountersAttributes (parent);
1576 if (eventTypes == null)
1579 XMLEvents evt = (XMLEvents) other;
1580 string etype = eventTypes [name] as string;
1581 string oetype = null;
1582 if (evt.eventTypes != null)
1583 oetype = evt.eventTypes [name] as string;
1585 if (etype != oetype)
1586 AddWarning (parent, "Event type is {0} and should be {1}", oetype, etype);
1588 AddCountersAttributes (parent);
1589 copy.AddPartialToPartial (counters);
1594 protected override string ConvertToString (int att)
1596 EventAttributes ea = (EventAttributes) att;
1597 return ea.ToString ();
1600 public override string GroupName {
1601 get { return "events"; }
1604 public override string Name {
1605 get { return "event"; }
1609 class XMLMethods : XMLMember
1611 Hashtable returnTypes;
1612 Hashtable parameters;
1613 Hashtable genericConstraints;
1614 Hashtable signatureFlags;
1625 protected override void LoadExtraData (string name, XmlNode node)
1627 XmlAttribute xatt = node.Attributes ["returntype"];
1629 if (returnTypes == null)
1630 returnTypes = new Hashtable ();
1632 returnTypes [name] = xatt.Value;
1635 SignatureFlags flags = SignatureFlags.None;
1636 if (((XmlElement) node).GetAttribute ("abstract") == "true")
1637 flags |= SignatureFlags.Abstract;
1638 if (((XmlElement) node).GetAttribute ("static") == "true")
1639 flags |= SignatureFlags.Static;
1640 if (((XmlElement) node).GetAttribute ("virtual") == "true")
1641 flags |= SignatureFlags.Virtual;
1642 if (flags != SignatureFlags.None) {
1643 if (signatureFlags == null)
1644 signatureFlags = new Hashtable ();
1645 signatureFlags [name] = flags;
1648 XmlNode parametersNode = node.SelectSingleNode ("parameters");
1649 if (parametersNode != null) {
1650 if (parameters == null)
1651 parameters = new Hashtable ();
1653 XMLParameters parms = new XMLParameters ();
1654 parms.LoadData (parametersNode);
1656 parameters[name] = parms;
1659 XmlNode genericNode = node.SelectSingleNode ("generic-method-constraints");
1660 if (genericNode != null) {
1661 if (genericConstraints == null)
1662 genericConstraints = new Hashtable ();
1663 XMLGenericMethodConstraints csts = new XMLGenericMethodConstraints ();
1664 csts.LoadData (genericNode);
1665 genericConstraints [name] = csts;
1668 base.LoadExtraData (name, node);
1671 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1673 // create backup of actual counters
1674 Counters copy = counters;
1675 // initialize counters for current method
1676 counters = new Counters();
1679 base.CompareToInner(name, parent, other);
1680 XMLMethods methods = (XMLMethods) other;
1682 SignatureFlags flags = signatureFlags != null &&
1683 signatureFlags.ContainsKey (name) ?
1684 (SignatureFlags) signatureFlags [name] :
1685 SignatureFlags.None;
1686 SignatureFlags oflags = methods.signatureFlags != null &&
1687 methods.signatureFlags.ContainsKey (name) ?
1688 (SignatureFlags) methods.signatureFlags [name] :
1689 SignatureFlags.None;
1691 if (flags!= oflags) {
1692 if (flags == SignatureFlags.None)
1693 AddWarning (parent, String.Format ("should not be {0}", oflags));
1694 else if (oflags == SignatureFlags.None)
1695 AddWarning (parent, String.Format ("should be {0}", flags));
1697 AddWarning (parent, String.Format ("{0} and should be {1}", oflags, flags));
1700 if (returnTypes != null) {
1701 string rtype = returnTypes[name] as string;
1702 string ortype = null;
1703 if (methods.returnTypes != null)
1704 ortype = methods.returnTypes[name] as string;
1706 if (rtype != ortype)
1707 AddWarning (parent, "Return type is {0} and should be {1}", ortype, rtype);
1710 if (parameters != null) {
1711 XMLParameters parms = parameters[name] as XMLParameters;
1712 parms.CompareTo (document, parent, methods.parameters[name]);
1713 counters.AddPartialToPartial (parms.Counters);
1716 // output counter attributes in result document
1717 AddCountersAttributes(parent);
1719 // add temporary counters to actual counters
1720 copy.AddPartialToPartial(counters);
1721 // restore backup of actual counters
1726 protected override string ConvertToString (int att)
1728 MethodAttributes ma = (MethodAttributes) att;
1729 // ignore ReservedMasks
1730 ma &= ~ MethodAttributes.ReservedMask;
1731 ma &= ~ MethodAttributes.VtableLayoutMask;
1732 if ((ma & MethodAttributes.FamORAssem) != 0)
1733 ma = (ma & ~ MethodAttributes.FamORAssem) | MethodAttributes.Family;
1735 // ignore the HasSecurity attribute for now
1736 if ((ma & MethodAttributes.HasSecurity) != 0)
1737 ma = (MethodAttributes) (att - (int) MethodAttributes.HasSecurity);
1739 // ignore the RequireSecObject attribute for now
1740 if ((ma & MethodAttributes.RequireSecObject) != 0)
1741 ma = (MethodAttributes) (att - (int) MethodAttributes.RequireSecObject);
1743 // we don't care if the implementation is forwarded through PInvoke
1744 if ((ma & MethodAttributes.PinvokeImpl) != 0)
1745 ma = (MethodAttributes) (att - (int) MethodAttributes.PinvokeImpl);
1747 return ma.ToString ();
1750 public override string GroupName {
1751 get { return "methods"; }
1754 public override string Name {
1755 get { return "method"; }
1759 class XMLConstructors : XMLMethods
1761 public override string GroupName {
1762 get { return "constructors"; }
1765 public override string Name {
1766 get { return "constructor"; }
1770 class XmlNodeComparer : IComparer
1772 public static XmlNodeComparer Default = new XmlNodeComparer ();
1774 public int Compare (object a, object b)
1776 XmlNode na = (XmlNode) a;
1777 XmlNode nb = (XmlNode) b;
1778 return String.Compare (na.Attributes ["name"].Value, nb.Attributes ["name"].Value);