2010-06-03 Jb Evain <jbevain@novell.com>
[mcs.git] / tools / corcompare / mono-api-diff.cs
blobc5d2ac11a65bee86f055b7b030442d9dc3258aa8
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 // Marek Safar (marek.safar@gmail.com)
8 //
9 // Maintainer:
10 // C.J. Adams-Collier (cjac@colliertech.org)
12 // (C) 2003 Novell, Inc (http://www.novell.com)
13 // (C) 2009,2010 Collier Technologies (http://www.colliertech.org)
15 using System;
16 using System.Collections;
17 using System.IO;
18 using System.Reflection;
19 using System.Text;
20 using System.Xml;
22 namespace Mono.AssemblyCompare
24 class Driver
26 static int Main (string [] args)
28 if (args.Length != 2) {
29 Console.WriteLine ("Usage: mono mono-api-diff.exe <assembly 1 xml> <assembly 2 xml>");
30 return 1;
33 XMLAssembly ms = CreateXMLAssembly (args [0]);
34 XMLAssembly mono = CreateXMLAssembly (args [1]);
35 XmlDocument doc = ms.CompareAndGetDocument (mono);
37 XmlTextWriter writer = new XmlTextWriter (Console.Out);
38 writer.Formatting = Formatting.Indented;
39 doc.WriteTo (writer);
41 return 0;
44 static XMLAssembly CreateXMLAssembly (string file)
46 XmlDocument doc = new XmlDocument ();
47 doc.Load (File.OpenRead (file));
49 XmlNode node = doc.SelectSingleNode ("/assemblies/assembly");
50 XMLAssembly result = new XMLAssembly ();
51 try {
52 result.LoadData (node);
53 } catch (Exception e) {
54 Console.Error.WriteLine ("Error loading {0}: {1}\n{2}", file, e.Message, e);
55 Environment.Exit (1);
58 return result;
62 class Counters
64 public int Present;
65 public int PresentTotal;
66 public int Missing;
67 public int MissingTotal;
68 public int Todo;
69 public int TodoTotal;
71 public int Extra;
72 public int ExtraTotal;
73 public int Warning;
74 public int WarningTotal;
75 public int ErrorTotal;
77 public Counters ()
81 public void AddPartialToPartial (Counters other)
83 Present += other.Present;
84 Extra += other.Extra;
85 Missing += other.Missing;
87 Todo += other.Todo;
88 Warning += other.Warning;
89 AddPartialToTotal (other);
92 public void AddPartialToTotal (Counters other)
94 PresentTotal += other.Present;
95 ExtraTotal += other.Extra;
96 MissingTotal += other.Missing;
98 TodoTotal += other.Todo;
99 WarningTotal += other.Warning;
102 public void AddTotalToPartial (Counters other)
104 Present += other.PresentTotal;
105 Extra += other.ExtraTotal;
106 Missing += other.MissingTotal;
108 Todo += other.TodoTotal;
109 Warning += other.WarningTotal;
110 AddTotalToTotal (other);
113 public void AddTotalToTotal (Counters other)
115 PresentTotal += other.PresentTotal;
116 ExtraTotal += other.ExtraTotal;
117 MissingTotal += other.MissingTotal;
119 TodoTotal += other.TodoTotal;
120 WarningTotal += other.WarningTotal;
121 ErrorTotal += other.ErrorTotal;
124 public int Total {
125 get { return Present + Missing; }
128 public int AbsTotal {
129 get { return PresentTotal + MissingTotal; }
132 public int Ok {
133 get { return Present - Todo; }
136 public int OkTotal {
137 get { return PresentTotal - TodoTotal - ErrorTotal; }
140 public override string ToString ()
142 StringWriter sw = new StringWriter ();
143 sw.WriteLine ("Present: {0}", Present);
144 sw.WriteLine ("PresentTotal: {0}", PresentTotal);
145 sw.WriteLine ("Missing: {0}", Missing);
146 sw.WriteLine ("MissingTotal: {0}", MissingTotal);
147 sw.WriteLine ("Todo: {0}", Todo);
148 sw.WriteLine ("TodoTotal: {0}", TodoTotal);
149 sw.WriteLine ("Extra: {0}", Extra);
150 sw.WriteLine ("ExtraTotal: {0}", ExtraTotal);
151 sw.WriteLine ("Warning: {0}", Warning);
152 sw.WriteLine ("WarningTotal: {0}", WarningTotal);
153 sw.WriteLine ("ErrorTotal: {0}", ErrorTotal);
154 sw.WriteLine ("--");
155 return sw.GetStringBuilder ().ToString ();
159 abstract class XMLData
161 protected XmlDocument document;
162 protected Counters counters;
163 bool haveWarnings;
165 public XMLData ()
167 counters = new Counters ();
170 public virtual void LoadData (XmlNode node)
174 protected object [] LoadRecursive (XmlNodeList nodeList, Type type)
176 ArrayList list = new ArrayList ();
177 foreach (XmlNode node in nodeList) {
178 XMLData data = (XMLData) Activator.CreateInstance (type);
179 data.LoadData (node);
180 list.Add (data);
183 return (object []) list.ToArray (type);
186 public static bool IsMeaninglessAttribute (string s)
188 if (s == null)
189 return false;
190 if (s == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")
191 return true;
192 return false;
195 public static bool IsMonoTODOAttribute (string s)
197 if (s == null)
198 return false;
199 if (//s.EndsWith ("MonoTODOAttribute") ||
200 s.EndsWith ("MonoDocumentationNoteAttribute") ||
201 s.EndsWith ("MonoExtensionAttribute") ||
202 // s.EndsWith ("MonoInternalNoteAttribute") ||
203 s.EndsWith ("MonoLimitationAttribute") ||
204 s.EndsWith ("MonoNotSupportedAttribute"))
205 return true;
206 return s.EndsWith ("TODOAttribute");
209 protected void AddAttribute (XmlNode node, string name, string value)
211 XmlAttribute attr = document.CreateAttribute (name);
212 attr.Value = value;
213 node.Attributes.Append (attr);
216 protected void AddExtra (XmlNode node)
218 //TODO: count all the subnodes?
219 AddAttribute (node, "presence", "extra");
220 AddAttribute (node, "ok", "1");
221 AddAttribute (node, "ok_total", "1");
222 AddAttribute (node, "extra", "1");
223 AddAttribute (node, "extra_total", "1");
226 public void AddCountersAttributes (XmlNode node)
228 if (counters.Missing > 0)
229 AddAttribute (node, "missing", counters.Missing.ToString ());
231 if (counters.Present > 0)
232 AddAttribute (node, "present", counters.Present.ToString ());
234 if (counters.Extra > 0)
235 AddAttribute (node, "extra", counters.Extra.ToString ());
237 if (counters.Ok > 0)
238 AddAttribute (node, "ok", counters.Ok.ToString ());
240 if (counters.Total > 0) {
241 int percent = (100 * counters.Ok / counters.Total);
242 AddAttribute (node, "complete", percent.ToString ());
245 if (counters.Todo > 0)
246 AddAttribute (node, "todo", counters.Todo.ToString ());
248 if (counters.Warning > 0)
249 AddAttribute (node, "warning", counters.Warning.ToString ());
251 if (counters.MissingTotal > 0)
252 AddAttribute (node, "missing_total", counters.MissingTotal.ToString ());
254 if (counters.PresentTotal > 0)
255 AddAttribute (node, "present_total", counters.PresentTotal.ToString ());
257 if (counters.ExtraTotal > 0)
258 AddAttribute (node, "extra_total", counters.ExtraTotal.ToString ());
260 if (counters.OkTotal > 0)
261 AddAttribute (node, "ok_total", counters.OkTotal.ToString ());
263 if (counters.AbsTotal > 0) {
264 int percent = (100 * counters.OkTotal / counters.AbsTotal);
265 AddAttribute (node, "complete_total", percent.ToString ());
268 if (counters.TodoTotal > 0) {
269 AddAttribute (node, "todo_total", counters.TodoTotal.ToString ());
270 //TODO: should be different on error. check error cases in corcompare.
271 AddAttribute (node, "error_total", counters.Todo.ToString ());
274 if (counters.WarningTotal > 0)
275 AddAttribute (node, "warning_total", counters.WarningTotal.ToString ());
279 protected void AddWarning (XmlNode parent, string fmt, params object [] args)
281 counters.Warning++;
282 haveWarnings = true;
283 XmlNode warnings = parent.SelectSingleNode ("warnings");
284 if (warnings == null) {
285 warnings = document.CreateElement ("warnings", null);
286 parent.AppendChild (warnings);
289 AddAttribute (parent, "error", "warning");
290 XmlNode warning = document.CreateElement ("warning", null);
291 AddAttribute (warning, "text", String.Format (fmt, args));
292 warnings.AppendChild (warning);
295 public bool HaveWarnings {
296 get { return haveWarnings; }
299 public Counters Counters {
300 get { return counters; }
303 public abstract void CompareTo (XmlDocument doc, XmlNode parent, object other);
306 abstract class XMLNameGroup : XMLData
308 protected XmlNode group;
309 protected Hashtable keys;
311 public override void LoadData (XmlNode node)
313 if (node == null)
314 throw new ArgumentNullException ("node");
316 if (node.Name != GroupName)
317 throw new FormatException (String.Format ("Expecting <{0}>", GroupName));
319 keys = new Hashtable ();
320 foreach (XmlNode n in node.ChildNodes) {
321 string name = n.Attributes ["name"].Value;
322 if (CheckIfAdd (name, n)) {
323 string key = GetNodeKey (name, n);
324 //keys.Add (key, name);
325 keys [key] = name;
326 LoadExtraData (key, n);
331 protected virtual bool CheckIfAdd (string value, XmlNode node)
333 return true;
336 protected virtual void LoadExtraData (string name, XmlNode node)
340 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
342 this.document = doc;
343 if (group == null)
344 group = doc.CreateElement (GroupName, null);
346 Hashtable okeys = null;
347 if (other != null && ((XMLNameGroup) other).keys != null) {
348 okeys = ((XMLNameGroup) other).keys;
351 XmlNode node = null;
352 bool onull = (okeys == null);
353 if (keys != null) {
354 foreach (DictionaryEntry entry in keys) {
355 node = doc.CreateElement (Name, null);
356 group.AppendChild (node);
357 string key = (string) entry.Key;
358 string name = (string) entry.Value;
359 AddAttribute (node, "name", name);
361 if (!onull && HasKey (key, okeys)) {
362 CompareToInner (key, node, (XMLNameGroup) other);
363 okeys.Remove (key);
364 counters.Present++;
365 } else {
366 AddAttribute (node, "presence", "missing");
367 counters.Missing++;
372 if (!onull && okeys.Count != 0) {
373 foreach (string value in okeys.Values) {
374 node = doc.CreateElement (Name, null);
375 AddAttribute (node, "name", (string) value);
376 AddAttribute (node, "presence", "extra");
377 group.AppendChild (node);
378 counters.Extra++;
382 if (group.HasChildNodes)
383 parent.AppendChild (group);
386 protected virtual void CompareToInner (string name, XmlNode node, XMLNameGroup other)
390 public virtual string GetNodeKey (string name, XmlNode node)
392 return name;
395 public virtual bool HasKey (string key, Hashtable other)
397 return other.ContainsKey (key);
400 public abstract string GroupName { get; }
401 public abstract string Name { get; }
404 class XMLAssembly : XMLData
406 XMLAttributes attributes;
407 XMLNamespace [] namespaces;
408 string name;
409 string version;
411 public override void LoadData (XmlNode node)
413 if (node == null)
414 throw new ArgumentNullException ("node");
416 name = node.Attributes ["name"].Value;
417 version = node.Attributes ["version"].Value;
418 XmlNode atts = node.FirstChild;
419 attributes = new XMLAttributes ();
420 if (atts.Name == "attributes") {
421 attributes.LoadData (atts);
422 atts = atts.NextSibling;
425 if (atts == null || atts.Name != "namespaces") {
426 Console.Error.WriteLine ("Warning: no namespaces found!");
427 return;
430 namespaces = (XMLNamespace []) LoadRecursive (atts.ChildNodes, typeof (XMLNamespace));
433 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
435 XMLAssembly assembly = (XMLAssembly) other;
437 XmlNode childA = doc.CreateElement ("assembly", null);
438 AddAttribute (childA, "name", name);
439 AddAttribute (childA, "version", version);
440 if (name != assembly.name)
441 AddWarning (childA, "Assembly names not equal: {0}, {1}", name, assembly.name);
443 if (version != assembly.version)
444 AddWarning (childA, "Assembly version not equal: {0}, {1}", version, assembly.version);
446 parent.AppendChild (childA);
448 attributes.CompareTo (doc, childA, assembly.attributes);
449 counters.AddPartialToPartial (attributes.Counters);
451 CompareNamespaces (childA, assembly.namespaces);
452 if (assembly.attributes != null && assembly.attributes.IsTodo) {
453 counters.Todo++;
454 counters.TodoTotal++;
455 counters.ErrorTotal++;
456 AddAttribute (childA, "error", "todo");
457 if (assembly.attributes.Comment != null)
458 AddAttribute (childA, "comment", assembly.attributes.Comment);
461 AddCountersAttributes (childA);
464 void CompareNamespaces (XmlNode parent, XMLNamespace [] other)
466 ArrayList newNS = new ArrayList ();
467 XmlNode group = document.CreateElement ("namespaces", null);
468 parent.AppendChild (group);
470 Hashtable oh = CreateHash (other);
471 XmlNode node = null;
472 int count = (namespaces == null) ? 0 : namespaces.Length;
473 for (int i = 0; i < count; i++) {
474 XMLNamespace xns = namespaces [i];
476 node = document.CreateElement ("namespace", null);
477 newNS.Add (node);
478 AddAttribute (node, "name", xns.Name);
480 int idx = -1;
481 if (oh.ContainsKey (xns.Name))
482 idx = (int) oh [xns.Name];
483 XMLNamespace ons = idx >= 0 ? (XMLNamespace) other [idx] : null;
484 xns.CompareTo (document, node, ons);
485 if (idx >= 0)
486 other [idx] = null;
487 xns.AddCountersAttributes (node);
488 counters.Present++;
489 counters.PresentTotal++;
490 counters.AddPartialToTotal (xns.Counters);
493 if (other != null) {
494 count = other.Length;
495 for (int i = 0; i < count; i++) {
496 XMLNamespace n = other [i];
497 if (n == null)
498 continue;
500 node = document.CreateElement ("namespace", null);
501 newNS.Add (node);
502 AddAttribute (node, "name", n.Name);
503 AddExtra (node);
504 counters.ExtraTotal++;
508 XmlNode [] nodes = (XmlNode []) newNS.ToArray (typeof (XmlNode));
509 Array.Sort (nodes, XmlNodeComparer.Default);
510 foreach (XmlNode nn in nodes)
511 group.AppendChild (nn);
514 static Hashtable CreateHash (XMLNamespace [] other)
516 Hashtable result = new Hashtable ();
517 if (other != null) {
518 int i = 0;
519 foreach (XMLNamespace n in other) {
520 result [n.Name] = i++;
524 return result;
527 public XmlDocument CompareAndGetDocument (XMLAssembly other)
529 XmlDocument doc = new XmlDocument ();
530 this.document = doc;
531 XmlNode parent = doc.CreateElement ("assemblies", null);
532 doc.AppendChild (parent);
534 CompareTo (doc, parent, other);
536 XmlNode decl = doc.CreateXmlDeclaration ("1.0", null, null);
537 doc.InsertBefore (decl, doc.DocumentElement);
539 return doc;
543 class XMLNamespace : XMLData
545 string name;
546 XMLClass [] types;
548 public override void LoadData (XmlNode node)
550 if (node == null)
551 throw new ArgumentNullException ("node");
553 if (node.Name != "namespace")
554 throw new FormatException ("Expecting <namespace>");
556 name = node.Attributes ["name"].Value;
557 XmlNode classes = node.FirstChild;
558 if (classes == null) {
559 Console.Error.WriteLine ("Warning: no classes for {0}", node.Attributes ["name"]);
560 return;
563 if (classes.Name != "classes")
564 throw new FormatException ("Expecting <classes>. Got <" + classes.Name + ">");
566 types = (XMLClass []) LoadRecursive (classes.ChildNodes, typeof (XMLClass));
569 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
571 this.document = doc;
572 XMLNamespace nspace = (XMLNamespace) other;
574 XmlNode childA = doc.CreateElement ("classes", null);
575 parent.AppendChild (childA);
577 CompareTypes (childA, nspace != null ? nspace.types : new XMLClass [0]);
580 void CompareTypes (XmlNode parent, XMLClass [] other)
582 ArrayList newNodes = new ArrayList ();
583 Hashtable oh = CreateHash (other);
584 XmlNode node = null;
585 int count = (types == null) ? 0 : types.Length;
586 for (int i = 0; i < count; i++) {
587 XMLClass xclass = types [i];
589 node = document.CreateElement ("class", null);
590 newNodes.Add (node);
591 AddAttribute (node, "name", xclass.Name);
592 AddAttribute (node, "type", xclass.Type);
594 int idx = -1;
595 if (oh.ContainsKey (xclass.Name))
596 idx = (int) oh [xclass.Name];
597 xclass.CompareTo (document, node, idx >= 0 ? other [idx] : new XMLClass ());
598 if (idx >= 0)
599 other [idx] = null;
600 counters.AddPartialToPartial (xclass.Counters);
603 if (other != null) {
604 count = other.Length;
605 for (int i = 0; i < count; i++) {
606 XMLClass c = other [i];
607 if (c == null || IsMonoTODOAttribute (c.Name))
608 continue;
610 node = document.CreateElement ("class", null);
611 newNodes.Add (node);
612 AddAttribute (node, "name", c.Name);
613 AddAttribute (node, "type", c.Type);
614 AddExtra (node);
615 counters.Extra++;
616 counters.ExtraTotal++;
620 XmlNode [] nodes = (XmlNode []) newNodes.ToArray (typeof (XmlNode));
621 Array.Sort (nodes, XmlNodeComparer.Default);
622 foreach (XmlNode nn in nodes)
623 parent.AppendChild (nn);
626 static Hashtable CreateHash (XMLClass [] other)
628 Hashtable result = new Hashtable ();
629 if (other != null) {
630 int i = 0;
631 foreach (XMLClass c in other) {
632 result [c.Name] = i++;
636 return result;
639 public string Name {
640 get { return name; }
644 class XMLClass : XMLData
646 string name;
647 string type;
648 string baseName;
649 bool isSealed;
650 bool isSerializable;
651 bool isAbstract;
652 string charSet;
653 string layout;
654 XMLAttributes attributes;
655 XMLInterfaces interfaces;
656 XMLGenericTypeConstraints genericConstraints;
657 XMLFields fields;
658 XMLConstructors constructors;
659 XMLProperties properties;
660 XMLEvents events;
661 XMLMethods methods;
662 XMLClass [] nested;
664 public override void LoadData (XmlNode node)
666 if (node == null)
667 throw new ArgumentNullException ("node");
669 name = node.Attributes ["name"].Value;
670 type = node.Attributes ["type"].Value;
671 XmlAttribute xatt = node.Attributes ["base"];
672 if (xatt != null)
673 baseName = xatt.Value;
675 xatt = node.Attributes ["sealed"];
676 isSealed = (xatt != null && xatt.Value == "true");
678 xatt = node.Attributes ["abstract"];
679 isAbstract = (xatt != null && xatt.Value == "true");
681 xatt = node.Attributes["serializable"];
682 isSerializable = (xatt != null && xatt.Value == "true");
684 xatt = node.Attributes["charset"];
685 if (xatt != null)
686 charSet = xatt.Value;
688 xatt = node.Attributes["layout"];
689 if (xatt != null)
690 layout = xatt.Value;
692 XmlNode child = node.FirstChild;
693 if (child == null) {
694 // Console.Error.WriteLine ("Empty class {0} {1}", name, type);
695 return;
698 if (child.Name == "attributes") {
699 attributes = new XMLAttributes ();
700 attributes.LoadData (child);
701 child = child.NextSibling;
704 if (child != null && child.Name == "interfaces") {
705 interfaces = new XMLInterfaces ();
706 interfaces.LoadData (child);
707 child = child.NextSibling;
710 if (child != null && child.Name == "generic-type-constraints") {
711 genericConstraints = new XMLGenericTypeConstraints ();
712 genericConstraints.LoadData (child);
713 child = child.NextSibling;
716 if (child != null && child.Name == "fields") {
717 fields = new XMLFields ();
718 fields.LoadData (child);
719 child = child.NextSibling;
722 if (child != null && child.Name == "constructors") {
723 constructors = new XMLConstructors ();
724 constructors.LoadData (child);
725 child = child.NextSibling;
728 if (child != null && child.Name == "properties") {
729 properties = new XMLProperties ();
730 properties.LoadData (child);
731 child = child.NextSibling;
734 if (child != null && child.Name == "events") {
735 events = new XMLEvents ();
736 events.LoadData (child);
737 child = child.NextSibling;
740 if (child != null && child.Name == "methods") {
741 methods = new XMLMethods ();
742 methods.LoadData (child);
743 child = child.NextSibling;
746 if (child != null && child.Name == "generic-parameters") {
747 // HACK: ignore this tag as it doesn't seem to
748 // add any value when checking for differences
749 return;
752 if (child == null)
753 return;
755 if (child.Name != "classes") {
756 Console.WriteLine ("name: {0} type: {1} {2}", name, type, child.NodeType);
757 throw new FormatException ("Expecting <classes>. Got <" + child.Name + ">");
760 nested = (XMLClass []) LoadRecursive (child.ChildNodes, typeof (XMLClass));
763 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
765 this.document = doc;
766 XMLClass oclass = (XMLClass) other;
768 if (attributes != null || oclass.attributes != null) {
769 if (attributes == null)
770 attributes = new XMLAttributes ();
772 attributes.CompareTo (doc, parent, oclass.attributes);
773 counters.AddPartialToPartial (attributes.Counters);
774 if (oclass.attributes != null && oclass.attributes.IsTodo) {
775 counters.Todo++;
776 counters.TodoTotal++;
777 counters.ErrorTotal++;
778 AddAttribute (parent, "error", "todo");
779 if (oclass.attributes.Comment != null)
780 AddAttribute (parent, "comment", oclass.attributes.Comment);
784 if (type != oclass.type)
785 AddWarning (parent, "Class type is wrong: {0} != {1}", type, oclass.type);
787 if (baseName != oclass.baseName)
788 AddWarning (parent, "Base class is wrong: {0} != {1}", baseName, oclass.baseName);
790 if (isAbstract != oclass.isAbstract || isSealed != oclass.isSealed) {
791 if ((isAbstract && isSealed) || (oclass.isAbstract && oclass.isSealed))
792 AddWarning (parent, "Should {0}be static", (isAbstract && isSealed) ? "" : "not ");
793 else if (isAbstract != oclass.isAbstract)
794 AddWarning (parent, "Should {0}be abstract", isAbstract ? "" : "not ");
795 else if (isSealed != oclass.isSealed)
796 AddWarning (parent, "Should {0}be sealed", isSealed ? "" : "not ");
799 if (isSerializable != oclass.isSerializable)
800 AddWarning (parent, "Should {0}be serializable", isSerializable ? "" : "not ");
802 if (charSet != oclass.charSet)
803 AddWarning (parent, "CharSet is wrong: {0} != {1}", charSet, oclass.charSet);
805 if (layout != oclass.layout)
806 AddWarning (parent, "Layout is wrong: {0} != {1}", layout, oclass.layout);
808 if (interfaces != null || oclass.interfaces != null) {
809 if (interfaces == null)
810 interfaces = new XMLInterfaces ();
812 interfaces.CompareTo (doc, parent, oclass.interfaces);
813 counters.AddPartialToPartial (interfaces.Counters);
816 if (genericConstraints != null || oclass.genericConstraints != null) {
817 if (genericConstraints == null)
818 genericConstraints = new XMLGenericTypeConstraints ();
820 genericConstraints.CompareTo (doc, parent, oclass.genericConstraints);
821 counters.AddPartialToPartial (genericConstraints.Counters);
824 if (fields != null || oclass.fields != null) {
825 if (fields == null)
826 fields = new XMLFields ();
828 fields.CompareTo (doc, parent, oclass.fields);
829 counters.AddPartialToPartial (fields.Counters);
832 if (constructors != null || oclass.constructors != null) {
833 if (constructors == null)
834 constructors = new XMLConstructors ();
836 constructors.CompareTo (doc, parent, oclass.constructors);
837 counters.AddPartialToPartial (constructors.Counters);
840 if (properties != null || oclass.properties != null) {
841 if (properties == null)
842 properties = new XMLProperties ();
844 properties.CompareTo (doc, parent, oclass.properties);
845 counters.AddPartialToPartial (properties.Counters);
848 if (events != null || oclass.events != null) {
849 if (events == null)
850 events = new XMLEvents ();
852 events.CompareTo (doc, parent, oclass.events);
853 counters.AddPartialToPartial (events.Counters);
856 if (methods != null || oclass.methods != null) {
857 if (methods == null)
858 methods = new XMLMethods ();
860 methods.CompareTo (doc, parent, oclass.methods);
861 counters.AddPartialToPartial (methods.Counters);
864 if (nested != null || oclass.nested != null) {
865 XmlNode n = doc.CreateElement ("classes", null);
866 parent.AppendChild (n);
867 CompareTypes (n, oclass.nested);
870 AddCountersAttributes (parent);
873 void CompareTypes (XmlNode parent, XMLClass [] other)
875 ArrayList newNodes = new ArrayList ();
876 Hashtable oh = CreateHash (other);
877 XmlNode node = null;
878 int count = (nested == null) ? 0 : nested.Length;
879 for (int i = 0; i < count; i++) {
880 XMLClass xclass = nested [i];
882 node = document.CreateElement ("class", null);
883 newNodes.Add (node);
884 AddAttribute (node, "name", xclass.Name);
885 AddAttribute (node, "type", xclass.Type);
887 if (oh.ContainsKey (xclass.Name)) {
888 int idx = (int) oh [xclass.Name];
889 xclass.CompareTo (document, node, other [idx]);
890 other [idx] = null;
891 counters.AddPartialToPartial (xclass.Counters);
892 } else {
893 // TODO: Should I count here?
894 AddAttribute (node, "presence", "missing");
895 counters.Missing++;
896 counters.MissingTotal++;
900 if (other != null) {
901 count = other.Length;
902 for (int i = 0; i < count; i++) {
903 XMLClass c = other [i];
904 if (c == null || IsMonoTODOAttribute (c.Name))
905 continue;
907 node = document.CreateElement ("class", null);
908 newNodes.Add (node);
909 AddAttribute (node, "name", c.Name);
910 AddAttribute (node, "type", c.Type);
911 AddExtra (node);
912 counters.Extra++;
913 counters.ExtraTotal++;
917 XmlNode [] nodes = (XmlNode []) newNodes.ToArray (typeof (XmlNode));
918 Array.Sort (nodes, XmlNodeComparer.Default);
919 foreach (XmlNode nn in nodes)
920 parent.AppendChild (nn);
923 static Hashtable CreateHash (XMLClass [] other)
925 Hashtable result = new Hashtable ();
926 if (other != null) {
927 int i = 0;
928 foreach (XMLClass c in other) {
929 result [c.Name] = i++;
933 return result;
936 public string Name {
937 get { return name; }
940 public string Type {
941 get { return type; }
945 class XMLParameter : XMLData
947 string name;
948 string type;
949 string attrib;
950 string direction;
951 bool isUnsafe;
952 bool isOptional;
953 string defaultValue;
954 XMLAttributes attributes;
956 public override void LoadData (XmlNode node)
958 if (node == null)
959 throw new ArgumentNullException ("node");
961 if (node.Name != "parameter")
962 throw new ArgumentException ("Expecting <parameter>");
964 name = node.Attributes["name"].Value;
965 type = node.Attributes["type"].Value;
966 attrib = node.Attributes["attrib"].Value;
967 if (node.Attributes ["direction"] != null)
968 direction = node.Attributes["direction"].Value;
969 if (node.Attributes["unsafe"] != null)
970 isUnsafe = bool.Parse (node.Attributes["unsafe"].Value);
971 if (node.Attributes["optional"] != null)
972 isOptional = bool.Parse (node.Attributes["optional"].Value);
973 if (node.Attributes["defaultValue"] != null)
974 defaultValue = node.Attributes["defaultValue"].Value;
976 XmlNode child = node.FirstChild;
977 if (child == null)
978 return;
980 if (child.Name == "attributes") {
981 attributes = new XMLAttributes ();
982 attributes.LoadData (child);
983 child = child.NextSibling;
987 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
989 this.document = doc;
991 XMLParameter oparm = (XMLParameter) other;
993 if (name != oparm.name)
994 AddWarning (parent, "Parameter name is wrong: {0} != {1}", name, oparm.name);
996 if (type != oparm.type)
997 AddWarning (parent, "Parameter type is wrong: {0} != {1}", type, oparm.type);
999 if (attrib != oparm.attrib)
1000 AddWarning (parent, "Parameter attributes wrong: {0} != {1}", attrib, oparm.attrib);
1002 if (direction != oparm.direction)
1003 AddWarning (parent, "Parameter direction wrong: {0} != {1}", direction, oparm.direction);
1005 if (isUnsafe != oparm.isUnsafe)
1006 AddWarning (parent, "Parameter unsafe wrong: {0} != {1}", isUnsafe, oparm.isUnsafe);
1008 if (isOptional != oparm.isOptional)
1009 AddWarning (parent, "Parameter optional wrong: {0} != {1}", isOptional, oparm.isOptional);
1011 if (defaultValue != oparm.defaultValue)
1012 AddWarning (parent, "Parameter default value wrong: {0} != {1}", (defaultValue == null) ? "(no default value)" : defaultValue, (oparm.defaultValue == null) ? "(no default value)" : oparm.defaultValue);
1014 if (attributes != null || oparm.attributes != null) {
1015 if (attributes == null)
1016 attributes = new XMLAttributes ();
1018 attributes.CompareTo (doc, parent, oparm.attributes);
1019 counters.AddPartialToPartial (attributes.Counters);
1020 if (oparm.attributes != null && oparm.attributes.IsTodo) {
1021 counters.Todo++;
1022 counters.TodoTotal++;
1023 counters.ErrorTotal++;
1024 AddAttribute (parent, "error", "todo");
1025 if (oparm.attributes.Comment != null)
1026 AddAttribute (parent, "comment", oparm.attributes.Comment);
1031 public string Name {
1032 get { return name; }
1036 class XMLAttributeProperties: XMLNameGroup
1038 static Hashtable ignored_properties;
1039 static XMLAttributeProperties ()
1041 ignored_properties = new Hashtable ();
1042 ignored_properties.Add ("System.Reflection.AssemblyKeyFileAttribute", "KeyFile");
1043 ignored_properties.Add ("System.Reflection.AssemblyCompanyAttribute", "Company");
1044 ignored_properties.Add ("System.Reflection.AssemblyConfigurationAttribute", "Configuration");
1045 ignored_properties.Add ("System.Reflection.AssemblyCopyrightAttribute", "Copyright");
1046 ignored_properties.Add ("System.Reflection.AssemblyProductAttribute", "Product");
1047 ignored_properties.Add ("System.Reflection.AssemblyTrademarkAttribute", "Trademark");
1048 ignored_properties.Add ("System.Reflection.AssemblyInformationalVersionAttribute", "InformationalVersion");
1050 ignored_properties.Add ("System.ObsoleteAttribute", "Message");
1051 ignored_properties.Add ("System.IO.IODescriptionAttribute", "Description");
1052 ignored_properties.Add ("System.Diagnostics.MonitoringDescriptionAttribute", "Description");
1055 Hashtable properties = new Hashtable ();
1056 string attribute;
1058 public XMLAttributeProperties (string attribute)
1060 this.attribute = attribute;
1063 public override void LoadData(XmlNode node)
1065 if (node == null)
1066 throw new ArgumentNullException ("node");
1068 if (node.ChildNodes == null)
1069 return;
1071 string ignored = ignored_properties [attribute] as string;
1073 foreach (XmlNode n in node.ChildNodes) {
1074 string name = n.Attributes ["name"].Value;
1075 if (ignored == name)
1076 continue;
1078 if (n.Attributes ["null"] != null) {
1079 properties.Add (name, null);
1080 continue;
1082 string value = n.Attributes ["value"].Value;
1083 properties.Add (name, value);
1087 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
1089 this.document = doc;
1091 Hashtable other_properties = ((XMLAttributeProperties)other).properties;
1092 foreach (DictionaryEntry de in other_properties) {
1093 object other_value = properties [de.Key];
1095 if (de.Value == null) {
1096 if (other_value != null)
1097 AddWarning (parent, "Property '{0}' is 'null' and should be '{1}'", de.Key, other_value);
1098 continue;
1101 if (de.Value.Equals (other_value))
1102 continue;
1104 AddWarning (parent, "Property '{0}' is '{1}' and should be '{2}'",
1105 de.Key, de.Value, other_value == null ? "null" : other_value);
1109 public override string GroupName {
1110 get {
1111 return "properties";
1115 public override string Name {
1116 get {
1117 return "";
1122 class XMLAttributes : XMLNameGroup
1124 Hashtable properties = new Hashtable ();
1126 bool isTodo;
1127 string comment;
1129 protected override bool CheckIfAdd (string value, XmlNode node)
1131 if (IsMonoTODOAttribute (value)) {
1132 isTodo = true;
1134 XmlNode pNode = node.SelectSingleNode ("properties");
1135 if (pNode != null && pNode.ChildNodes.Count > 0 && pNode.ChildNodes [0].Attributes ["value"] != null) {
1136 comment = pNode.ChildNodes [0].Attributes ["value"].Value;
1138 return false;
1141 return !IsMeaninglessAttribute (value);
1144 protected override void CompareToInner (string name, XmlNode node, XMLNameGroup other)
1146 XMLAttributeProperties other_prop = ((XMLAttributes)other).properties [name] as XMLAttributeProperties;
1147 XMLAttributeProperties this_prop = properties [name] as XMLAttributeProperties;
1148 if (other_prop == null || this_prop == null)
1149 return;
1151 this_prop.CompareTo (document, node, other_prop);
1152 counters.AddPartialToPartial (this_prop.Counters);
1155 public override string GetNodeKey (string name, XmlNode node)
1157 string key = null;
1159 // if multiple attributes with the same name (type) exist, then we
1160 // cannot be sure which attributes correspond, so we must use the
1161 // name of the attribute (type) and the name/value of its properties
1162 // as key
1164 XmlNodeList attributes = node.ParentNode.SelectNodes("attribute[@name='" + name + "']");
1165 if (attributes.Count > 1) {
1166 ArrayList keyParts = new ArrayList ();
1168 XmlNodeList properties = node.SelectNodes ("properties/property");
1169 foreach (XmlNode property in properties) {
1170 XmlAttributeCollection attrs = property.Attributes;
1171 if (attrs["value"] != null) {
1172 keyParts.Add (attrs["name"].Value + "=" + attrs["value"].Value);
1173 } else {
1174 keyParts.Add (attrs["name"].Value + "=");
1178 // sort properties by name, as order of properties in XML is
1179 // undefined
1180 keyParts.Sort ();
1182 // insert name (type) of attribute
1183 keyParts.Insert (0, name);
1185 StringBuilder sb = new StringBuilder ();
1186 foreach (string value in keyParts) {
1187 sb.Append (value);
1188 sb.Append (';');
1190 key = sb.ToString ();
1191 } else {
1192 key = name;
1195 return key;
1198 protected override void LoadExtraData(string name, XmlNode node)
1200 XmlNode pNode = node.SelectSingleNode ("properties");
1202 if (IsMonoTODOAttribute (name)) {
1203 isTodo = true;
1204 if (pNode.ChildNodes [0].Attributes ["value"] != null) {
1205 comment = pNode.ChildNodes [0].Attributes ["value"].Value;
1207 return;
1210 if (pNode != null) {
1211 XMLAttributeProperties p = new XMLAttributeProperties (name);
1212 p.LoadData (pNode);
1214 properties[name] = p;
1218 public override string GroupName {
1219 get { return "attributes"; }
1222 public override string Name {
1223 get { return "attribute"; }
1226 public bool IsTodo {
1227 get { return isTodo; }
1230 public string Comment {
1231 get { return comment; }
1235 class XMLInterfaces : XMLNameGroup
1237 public override string GroupName {
1238 get { return "interfaces"; }
1241 public override string Name {
1242 get { return "interface"; }
1246 abstract class XMLGenericGroup : XMLNameGroup
1248 string attributes;
1250 protected override void LoadExtraData (string name, XmlNode node)
1252 attributes = ((XmlElement) node).GetAttribute ("generic-attribute");
1255 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1257 base.CompareToInner (name, parent, other);
1259 XMLGenericGroup g = (XMLGenericGroup) other;
1260 if (attributes != g.attributes)
1261 AddWarning (parent, "Incorrect generic attributes: '{0}' != '{1}'", attributes, g.attributes);
1265 class XMLGenericTypeConstraints : XMLGenericGroup
1267 public override string GroupName {
1268 get { return "generic-type-constraints"; }
1271 public override string Name {
1272 get { return "generic-type-constraint"; }
1276 class XMLGenericMethodConstraints : XMLGenericGroup
1278 public override string GroupName {
1279 get { return "generic-method-constraints"; }
1282 public override string Name {
1283 get { return "generic-method-constraint"; }
1287 abstract class XMLMember : XMLNameGroup
1289 Hashtable attributeMap;
1290 Hashtable access = new Hashtable ();
1292 protected override void LoadExtraData (string name, XmlNode node)
1294 XmlAttribute xatt = node.Attributes ["attrib"];
1295 if (xatt != null)
1296 access [name] = xatt.Value;
1298 XmlNode orig = node;
1300 node = node.FirstChild;
1301 while (node != null) {
1302 if (node != null && node.Name == "attributes") {
1303 XMLAttributes a = new XMLAttributes ();
1304 a.LoadData (node);
1305 if (attributeMap == null)
1306 attributeMap = new Hashtable ();
1308 attributeMap [name] = a;
1309 break;
1311 node = node.NextSibling;
1314 base.LoadExtraData (name, orig);
1317 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1319 base.CompareToInner (name, parent, other);
1320 XMLMember mb = other as XMLMember;
1321 XMLAttributes att = null;
1322 XMLAttributes oatt = null;
1323 if (attributeMap != null)
1324 att = attributeMap [name] as XMLAttributes;
1326 if (mb != null && mb.attributeMap != null)
1327 oatt = mb.attributeMap [name] as XMLAttributes;
1329 if (att != null || oatt != null) {
1330 if (att == null)
1331 att = new XMLAttributes ();
1333 att.CompareTo (document, parent, oatt);
1334 counters.AddPartialToPartial(att.Counters);
1335 if (oatt != null && oatt.IsTodo) {
1336 counters.Todo++;
1337 counters.ErrorTotal++;
1338 AddAttribute (parent, "error", "todo");
1339 if (oatt.Comment != null)
1340 AddAttribute (parent, "comment", oatt.Comment);
1344 XMLMember member = (XMLMember) other;
1345 string acc = access [name] as string;
1346 if (acc == null)
1347 return;
1349 string oacc = null;
1350 if (member.access != null)
1351 oacc = member.access [name] as string;
1353 string accName = ConvertToString (Int32.Parse (acc));
1354 string oaccName = "";
1355 if (oacc != null)
1356 oaccName = ConvertToString (Int32.Parse (oacc));
1358 if (accName != oaccName)
1359 AddWarning (parent, "Incorrect attributes: '{0}' != '{1}'", accName, oaccName);
1362 protected virtual string ConvertToString (int att)
1364 return null;
1368 class XMLFields : XMLMember
1370 Hashtable fieldTypes;
1371 Hashtable fieldValues;
1373 protected override void LoadExtraData (string name, XmlNode node)
1375 XmlAttribute xatt = node.Attributes ["fieldtype"];
1376 if (xatt != null) {
1377 if (fieldTypes == null)
1378 fieldTypes = new Hashtable ();
1380 fieldTypes [name] = xatt.Value;
1383 xatt = node.Attributes ["value"];
1384 if (xatt != null) {
1385 if (fieldValues == null)
1386 fieldValues = new Hashtable ();
1388 fieldValues[name] = xatt.Value;
1391 base.LoadExtraData (name, node);
1394 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1396 base.CompareToInner (name, parent, other);
1397 XMLFields fields = (XMLFields) other;
1398 if (fieldTypes != null) {
1399 string ftype = fieldTypes [name] as string;
1400 string oftype = null;
1401 if (fields.fieldTypes != null)
1402 oftype = fields.fieldTypes [name] as string;
1404 if (ftype != oftype)
1405 AddWarning (parent, "Field type is {0} and should be {1}", oftype, ftype);
1407 if (fieldValues != null) {
1408 string fvalue = fieldValues [name] as string;
1409 string ofvalue = null;
1410 if (fields.fieldValues != null)
1411 ofvalue = fields.fieldValues [name] as string;
1413 if (fvalue != ofvalue)
1414 AddWarning (parent, "Field value is {0} and should be {1}", ofvalue, fvalue);
1418 protected override string ConvertToString (int att)
1420 FieldAttributes fa = (FieldAttributes) att;
1421 return fa.ToString ();
1424 public override string GroupName {
1425 get { return "fields"; }
1428 public override string Name {
1429 get { return "field"; }
1433 class XMLParameters : XMLNameGroup
1435 public override void LoadData (XmlNode node)
1437 if (node == null)
1438 throw new ArgumentNullException ("node");
1440 if (node.Name != GroupName)
1441 throw new FormatException (String.Format ("Expecting <{0}>", GroupName));
1443 keys = new Hashtable ();
1444 foreach (XmlNode n in node.ChildNodes) {
1445 string name = n.Attributes["name"].Value;
1446 string key = GetNodeKey (name, n);
1447 XMLParameter parm = new XMLParameter ();
1448 parm.LoadData (n);
1449 keys.Add (key, parm);
1450 LoadExtraData (key, n);
1454 public override string GroupName {
1455 get {
1456 return "parameters";
1460 public override string Name {
1461 get {
1462 return "parameter";
1466 public override string GetNodeKey (string name, XmlNode node)
1468 return node.Attributes["position"].Value;
1471 public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
1473 this.document = doc;
1474 if (group == null)
1475 group = doc.CreateElement (GroupName, null);
1477 Hashtable okeys = null;
1478 if (other != null && ((XMLParameters) other).keys != null) {
1479 okeys = ((XMLParameters) other).keys;
1482 XmlNode node = null;
1483 bool onull = (okeys == null);
1484 if (keys != null) {
1485 foreach (DictionaryEntry entry in keys) {
1486 node = doc.CreateElement (Name, null);
1487 group.AppendChild (node);
1488 string key = (string) entry.Key;
1489 XMLParameter parm = (XMLParameter) entry.Value;
1490 AddAttribute (node, "name", parm.Name);
1492 if (!onull && HasKey (key, okeys)) {
1493 parm.CompareTo (document, node, okeys[key]);
1494 counters.AddPartialToPartial (parm.Counters);
1495 okeys.Remove (key);
1496 counters.Present++;
1497 } else {
1498 AddAttribute (node, "presence", "missing");
1499 counters.Missing++;
1504 if (!onull && okeys.Count != 0) {
1505 foreach (XMLParameter value in okeys.Values) {
1506 node = doc.CreateElement (Name, null);
1507 AddAttribute (node, "name", value.Name);
1508 AddAttribute (node, "presence", "extra");
1509 group.AppendChild (node);
1510 counters.Extra++;
1514 if (group.HasChildNodes)
1515 parent.AppendChild (group);
1519 class XMLProperties : XMLMember
1521 Hashtable nameToMethod = new Hashtable ();
1523 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1525 Counters copy = counters;
1526 counters = new Counters();
1528 XMLProperties oprop = other as XMLProperties;
1529 if (oprop != null) {
1530 XMLMethods m = nameToMethod [name] as XMLMethods;
1531 XMLMethods om = oprop.nameToMethod [name] as XMLMethods;
1532 if (m != null || om != null) {
1533 if (m == null)
1534 m = new XMLMethods ();
1536 m.CompareTo(document, parent, om);
1537 counters.AddPartialToPartial(m.Counters);
1541 base.CompareToInner (name, parent, other);
1542 AddCountersAttributes(parent);
1544 copy.AddPartialToPartial(counters);
1545 counters = copy;
1548 protected override void LoadExtraData (string name, XmlNode node)
1550 XmlNode orig = node;
1551 node = node.FirstChild;
1552 while (node != null) {
1553 if (node != null && node.Name == "methods") {
1554 XMLMethods m = new XMLMethods ();
1555 XmlNode parent = node.ParentNode;
1556 string key = GetNodeKey (name, parent);
1557 m.LoadData (node);
1558 nameToMethod [key] = m;
1559 break;
1561 node = node.NextSibling;
1564 base.LoadExtraData (name, orig);
1567 public override string GetNodeKey (string name, XmlNode node)
1569 XmlAttributeCollection atts = node.Attributes;
1570 return String.Format ("{0}:{1}:{2}",
1571 (atts["name"] != null ? atts["name"].Value : ""),
1572 (atts["ptype"] != null ? atts["ptype"].Value : ""),
1573 (atts["params"] != null ? atts["params"].Value : "")
1577 public override string GroupName {
1578 get { return "properties"; }
1581 public override string Name {
1582 get { return "property"; }
1586 class XMLEvents : XMLMember
1588 Hashtable eventTypes;
1589 Hashtable nameToMethod = new Hashtable ();
1591 protected override void LoadExtraData (string name, XmlNode node)
1593 XmlAttribute xatt = node.Attributes ["eventtype"];
1594 if (xatt != null) {
1595 if (eventTypes == null)
1596 eventTypes = new Hashtable ();
1598 eventTypes [name] = xatt.Value;
1601 XmlNode child = node.FirstChild;
1602 while (child != null) {
1603 if (child != null && child.Name == "methods") {
1604 XMLMethods m = new XMLMethods ();
1605 XmlNode parent = child.ParentNode;
1606 string key = GetNodeKey (name, parent);
1607 m.LoadData (child);
1608 nameToMethod [key] = m;
1609 break;
1611 child = child.NextSibling;
1614 base.LoadExtraData (name, node);
1617 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1619 Counters copy = counters;
1620 counters = new Counters ();
1622 try {
1623 base.CompareToInner (name, parent, other);
1624 AddCountersAttributes (parent);
1625 if (eventTypes == null)
1626 return;
1628 XMLEvents evt = (XMLEvents) other;
1629 string etype = eventTypes [name] as string;
1630 string oetype = null;
1631 if (evt.eventTypes != null)
1632 oetype = evt.eventTypes [name] as string;
1634 if (etype != oetype)
1635 AddWarning (parent, "Event type is {0} and should be {1}", oetype, etype);
1637 XMLMethods m = nameToMethod [name] as XMLMethods;
1638 XMLMethods om = evt.nameToMethod [name] as XMLMethods;
1639 if (m != null || om != null) {
1640 if (m == null)
1641 m = new XMLMethods ();
1643 m.CompareTo (document, parent, om);
1644 counters.AddPartialToPartial (m.Counters);
1646 } finally {
1647 AddCountersAttributes (parent);
1648 copy.AddPartialToPartial (counters);
1649 counters = copy;
1653 protected override string ConvertToString (int att)
1655 EventAttributes ea = (EventAttributes) att;
1656 return ea.ToString ();
1659 public override string GroupName {
1660 get { return "events"; }
1663 public override string Name {
1664 get { return "event"; }
1668 class XMLMethods : XMLMember
1670 Hashtable returnTypes;
1671 Hashtable parameters;
1672 Hashtable genericConstraints;
1673 Hashtable signatureFlags;
1675 [Flags]
1676 enum SignatureFlags
1678 None = 0,
1679 Abstract = 1,
1680 Virtual = 2,
1681 Static = 4,
1682 Final = 8,
1685 protected override void LoadExtraData (string name, XmlNode node)
1687 XmlAttribute xatt = node.Attributes ["returntype"];
1688 if (xatt != null) {
1689 if (returnTypes == null)
1690 returnTypes = new Hashtable ();
1692 returnTypes [name] = xatt.Value;
1695 SignatureFlags flags = SignatureFlags.None;
1696 if (((XmlElement) node).GetAttribute ("abstract") == "true")
1697 flags |= SignatureFlags.Abstract;
1698 if (((XmlElement) node).GetAttribute ("static") == "true")
1699 flags |= SignatureFlags.Static;
1700 if (((XmlElement) node).GetAttribute ("virtual") == "true")
1701 flags |= SignatureFlags.Virtual;
1702 if (((XmlElement) node).GetAttribute ("final") == "true")
1703 flags |= SignatureFlags.Final;
1704 if (flags != SignatureFlags.None) {
1705 if (signatureFlags == null)
1706 signatureFlags = new Hashtable ();
1707 signatureFlags [name] = flags;
1710 XmlNode parametersNode = node.SelectSingleNode ("parameters");
1711 if (parametersNode != null) {
1712 if (parameters == null)
1713 parameters = new Hashtable ();
1715 XMLParameters parms = new XMLParameters ();
1716 parms.LoadData (parametersNode);
1718 parameters[name] = parms;
1721 XmlNode genericNode = node.SelectSingleNode ("generic-method-constraints");
1722 if (genericNode != null) {
1723 if (genericConstraints == null)
1724 genericConstraints = new Hashtable ();
1725 XMLGenericMethodConstraints csts = new XMLGenericMethodConstraints ();
1726 csts.LoadData (genericNode);
1727 genericConstraints [name] = csts;
1730 base.LoadExtraData (name, node);
1733 public override string GetNodeKey (string name, XmlNode node)
1735 // for explicit/implicit operators we need to include the return
1736 // type in the key to allow matching; as a side-effect, differences
1737 // in return types will be reported as extra/missing methods
1739 // for regular methods we do not need to take into account the
1740 // return type for matching methods; differences in return types
1741 // will be reported as a warning on the method
1742 if (name.StartsWith ("op_")) {
1743 XmlAttribute xatt = node.Attributes ["returntype"];
1744 string returnType = xatt != null ? xatt.Value + " " : string.Empty;
1745 return returnType + name;
1747 return name;
1750 protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
1752 // create backup of actual counters
1753 Counters copy = counters;
1754 // initialize counters for current method
1755 counters = new Counters();
1757 try {
1758 base.CompareToInner(name, parent, other);
1759 XMLMethods methods = (XMLMethods) other;
1761 SignatureFlags flags = signatureFlags != null &&
1762 signatureFlags.ContainsKey (name) ?
1763 (SignatureFlags) signatureFlags [name] :
1764 SignatureFlags.None;
1765 SignatureFlags oflags = methods.signatureFlags != null &&
1766 methods.signatureFlags.ContainsKey (name) ?
1767 (SignatureFlags) methods.signatureFlags [name] :
1768 SignatureFlags.None;
1770 if (flags!= oflags) {
1771 if (flags == SignatureFlags.None)
1772 AddWarning (parent, String.Format ("should not be {0}", oflags));
1773 else if (oflags == SignatureFlags.None)
1774 AddWarning (parent, String.Format ("should be {0}", flags));
1775 else
1776 AddWarning (parent, String.Format ("{0} and should be {1}", oflags, flags));
1779 if (returnTypes != null) {
1780 string rtype = returnTypes[name] as string;
1781 string ortype = null;
1782 if (methods.returnTypes != null)
1783 ortype = methods.returnTypes[name] as string;
1785 if (rtype != ortype)
1786 AddWarning (parent, "Return type is {0} and should be {1}", ortype, rtype);
1789 if (parameters != null) {
1790 XMLParameters parms = parameters[name] as XMLParameters;
1791 parms.CompareTo (document, parent, methods.parameters[name]);
1792 counters.AddPartialToPartial (parms.Counters);
1794 } finally {
1795 // output counter attributes in result document
1796 AddCountersAttributes(parent);
1798 // add temporary counters to actual counters
1799 copy.AddPartialToPartial(counters);
1800 // restore backup of actual counters
1801 counters = copy;
1805 protected override string ConvertToString (int att)
1807 MethodAttributes ma = (MethodAttributes) att;
1808 // ignore ReservedMasks
1809 ma &= ~ MethodAttributes.ReservedMask;
1810 ma &= ~ MethodAttributes.VtableLayoutMask;
1811 if ((ma & MethodAttributes.FamORAssem) != 0)
1812 ma = (ma & ~ MethodAttributes.FamORAssem) | MethodAttributes.Family;
1814 // ignore the HasSecurity attribute for now
1815 if ((ma & MethodAttributes.HasSecurity) != 0)
1816 ma = (MethodAttributes) (att - (int) MethodAttributes.HasSecurity);
1818 // ignore the RequireSecObject attribute for now
1819 if ((ma & MethodAttributes.RequireSecObject) != 0)
1820 ma = (MethodAttributes) (att - (int) MethodAttributes.RequireSecObject);
1822 // we don't care if the implementation is forwarded through PInvoke
1823 if ((ma & MethodAttributes.PinvokeImpl) != 0)
1824 ma = (MethodAttributes) (att - (int) MethodAttributes.PinvokeImpl);
1826 return ma.ToString ();
1829 public override string GroupName {
1830 get { return "methods"; }
1833 public override string Name {
1834 get { return "method"; }
1838 class XMLConstructors : XMLMethods
1840 public override string GroupName {
1841 get { return "constructors"; }
1844 public override string Name {
1845 get { return "constructor"; }
1849 class XmlNodeComparer : IComparer
1851 public static XmlNodeComparer Default = new XmlNodeComparer ();
1853 public int Compare (object a, object b)
1855 XmlNode na = (XmlNode) a;
1856 XmlNode nb = (XmlNode) b;
1857 return String.Compare (na.Attributes ["name"].Value, nb.Attributes ["name"].Value);