2 // mono-api-diff.cs - Compares 2 xml files produced by mono-api-info and
3 // produces a file suitable to build class status pages.
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 // (C) 2003 Novell, Inc (http://www.novell.com)
12 using System
.Collections
;
14 using System
.Reflection
;
18 namespace Mono
.AssemblyCompare
22 static int Main (string [] args
)
27 XMLAssembly ms
= CreateXMLAssembly (args
[0]);
28 XMLAssembly mono
= CreateXMLAssembly (args
[1]);
29 XmlDocument doc
= ms
.CompareAndGetDocument (mono
);
31 XmlTextWriter writer
= new XmlTextWriter (Console
.Out
);
32 writer
.Formatting
= Formatting
.Indented
;
38 static XMLAssembly
CreateXMLAssembly (string file
)
40 XmlDocument doc
= new XmlDocument ();
41 doc
.Load (File
.OpenRead (file
));
43 XmlNode node
= doc
.SelectSingleNode ("/assemblies/assembly");
44 XMLAssembly result
= new XMLAssembly ();
46 result
.LoadData (node
);
47 } catch (Exception e
) {
48 Console
.Error
.WriteLine ("Error loading {0}: {1}\n{2}", file
, e
.Message
, e
);
59 public int PresentTotal
;
61 public int MissingTotal
;
66 public int ExtraTotal
;
68 public int WarningTotal
;
69 public int ErrorTotal
;
75 public void AddPartialToPartial (Counters other
)
77 Present
+= other
.Present
;
79 Missing
+= other
.Missing
;
82 Warning
+= other
.Warning
;
83 AddPartialToTotal (other
);
86 public void AddPartialToTotal (Counters other
)
88 PresentTotal
+= other
.Present
;
89 ExtraTotal
+= other
.Extra
;
90 MissingTotal
+= other
.Missing
;
92 TodoTotal
+= other
.Todo
;
93 WarningTotal
+= other
.Warning
;
96 public void AddTotalToPartial (Counters other
)
98 Present
+= other
.PresentTotal
;
99 Extra
+= other
.ExtraTotal
;
100 Missing
+= other
.MissingTotal
;
102 Todo
+= other
.TodoTotal
;
103 Warning
+= other
.WarningTotal
;
104 AddTotalToTotal (other
);
107 public void AddTotalToTotal (Counters other
)
109 PresentTotal
+= other
.PresentTotal
;
110 ExtraTotal
+= other
.ExtraTotal
;
111 MissingTotal
+= other
.MissingTotal
;
113 TodoTotal
+= other
.TodoTotal
;
114 WarningTotal
+= other
.WarningTotal
;
115 ErrorTotal
+= other
.ErrorTotal
;
119 get { return Present + Missing; }
122 public int AbsTotal
{
123 get { return PresentTotal + MissingTotal; }
127 get { return Present - Todo; }
131 get { return PresentTotal - TodoTotal - ErrorTotal; }
134 public override string ToString ()
136 StringWriter sw
= new StringWriter ();
137 sw
.WriteLine ("Present: {0}", Present
);
138 sw
.WriteLine ("PresentTotal: {0}", PresentTotal
);
139 sw
.WriteLine ("Missing: {0}", Missing
);
140 sw
.WriteLine ("MissingTotal: {0}", MissingTotal
);
141 sw
.WriteLine ("Todo: {0}", Todo
);
142 sw
.WriteLine ("TodoTotal: {0}", TodoTotal
);
143 sw
.WriteLine ("Extra: {0}", Extra
);
144 sw
.WriteLine ("ExtraTotal: {0}", ExtraTotal
);
145 sw
.WriteLine ("Warning: {0}", Warning
);
146 sw
.WriteLine ("WarningTotal: {0}", WarningTotal
);
147 sw
.WriteLine ("ErrorTotal: {0}", ErrorTotal
);
149 return sw
.GetStringBuilder ().ToString ();
153 abstract class XMLData
155 protected XmlDocument document
;
156 protected Counters counters
;
161 counters
= new Counters ();
164 public virtual void LoadData (XmlNode node
)
168 protected object [] LoadRecursive (XmlNodeList nodeList
, Type type
)
170 ArrayList list
= new ArrayList ();
171 foreach (XmlNode node
in nodeList
) {
172 XMLData data
= (XMLData
) Activator
.CreateInstance (type
);
173 data
.LoadData (node
);
177 return (object []) list
.ToArray (type
);
180 protected void AddAttribute (XmlNode node
, string name
, string value)
182 XmlAttribute attr
= document
.CreateAttribute (name
);
184 node
.Attributes
.Append (attr
);
187 protected void AddExtra (XmlNode node
)
189 //TODO: count all the subnodes?
190 AddAttribute (node
, "presence", "extra");
191 AddAttribute (node
, "ok", "1");
192 AddAttribute (node
, "ok_total", "1");
193 AddAttribute (node
, "extra", "1");
194 AddAttribute (node
, "extra_total", "1");
197 public void AddCountersAttributes (XmlNode node
)
199 if (counters
.Missing
> 0)
200 AddAttribute (node
, "missing", counters
.Missing
.ToString ());
202 if (counters
.Present
> 0)
203 AddAttribute (node
, "present", counters
.Present
.ToString ());
205 if (counters
.Extra
> 0)
206 AddAttribute (node
, "extra", counters
.Extra
.ToString ());
209 AddAttribute (node
, "ok", counters
.Ok
.ToString ());
211 if (counters
.Total
> 0) {
212 int percent
= (100 * counters
.Ok
/ counters
.Total
);
213 AddAttribute (node
, "complete", percent
.ToString ());
216 if (counters
.Todo
> 0)
217 AddAttribute (node
, "todo", counters
.Todo
.ToString ());
219 if (counters
.Warning
> 0)
220 AddAttribute (node
, "warning", counters
.Warning
.ToString ());
222 if (counters
.MissingTotal
> 0)
223 AddAttribute (node
, "missing_total", counters
.MissingTotal
.ToString ());
225 if (counters
.PresentTotal
> 0)
226 AddAttribute (node
, "present_total", counters
.PresentTotal
.ToString ());
228 if (counters
.ExtraTotal
> 0)
229 AddAttribute (node
, "extra_total", counters
.ExtraTotal
.ToString ());
231 if (counters
.OkTotal
> 0)
232 AddAttribute (node
, "ok_total", counters
.OkTotal
.ToString ());
234 if (counters
.AbsTotal
> 0) {
235 int percent
= (100 * counters
.OkTotal
/ counters
.AbsTotal
);
236 AddAttribute (node
, "complete_total", percent
.ToString ());
239 if (counters
.TodoTotal
> 0) {
240 AddAttribute (node
, "todo_total", counters
.TodoTotal
.ToString ());
241 //TODO: should be different on error. check error cases in corcompare.
242 AddAttribute (node
, "error_total", counters
.Todo
.ToString ());
245 if (counters
.WarningTotal
> 0)
246 AddAttribute (node
, "warning_total", counters
.WarningTotal
.ToString ());
250 protected void AddWarning (XmlNode parent
, string fmt
, params object [] args
)
254 XmlNode warnings
= parent
.SelectSingleNode ("warnings");
255 if (warnings
== null) {
256 warnings
= document
.CreateElement ("warnings", null);
257 parent
.AppendChild (warnings
);
260 AddAttribute (parent
, "error", "warning");
261 XmlNode warning
= document
.CreateElement ("warning", null);
262 AddAttribute (warning
, "text", String
.Format (fmt
, args
));
263 warnings
.AppendChild (warning
);
266 public bool HaveWarnings
{
267 get { return haveWarnings; }
270 public Counters Counters
{
271 get { return counters; }
274 public abstract void CompareTo (XmlDocument doc
, XmlNode parent
, object other
);
277 abstract class XMLNameGroup
: XMLData
279 protected XmlNode
group;
280 protected Hashtable keys
;
282 public override void LoadData (XmlNode node
)
285 throw new ArgumentNullException ("node");
287 if (node
.Name
!= GroupName
)
288 throw new FormatException (String
.Format ("Expecting <{0}>", GroupName
));
290 keys
= new Hashtable ();
291 foreach (XmlNode n
in node
.ChildNodes
) {
292 string name
= n
.Attributes
["name"].Value
;
293 if (CheckIfAdd (name
, n
)) {
294 string key
= GetNodeKey (name
, n
);
295 keys
.Add (key
, name
);
296 LoadExtraData (key
, n
);
301 protected virtual bool CheckIfAdd (string value, XmlNode node
)
306 protected virtual void LoadExtraData (string name
, XmlNode node
)
310 public override void CompareTo (XmlDocument doc
, XmlNode parent
, object other
)
314 group = doc
.CreateElement (GroupName
, null);
316 Hashtable okeys
= null;
317 if (other
!= null && ((XMLNameGroup
) other
).keys
!= null) {
318 okeys
= ((XMLNameGroup
) other
).keys
;
322 bool onull
= (okeys
== null);
324 foreach (DictionaryEntry entry
in keys
) {
325 node
= doc
.CreateElement (Name
, null);
326 group.AppendChild (node
);
327 string key
= (string) entry
.Key
;
328 string name
= (string) entry
.Value
;
329 AddAttribute (node
, "name", name
);
331 if (!onull
&& HasKey (key
, okeys
)) {
332 CompareToInner (key
, node
, (XMLNameGroup
) other
);
336 AddAttribute (node
, "presence", "missing");
342 if (!onull
&& okeys
.Count
!= 0) {
343 foreach (string value in okeys
.Values
) {
344 node
= doc
.CreateElement (Name
, null);
345 AddAttribute (node
, "name", (string) value);
346 AddAttribute (node
, "presence", "extra");
347 group.AppendChild (node
);
352 if (group.HasChildNodes
)
353 parent
.AppendChild (group);
356 protected virtual void CompareToInner (string name
, XmlNode node
, XMLNameGroup other
)
360 public virtual string GetNodeKey (string name
, XmlNode node
)
365 public virtual bool HasKey (string key
, Hashtable other
)
367 return other
.ContainsKey (key
);
370 public abstract string GroupName { get; }
371 public abstract string Name { get; }
374 class XMLAssembly
: XMLData
376 XMLAttributes attributes
;
377 XMLNamespace
[] namespaces
;
381 public override void LoadData (XmlNode node
)
384 throw new ArgumentNullException ("node");
386 name
= node
.Attributes
["name"].Value
;
387 version
= node
.Attributes
["version"].Value
;
388 XmlNode atts
= node
.FirstChild
;
389 attributes
= new XMLAttributes ();
390 if (atts
.Name
== "attributes") {
391 attributes
.LoadData (atts
);
392 atts
= atts
.NextSibling
;
395 if (atts
== null || atts
.Name
!= "namespaces") {
396 Console
.Error
.WriteLine ("Warning: no namespaces found!");
400 namespaces
= (XMLNamespace
[]) LoadRecursive (atts
.ChildNodes
, typeof (XMLNamespace
));
403 public override void CompareTo (XmlDocument doc
, XmlNode parent
, object other
)
405 XMLAssembly assembly
= (XMLAssembly
) other
;
407 XmlNode childA
= doc
.CreateElement ("assembly", null);
408 AddAttribute (childA
, "name", name
);
409 AddAttribute (childA
, "version", version
);
410 if (name
!= assembly
.name
)
411 AddWarning (childA
, "Assembly names not equal: {0}, {1}", name
, assembly
.name
);
413 if (version
!= assembly
.version
)
414 AddWarning (childA
, "Assembly version not equal: {0}, {1}", version
, assembly
.version
);
416 parent
.AppendChild (childA
);
418 attributes
.CompareTo (doc
, childA
, assembly
.attributes
);
419 counters
.AddPartialToPartial (attributes
.Counters
);
421 CompareNamespaces (childA
, assembly
.namespaces
);
422 if (assembly
.attributes
!= null && assembly
.attributes
.IsTodo
) {
424 counters
.TodoTotal
++;
425 counters
.ErrorTotal
++;
426 AddAttribute (childA
, "error", "todo");
427 if (assembly
.attributes
.Comment
!= null)
428 AddAttribute (childA
, "comment", assembly
.attributes
.Comment
);
431 AddCountersAttributes (childA
);
434 void CompareNamespaces (XmlNode parent
, XMLNamespace
[] other
)
436 ArrayList newNS
= new ArrayList ();
437 XmlNode
group = document
.CreateElement ("namespaces", null);
438 parent
.AppendChild (group);
440 Hashtable oh
= CreateHash (other
);
442 int count
= (namespaces
== null) ? 0 : namespaces
.Length
;
443 for (int i
= 0; i
< count
; i
++) {
444 XMLNamespace xns
= namespaces
[i
];
446 node
= document
.CreateElement ("namespace", null);
448 AddAttribute (node
, "name", xns
.Name
);
450 if (oh
.ContainsKey (xns
.Name
)) {
451 int idx
= (int) oh
[xns
.Name
];
452 xns
.CompareTo (document
, node
, other
[idx
]);
454 xns
.AddCountersAttributes (node
);
456 counters
.PresentTotal
++;
457 counters
.AddPartialToTotal (xns
.Counters
);
459 AddAttribute (node
, "presence", "missing");
461 counters
.MissingTotal
++;
466 count
= other
.Length
;
467 for (int i
= 0; i
< count
; i
++) {
468 XMLNamespace n
= other
[i
];
472 node
= document
.CreateElement ("namespace", null);
474 AddAttribute (node
, "name", n
.Name
);
476 counters
.ExtraTotal
++;
480 XmlNode
[] nodes
= (XmlNode
[]) newNS
.ToArray (typeof (XmlNode
));
481 Array
.Sort (nodes
, XmlNodeComparer
.Default
);
482 foreach (XmlNode nn
in nodes
)
483 group.AppendChild (nn
);
486 static Hashtable
CreateHash (XMLNamespace
[] other
)
488 Hashtable result
= new Hashtable ();
491 foreach (XMLNamespace n
in other
) {
492 result
[n
.Name
] = i
++;
499 public XmlDocument
CompareAndGetDocument (XMLAssembly other
)
501 XmlDocument doc
= new XmlDocument ();
503 XmlNode parent
= doc
.CreateElement ("assemblies", null);
504 doc
.AppendChild (parent
);
506 CompareTo (doc
, parent
, other
);
508 XmlNode decl
= doc
.CreateXmlDeclaration ("1.0", null, null);
509 doc
.InsertBefore (decl
, doc
.DocumentElement
);
515 class XMLNamespace
: XMLData
520 public override void LoadData (XmlNode node
)
523 throw new ArgumentNullException ("node");
525 if (node
.Name
!= "namespace")
526 throw new FormatException ("Expecting <namespace>");
528 name
= node
.Attributes
["name"].Value
;
529 XmlNode classes
= node
.FirstChild
;
530 if (classes
== null) {
531 Console
.Error
.WriteLine ("Warning: no classes for {0}", node
.Attributes
["name"]);
535 if (classes
.Name
!= "classes")
536 throw new FormatException ("Expecting <classes>. Got <" + classes
.Name
+ ">");
538 types
= (XMLClass
[]) LoadRecursive (classes
.ChildNodes
, typeof (XMLClass
));
541 public override void CompareTo (XmlDocument doc
, XmlNode parent
, object other
)
544 XMLNamespace nspace
= (XMLNamespace
) other
;
546 XmlNode childA
= doc
.CreateElement ("classes", null);
547 parent
.AppendChild (childA
);
549 CompareTypes (childA
, nspace
.types
);
552 void CompareTypes (XmlNode parent
, XMLClass
[] other
)
554 ArrayList newNodes
= new ArrayList ();
555 Hashtable oh
= CreateHash (other
);
557 int count
= (types
== null) ? 0 : types
.Length
;
558 for (int i
= 0; i
< count
; i
++) {
559 XMLClass xclass
= types
[i
];
561 node
= document
.CreateElement ("class", null);
563 AddAttribute (node
, "name", xclass
.Name
);
564 AddAttribute (node
, "type", xclass
.Type
);
566 if (oh
.ContainsKey (xclass
.Name
)) {
567 int idx
= (int) oh
[xclass
.Name
];
568 xclass
.CompareTo (document
, node
, other
[idx
]);
570 counters
.AddPartialToPartial (xclass
.Counters
);
572 AddAttribute (node
, "presence", "missing");
574 counters
.MissingTotal
++;
579 count
= other
.Length
;
580 for (int i
= 0; i
< count
; i
++) {
581 XMLClass c
= other
[i
];
582 if (c
== null || c
.Name
.EndsWith ("TODOAttribute"))
585 node
= document
.CreateElement ("class", null);
587 AddAttribute (node
, "name", c
.Name
);
588 AddAttribute (node
, "type", c
.Type
);
591 counters
.ExtraTotal
++;
595 XmlNode
[] nodes
= (XmlNode
[]) newNodes
.ToArray (typeof (XmlNode
));
596 Array
.Sort (nodes
, XmlNodeComparer
.Default
);
597 foreach (XmlNode nn
in nodes
)
598 parent
.AppendChild (nn
);
601 static Hashtable
CreateHash (XMLClass
[] other
)
603 Hashtable result
= new Hashtable ();
606 foreach (XMLClass c
in other
) {
607 result
[c
.Name
] = i
++;
619 class XMLClass
: XMLData
629 XMLAttributes attributes
;
630 XMLInterfaces interfaces
;
632 XMLConstructors constructors
;
633 XMLProperties properties
;
638 public override void LoadData (XmlNode node
)
641 throw new ArgumentNullException ("node");
643 name
= node
.Attributes
["name"].Value
;
644 type
= node
.Attributes
["type"].Value
;
645 XmlAttribute xatt
= node
.Attributes
["base"];
647 baseName
= xatt
.Value
;
649 xatt
= node
.Attributes
["sealed"];
650 isSealed
= (xatt
!= null && xatt
.Value
== "true");
652 xatt
= node
.Attributes
["abstract"];
653 isAbstract
= (xatt
!= null && xatt
.Value
== "true");
655 xatt
= node
.Attributes
["serializable"];
656 isSerializable
= (xatt
!= null && xatt
.Value
== "true");
658 xatt
= node
.Attributes
["charset"];
660 charSet
= xatt
.Value
;
662 xatt
= node
.Attributes
["layout"];
666 XmlNode child
= node
.FirstChild
;
668 // Console.Error.WriteLine ("Empty class {0} {1}", name, type);
672 if (child
.Name
== "attributes") {
673 attributes
= new XMLAttributes ();
674 attributes
.LoadData (child
);
675 child
= child
.NextSibling
;
678 if (child
!= null && child
.Name
== "interfaces") {
679 interfaces
= new XMLInterfaces ();
680 interfaces
.LoadData (child
);
681 child
= child
.NextSibling
;
684 if (child
!= null && child
.Name
== "fields") {
685 fields
= new XMLFields ();
686 fields
.LoadData (child
);
687 child
= child
.NextSibling
;
690 if (child
!= null && child
.Name
== "constructors") {
691 constructors
= new XMLConstructors ();
692 constructors
.LoadData (child
);
693 child
= child
.NextSibling
;
696 if (child
!= null && child
.Name
== "properties") {
697 properties
= new XMLProperties ();
698 properties
.LoadData (child
);
699 child
= child
.NextSibling
;
702 if (child
!= null && child
.Name
== "events") {
703 events
= new XMLEvents ();
704 events
.LoadData (child
);
705 child
= child
.NextSibling
;
708 if (child
!= null && child
.Name
== "methods") {
709 methods
= new XMLMethods ();
710 methods
.LoadData (child
);
711 child
= child
.NextSibling
;
717 if (child
.Name
!= "classes") {
718 Console
.WriteLine ("name: {0} type: {1} {2}", name
, type
, child
.NodeType
);
719 throw new FormatException ("Expecting <classes>. Got <" + child
.Name
+ ">");
722 nested
= (XMLClass
[]) LoadRecursive (child
.ChildNodes
, typeof (XMLClass
));
725 public override void CompareTo (XmlDocument doc
, XmlNode parent
, object other
)
728 XMLClass oclass
= (XMLClass
) other
;
730 if (attributes
!= null || oclass
.attributes
!= null) {
731 if (attributes
== null)
732 attributes
= new XMLAttributes ();
734 attributes
.CompareTo (doc
, parent
, oclass
.attributes
);
735 counters
.AddPartialToPartial (attributes
.Counters
);
736 if (oclass
.attributes
!= null && oclass
.attributes
.IsTodo
) {
738 counters
.TodoTotal
++;
739 counters
.ErrorTotal
++;
740 AddAttribute (parent
, "error", "todo");
741 if (oclass
.attributes
.Comment
!= null)
742 AddAttribute (parent
, "comment", oclass
.attributes
.Comment
);
746 if (type
!= oclass
.type
)
747 AddWarning (parent
, "Class type is wrong: {0} != {1}", type
, oclass
.type
);
749 if (baseName
!= oclass
.baseName
)
750 AddWarning (parent
, "Base class is wrong: {0} != {1}", baseName
, oclass
.baseName
);
752 if (isAbstract
!= oclass
.isAbstract
|| isSealed
!= oclass
.isSealed
) {
753 if ((isAbstract
&& isSealed
) || (!oclass
.isAbstract
&& !oclass
.isSealed
))
754 AddWarning (parent
, "Should {0}be static", isAbstract
? "" : "not ");
755 else if (isAbstract
!= oclass
.isAbstract
)
756 AddWarning (parent
, "Should {0}be abstract", isAbstract
? "" : "not ");
757 else if (isSealed
!= oclass
.isSealed
)
758 AddWarning (parent
, "Should {0}be sealed", isSealed
? "" : "not ");
761 if (isSerializable
!= oclass
.isSerializable
)
762 AddWarning (parent
, "Should {0}be serializable", isSerializable
? "" : "not ");
764 if (charSet
!= oclass
.charSet
)
765 AddWarning (parent
, "CharSet is wrong: {0} != {1}", charSet
, oclass
.charSet
);
767 if (layout
!= oclass
.layout
)
768 AddWarning (parent
, "Layout is wrong: {0} != {1}", layout
, oclass
.layout
);
770 if (interfaces
!= null || oclass
.interfaces
!= null) {
771 if (interfaces
== null)
772 interfaces
= new XMLInterfaces ();
774 interfaces
.CompareTo (doc
, parent
, oclass
.interfaces
);
775 counters
.AddPartialToPartial (interfaces
.Counters
);
778 if (fields
!= null || oclass
.fields
!= null) {
780 fields
= new XMLFields ();
782 fields
.CompareTo (doc
, parent
, oclass
.fields
);
783 counters
.AddPartialToPartial (fields
.Counters
);
786 if (constructors
!= null || oclass
.constructors
!= null) {
787 if (constructors
== null)
788 constructors
= new XMLConstructors ();
790 constructors
.CompareTo (doc
, parent
, oclass
.constructors
);
791 counters
.AddPartialToPartial (constructors
.Counters
);
794 if (properties
!= null || oclass
.properties
!= null) {
795 if (properties
== null)
796 properties
= new XMLProperties ();
798 properties
.CompareTo (doc
, parent
, oclass
.properties
);
799 counters
.AddPartialToPartial (properties
.Counters
);
802 if (events
!= null || oclass
.events
!= null) {
804 events
= new XMLEvents ();
806 events
.CompareTo (doc
, parent
, oclass
.events
);
807 counters
.AddPartialToPartial (events
.Counters
);
810 if (methods
!= null || oclass
.methods
!= null) {
812 methods
= new XMLMethods ();
814 methods
.CompareTo (doc
, parent
, oclass
.methods
);
815 counters
.AddPartialToPartial (methods
.Counters
);
818 if (nested
!= null || oclass
.nested
!= null) {
819 XmlNode n
= doc
.CreateElement ("classes", null);
820 parent
.AppendChild (n
);
821 CompareTypes (n
, oclass
.nested
);
824 AddCountersAttributes (parent
);
827 void CompareTypes (XmlNode parent
, XMLClass
[] other
)
829 ArrayList newNodes
= new ArrayList ();
830 Hashtable oh
= CreateHash (other
);
832 int count
= (nested
== null) ? 0 : nested
.Length
;
833 for (int i
= 0; i
< count
; i
++) {
834 XMLClass xclass
= nested
[i
];
836 node
= document
.CreateElement ("nestedclass", null);
838 AddAttribute (node
, "name", xclass
.Name
);
839 AddAttribute (node
, "type", xclass
.Type
);
841 if (oh
.ContainsKey (xclass
.Name
)) {
842 int idx
= (int) oh
[xclass
.Name
];
843 xclass
.CompareTo (document
, node
, other
[idx
]);
845 counters
.AddPartialToPartial (xclass
.Counters
);
847 // TODO: Should I count here?
848 AddAttribute (node
, "presence", "missing");
850 counters
.MissingTotal
++;
855 count
= other
.Length
;
856 for (int i
= 0; i
< count
; i
++) {
857 XMLClass c
= other
[i
];
858 if (c
== null || c
.Name
.EndsWith ("TODOAttribute"))
861 node
= document
.CreateElement ("nestedclass", null);
863 AddAttribute (node
, "name", c
.Name
);
866 counters
.ExtraTotal
++;
870 XmlNode
[] nodes
= (XmlNode
[]) newNodes
.ToArray (typeof (XmlNode
));
871 Array
.Sort (nodes
, XmlNodeComparer
.Default
);
872 foreach (XmlNode nn
in nodes
)
873 parent
.AppendChild (nn
);
876 static Hashtable
CreateHash (XMLClass
[] other
)
878 Hashtable result
= new Hashtable ();
881 foreach (XMLClass c
in other
) {
882 result
[c
.Name
] = i
++;
898 class XMLParameter
: XMLData
908 public override void LoadData (XmlNode node
)
911 throw new ArgumentNullException ("node");
913 if (node
.Name
!= "parameter")
914 throw new ArgumentException ("Expecting <parameter>");
916 name
= node
.Attributes
["name"].Value
;
917 type
= node
.Attributes
["type"].Value
;
918 attrib
= node
.Attributes
["attrib"].Value
;
919 if (node
.Attributes
["direction"] != null)
920 direction
= node
.Attributes
["direction"].Value
;
921 if (node
.Attributes
["unsafe"] != null)
922 isUnsafe
= bool.Parse (node
.Attributes
["unsafe"].Value
);
923 if (node
.Attributes
["optional"] != null)
924 isOptional
= bool.Parse (node
.Attributes
["optional"].Value
);
925 if (node
.Attributes
["defaultValue"] != null)
926 defaultValue
= node
.Attributes
["defaultValue"].Value
;
929 public override void CompareTo (XmlDocument doc
, XmlNode parent
, object other
)
933 XMLParameter oparm
= (XMLParameter
) other
;
935 if (type
!= oparm
.type
)
936 AddWarning (parent
, "Parameter type is wrong: {0} != {1}", type
, oparm
.type
);
938 if (attrib
!= oparm
.attrib
)
939 AddWarning (parent
, "Parameter attributes wrong: {0} != {1}", attrib
, oparm
.attrib
);
941 if (direction
!= oparm
.direction
)
942 AddWarning (parent
, "Parameter direction wrong: {0} != {1}", direction
, oparm
.direction
);
944 if (isUnsafe
!= oparm
.isUnsafe
)
945 AddWarning (parent
, "Parameter unsafe wrong: {0} != {1}", isUnsafe
, oparm
.isUnsafe
);
947 if (isOptional
!= oparm
.isOptional
)
948 AddWarning (parent
, "Parameter optional wrong: {0} != {1}", isOptional
, oparm
.isOptional
);
950 if (defaultValue
!= oparm
.defaultValue
)
951 AddWarning (parent
, "Parameter default value wrong: {0} != {1}", defaultValue
, oparm
.defaultValue
);
959 class XMLAttributes
: XMLNameGroup
964 protected override bool CheckIfAdd (string value, XmlNode node
)
966 if (value.EndsWith ("TODOAttribute")) {
968 XmlAttribute att
= node
.Attributes
["comment"];
978 public override string GetNodeKey (string name
, XmlNode node
)
980 string target
= string.Empty
;
981 if (node
.Attributes
["target"] != null)
982 target
= node
.Attributes
["target"].Value
;
984 while (keys
.ContainsKey (name
)) {
985 name
= String
.Format ("{0} [{1}]:{1}", name
, target
, i
++);
991 public override string GroupName
{
992 get { return "attributes"; }
995 public override string Name
{
996 get { return "attribute"; }
1000 get { return isTodo; }
1003 public string Comment
{
1004 get { return comment; }
1008 class XMLInterfaces
: XMLNameGroup
1010 public override string GroupName
{
1011 get { return "interfaces"; }
1014 public override string Name
{
1015 get { return "interface"; }
1019 abstract class XMLMember
: XMLNameGroup
1021 Hashtable attributeMap
;
1022 Hashtable access
= new Hashtable ();
1024 protected override void LoadExtraData (string name
, XmlNode node
)
1026 XmlAttribute xatt
= node
.Attributes
["attrib"];
1028 access
[name
] = xatt
.Value
;
1030 XmlNode orig
= node
;
1032 node
= node
.FirstChild
;
1033 while (node
!= null) {
1034 if (node
!= null && node
.Name
== "attributes") {
1035 XMLAttributes a
= new XMLAttributes ();
1037 if (attributeMap
== null)
1038 attributeMap
= new Hashtable ();
1040 attributeMap
[name
] = a
;
1043 node
= node
.NextSibling
;
1046 base.LoadExtraData (name
, orig
);
1049 protected override void CompareToInner (string name
, XmlNode parent
, XMLNameGroup other
)
1051 base.CompareToInner (name
, parent
, other
);
1052 XMLMember mb
= other
as XMLMember
;
1053 XMLAttributes att
= null;
1054 XMLAttributes oatt
= null;
1055 if (attributeMap
!= null)
1056 att
= attributeMap
[name
] as XMLAttributes
;
1058 if (mb
!= null && mb
.attributeMap
!= null)
1059 oatt
= mb
.attributeMap
[name
] as XMLAttributes
;
1061 if (att
!= null || oatt
!= null) {
1063 att
= new XMLAttributes ();
1065 att
.CompareTo (document
, parent
, oatt
);
1066 counters
.AddPartialToPartial(att
.Counters
);
1067 if (oatt
!= null && oatt
.IsTodo
) {
1069 counters
.ErrorTotal
++;
1070 AddAttribute (parent
, "error", "todo");
1071 if (oatt
.Comment
!= null)
1072 AddAttribute (parent
, "comment", oatt
.Comment
);
1076 if (!CheckAttributes
)
1079 XMLMember member
= (XMLMember
) other
;
1080 string acc
= access
[name
] as string;
1085 if (member
.access
!= null)
1086 oacc
= member
.access
[name
] as string;
1088 string accName
= ConvertToString (Int32
.Parse (acc
));
1089 string oaccName
= "";
1091 oaccName
= ConvertToString (Int32
.Parse (oacc
));
1093 if (accName
!= oaccName
)
1094 AddWarning (parent
, "Incorrect attributes: '{0}' != '{1}'", accName
, oaccName
);
1097 protected virtual string ConvertToString (int att
)
1102 protected virtual bool CheckAttributes
{
1109 class XMLFields
: XMLMember
1111 Hashtable fieldTypes
;
1112 Hashtable fieldValues
;
1114 protected override void LoadExtraData (string name
, XmlNode node
)
1116 XmlAttribute xatt
= node
.Attributes
["fieldtype"];
1118 if (fieldTypes
== null)
1119 fieldTypes
= new Hashtable ();
1121 fieldTypes
[name
] = xatt
.Value
;
1124 xatt
= node
.Attributes
["value"];
1126 if (fieldValues
== null)
1127 fieldValues
= new Hashtable ();
1129 fieldValues
[name
] = xatt
.Value
;
1132 base.LoadExtraData (name
, node
);
1135 protected override void CompareToInner (string name
, XmlNode parent
, XMLNameGroup other
)
1137 base.CompareToInner (name
, parent
, other
);
1138 XMLFields fields
= (XMLFields
) other
;
1139 if (fieldTypes
!= null) {
1140 string ftype
= fieldTypes
[name
] as string;
1141 string oftype
= null;
1142 if (fields
.fieldTypes
!= null)
1143 oftype
= fields
.fieldTypes
[name
] as string;
1145 if (ftype
!= oftype
)
1146 AddWarning (parent
, "Field type is {0} and should be {1}", oftype
, ftype
);
1148 if (fieldValues
!= null) {
1149 string fvalue
= fieldValues
[name
] as string;
1150 string ofvalue
= null;
1151 if (fields
.fieldValues
!= null)
1152 ofvalue
= fields
.fieldValues
[name
] as string;
1154 if (fvalue
!= ofvalue
)
1155 AddWarning (parent
, "Field value is {0} and should be {1}", ofvalue
, fvalue
);
1159 protected override string ConvertToString (int att
)
1161 FieldAttributes fa
= (FieldAttributes
) att
;
1162 return fa
.ToString ();
1165 protected override bool CheckAttributes
{
1167 // FIXME: set this to true once bugs #60086 and
1173 public override string GroupName
{
1174 get { return "fields"; }
1177 public override string Name
{
1178 get { return "field"; }
1182 class XMLParameters
: XMLNameGroup
1184 public override void LoadData (XmlNode node
)
1187 throw new ArgumentNullException ("node");
1189 if (node
.Name
!= GroupName
)
1190 throw new FormatException (String
.Format ("Expecting <{0}>", GroupName
));
1192 keys
= new Hashtable ();
1193 foreach (XmlNode n
in node
.ChildNodes
) {
1194 string name
= n
.Attributes
["name"].Value
;
1195 string key
= GetNodeKey (name
, n
);
1196 XMLParameter parm
= new XMLParameter ();
1198 keys
.Add (key
, parm
);
1199 LoadExtraData (key
, n
);
1203 public override string GroupName
{
1205 return "parameters";
1209 public override string Name
{
1215 public override string GetNodeKey (string name
, XmlNode node
)
1217 return node
.Attributes
["position"].Value
;
1220 public override void CompareTo (XmlDocument doc
, XmlNode parent
, object other
)
1222 this.document
= doc
;
1224 group = doc
.CreateElement (GroupName
, null);
1226 Hashtable okeys
= null;
1227 if (other
!= null && ((XMLParameters
) other
).keys
!= null) {
1228 okeys
= ((XMLParameters
) other
).keys
;
1231 XmlNode node
= null;
1232 bool onull
= (okeys
== null);
1234 foreach (DictionaryEntry entry
in keys
) {
1235 node
= doc
.CreateElement (Name
, null);
1236 group.AppendChild (node
);
1237 string key
= (string) entry
.Key
;
1238 XMLParameter parm
= (XMLParameter
) entry
.Value
;
1239 AddAttribute (node
, "name", parm
.Name
);
1241 if (!onull
&& HasKey (key
, okeys
)) {
1242 parm
.CompareTo (document
, node
, okeys
[key
]);
1243 counters
.AddPartialToPartial (parm
.Counters
);
1247 AddAttribute (node
, "presence", "missing");
1253 if (!onull
&& okeys
.Count
!= 0) {
1254 foreach (XMLParameter
value in okeys
.Values
) {
1255 node
= doc
.CreateElement (Name
, null);
1256 AddAttribute (node
, "name", value.Name
);
1257 AddAttribute (node
, "presence", "extra");
1258 group.AppendChild (node
);
1263 if (group.HasChildNodes
)
1264 parent
.AppendChild (group);
1268 class XMLProperties
: XMLMember
1270 Hashtable nameToMethod
= new Hashtable ();
1272 protected override void CompareToInner (string name
, XmlNode parent
, XMLNameGroup other
)
1274 Counters copy
= counters
;
1275 counters
= new Counters();
1277 XMLProperties oprop
= other
as XMLProperties
;
1278 if (oprop
!= null) {
1279 XMLMethods m
= nameToMethod
[name
] as XMLMethods
;
1280 XMLMethods om
= oprop
.nameToMethod
[name
] as XMLMethods
;
1281 if (m
!= null || om
!= null) {
1283 m
= new XMLMethods ();
1285 m
.CompareTo(document
, parent
, om
);
1286 counters
.AddPartialToPartial(m
.Counters
);
1290 base.CompareToInner (name
, parent
, other
);
1291 AddCountersAttributes(parent
);
1293 copy
.AddPartialToPartial(counters
);
1297 protected override void LoadExtraData (string name
, XmlNode node
)
1299 XmlNode orig
= node
;
1300 node
= node
.FirstChild
;
1301 while (node
!= null) {
1302 if (node
!= null && node
.Name
== "methods") {
1303 XMLMethods m
= new XMLMethods ();
1304 XmlNode parent
= node
.ParentNode
;
1305 string key
= GetNodeKey (name
, parent
);
1307 nameToMethod
[key
] = m
;
1310 node
= node
.NextSibling
;
1313 base.LoadExtraData (name
, orig
);
1316 public override string GetNodeKey (string name
, XmlNode node
)
1318 XmlAttributeCollection atts
= node
.Attributes
;
1319 return String
.Format ("{0}:{1}:{2}", atts
["name"].Value
,
1320 atts
["ptype"].Value
,
1321 atts
["params"].Value
);
1324 public override string GroupName
{
1325 get { return "properties"; }
1328 public override string Name
{
1329 get { return "property"; }
1333 class XMLEvents
: XMLMember
1335 Hashtable eventTypes
;
1337 protected override void LoadExtraData (string name
, XmlNode node
)
1339 XmlAttribute xatt
= node
.Attributes
["eventtype"];
1341 if (eventTypes
== null)
1342 eventTypes
= new Hashtable ();
1344 eventTypes
[name
] = xatt
.Value
;
1347 base.LoadExtraData (name
, node
);
1350 protected override void CompareToInner (string name
, XmlNode parent
, XMLNameGroup other
)
1352 Counters copy
= counters
;
1353 counters
= new Counters ();
1356 base.CompareToInner (name
, parent
, other
);
1357 AddCountersAttributes (parent
);
1358 if (eventTypes
== null)
1361 XMLEvents evt
= (XMLEvents
) other
;
1362 string etype
= eventTypes
[name
] as string;
1363 string oetype
= null;
1364 if (evt
.eventTypes
!= null)
1365 oetype
= evt
.eventTypes
[name
] as string;
1367 if (etype
!= oetype
)
1368 AddWarning (parent
, "Event type is {0} and should be {1}", oetype
, etype
);
1370 AddCountersAttributes (parent
);
1371 copy
.AddPartialToPartial (counters
);
1376 protected override string ConvertToString (int att
)
1378 EventAttributes ea
= (EventAttributes
) att
;
1379 return ea
.ToString ();
1382 public override string GroupName
{
1383 get { return "events"; }
1386 public override string Name
{
1387 get { return "event"; }
1391 class XMLMethods
: XMLMember
1393 Hashtable returnTypes
;
1394 Hashtable parameters
;
1396 protected override void LoadExtraData (string name
, XmlNode node
)
1398 XmlAttribute xatt
= node
.Attributes
["returntype"];
1400 if (returnTypes
== null)
1401 returnTypes
= new Hashtable ();
1403 returnTypes
[name
] = xatt
.Value
;
1406 XmlNode parametersNode
= node
.SelectSingleNode ("parameters");
1407 if (parametersNode
!= null) {
1408 if (parameters
== null)
1409 parameters
= new Hashtable ();
1411 XMLParameters parms
= new XMLParameters ();
1412 parms
.LoadData (parametersNode
);
1414 parameters
[name
] = parms
;
1417 base.LoadExtraData (name
, node
);
1420 protected override void CompareToInner (string name
, XmlNode parent
, XMLNameGroup other
)
1422 // create backup of actual counters
1423 Counters copy
= counters
;
1424 // initialize counters for current method
1425 counters
= new Counters();
1428 base.CompareToInner(name
, parent
, other
);
1429 XMLMethods methods
= (XMLMethods
) other
;
1430 if (returnTypes
!= null) {
1431 string rtype
= returnTypes
[name
] as string;
1432 string ortype
= null;
1433 if (methods
.returnTypes
!= null)
1434 ortype
= methods
.returnTypes
[name
] as string;
1436 if (rtype
!= ortype
)
1437 AddWarning (parent
, "Return type is {0} and should be {1}", ortype
, rtype
);
1440 if (parameters
!= null) {
1441 XMLParameters parms
= parameters
[name
] as XMLParameters
;
1442 parms
.CompareTo (document
, parent
, methods
.parameters
[name
]);
1443 counters
.AddPartialToPartial (parms
.Counters
);
1446 // output counter attributes in result document
1447 AddCountersAttributes(parent
);
1449 // add temporary counters to actual counters
1450 copy
.AddPartialToPartial(counters
);
1451 // restore backup of actual counters
1456 protected override string ConvertToString (int att
)
1458 MethodAttributes ma
= (MethodAttributes
) att
;
1459 // ignore the HasSecurity attribute for now
1460 if ((ma
& MethodAttributes
.HasSecurity
) != 0)
1461 ma
= (MethodAttributes
) (att
- (int) MethodAttributes
.HasSecurity
);
1463 // ignore the RequireSecObject attribute for now
1464 if ((ma
& MethodAttributes
.RequireSecObject
) != 0)
1465 ma
= (MethodAttributes
) (att
- (int) MethodAttributes
.RequireSecObject
);
1467 // we don't care if the implementation is forwarded through PInvoke
1468 if ((ma
& MethodAttributes
.PinvokeImpl
) != 0)
1469 ma
= (MethodAttributes
) (att
- (int) MethodAttributes
.PinvokeImpl
);
1471 return ma
.ToString ();
1474 protected override bool CheckAttributes
{
1476 // FIXME: set this to true once bugs #60086 and
1482 public override string GroupName
{
1483 get { return "methods"; }
1486 public override string Name
{
1487 get { return "method"; }
1491 class XMLConstructors
: XMLMethods
1493 public override string GroupName
{
1494 get { return "constructors"; }
1497 public override string Name
{
1498 get { return "constructor"; }
1502 class XmlNodeComparer
: IComparer
1504 public static XmlNodeComparer Default
= new XmlNodeComparer ();
1506 public int Compare (object a
, object b
)
1508 XmlNode na
= (XmlNode
) a
;
1509 XmlNode nb
= (XmlNode
) b
;
1510 return String
.Compare (na
.Attributes
["name"].Value
, nb
.Attributes
["name"].Value
);