Merge pull request #823 from DavidKarlas/master
[mono.git] / mcs / tools / corcompare / mono-api-html / ClassComparer.cs
1 // 
2 // Authors
3 //    Sebastien Pouliot  <sebastien@xamarin.com>
4 //
5 // Copyright 2013 Xamarin Inc. http://www.xamarin.com
6 // 
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 //
26
27 using System;
28 using System.Collections.Generic;
29 using System.IO;
30 using System.Xml.Linq;
31
32 namespace Xamarin.ApiDiff {
33
34         public class ClassComparer : Comparer {
35
36                 InterfaceComparer icomparer;
37                 ConstructorComparer ccomparer;
38                 FieldComparer fcomparer;
39                 PropertyComparer pcomparer;
40                 EventComparer ecomparer;
41                 MethodComparer mcomparer;
42                 ClassComparer kcomparer;
43
44                 public ClassComparer ()
45                 {
46                         icomparer = new InterfaceComparer ();
47                         ccomparer = new ConstructorComparer ();
48                         fcomparer = new FieldComparer ();
49                         pcomparer = new PropertyComparer ();
50                         ecomparer = new EventComparer ();
51                         mcomparer = new MethodComparer ();
52                 }
53
54                 public override void SetContext (XElement current)
55                 {
56                         State.Type = current.GetAttribute ("name");
57                         State.BaseType = current.GetAttribute ("base");
58                 }
59
60                 public void Compare (XElement source, XElement target)
61                 {
62                         var s = source.Element ("classes");
63                         var t = target.Element ("classes");
64                         if (XNode.DeepEquals (s, t))
65                                 return;
66                         Compare (s.Elements ("class"), t.Elements ("class"));
67                 }
68
69                 public override void Added (XElement target)
70                 {
71                         Output.WriteLine ("<h3>New Type {0}.{1}</h3>", State.Namespace, target.Attribute ("name").Value);
72                         Output.WriteLine ("<pre>");
73                         State.Indent = 0;
74                         AddedInner (target);
75                         Output.WriteLine ("</pre>");
76                 }
77
78                 public void AddedInner (XElement target)
79                 {
80                         SetContext (target);
81                         if (target.IsTrue ("serializable"))
82                                 Indent ().WriteLine ("[Serializable]");
83
84                         var type = target.Attribute ("type").Value;
85
86                         if (type == "enum") {
87                                 // check if [Flags] is present
88                                 var cattrs = target.Element ("attributes");
89                                 if (cattrs != null) {
90                                         foreach (var ca in cattrs.Elements ("attribute")) {
91                                                 if (ca.GetAttribute ("name") == "System.FlagsAttribute") {
92                                                         Indent ().WriteLine ("[Flags]");
93                                                         break;
94                                                 }
95                                         }
96                                 }
97                         }
98
99                         Indent ().Write ("public");
100
101                         if (type != "enum") {
102                                 bool seal = target.IsTrue ("sealed");
103                                 bool abst = target.IsTrue ("abstract");
104                                 if (seal && abst)
105                                         Output.Write (" static");
106                                 else if (seal && type != "struct")
107                                         Output.Write (" sealed");
108                                 else if (abst && type != "interface")
109                                         Output.Write (" abstract");
110                         }
111
112                         Output.Write (' ');
113                         Output.Write (type);
114                         Output.Write (' ');
115                         Output.Write (target.GetAttribute ("name"));
116
117                         var baseclass = target.GetAttribute ("base");
118                         if ((type != "enum") && (type != "struct")) {
119                                 if (baseclass != null) {
120                                         if (baseclass == "System.Object") {
121                                                 // while true we do not need to be reminded every time...
122                                                 baseclass = null;
123                                         } else {
124                                                 Output.Write (" : ");
125                                                 Output.Write (baseclass);
126                                         }
127                                 }
128                         }
129
130                         // interfaces on enums are "standard" not user provided - so we do not want to show them
131                         if (type != "enum") {
132                                 var i = target.Element ("interfaces");
133                                 if (i != null) {
134                                         var interfaces = new List<string> ();
135                                         foreach (var iface in i.Elements ("interface"))
136                                                 interfaces.Add (icomparer.GetDescription (iface));
137                                         Output.Write ((baseclass == null) ? " : " : ", ");
138                                         Output.Write (String.Join (", ", interfaces));
139                                 }
140                         }
141
142                         Output.WriteLine (" {");
143
144                         var t = target.Element ("constructors");
145                         if (t != null) {
146                                 Indent ().WriteLine ("\t// constructors");
147                                 foreach (var ctor in t.Elements ("constructor"))
148                                         ccomparer.Added (ctor);
149                         }
150
151                         t = target.Element ("fields");
152                         if (t != null) {
153                                 if (type != "enum")
154                                         Indent ().WriteLine ("\t// fields");
155                                 else
156                                         SetContext (target);
157                                 foreach (var field in t.Elements ("field"))
158                                         fcomparer.Added (field);
159                         }
160
161                         t = target.Element ("properties");
162                         if (t != null) {
163                                 Indent ().WriteLine ("\t// properties");
164                                 foreach (var property in t.Elements ("property"))
165                                         pcomparer.Added (property);
166                         }
167
168                         t = target.Element ("events");
169                         if (t != null) {
170                                 Indent ().WriteLine ("\t// events");
171                                 foreach (var evnt in t.Elements ("event"))
172                                         ecomparer.Added (evnt);
173                         }
174
175                         t = target.Element ("methods");
176                         if (t != null) {
177                                 Indent ().WriteLine ("\t// methods");
178                                 foreach (var method in t.Elements ("method"))
179                                         mcomparer.Added (method);
180                         }
181
182                         t = target.Element ("classes");
183                         if (t != null) {
184                                 Output.WriteLine ();
185                                 Indent ().WriteLine ("\t// inner types");
186                                 kcomparer = new NestedClassComparer ();
187                                 State.Indent++;
188                                 foreach (var inner in t.Elements ("class"))
189                                         kcomparer.AddedInner (inner);
190                                 State.Indent--;
191                         }
192                         Indent ().WriteLine ("}");
193                 }
194
195                 public override void Modified (XElement source, XElement target)
196                 {
197                         // hack - there could be changes that we're not monitoring (e.g. attributes properties)
198                         var output = Output;
199                         State.Output = new StringWriter ();
200
201                         ccomparer.Compare (source, target);
202                         icomparer.Compare (source, target);
203                         fcomparer.Compare (source, target);
204                         pcomparer.Compare (source, target);
205                         ecomparer.Compare (source, target);
206                         mcomparer.Compare (source, target);
207
208                         var si = source.Element ("classes");
209                         if (si != null) {
210                                 var ti = target.Element ("classes");
211                                 kcomparer = new NestedClassComparer ();
212                                 kcomparer.Compare (si.Elements ("class"), ti == null ? null : ti.Elements ("class"));
213                         }
214
215                         var s = (Output as StringWriter).ToString ();
216                         State.Output = output;
217                         if (s.Length > 0) {
218                                 Output.WriteLine ("<h3>Type Changed: {0}.{1}</h3>", State.Namespace, GetTypeName (target));
219                                 Output.WriteLine (s);
220                         }
221                 }
222
223                 public override void Removed (XElement source)
224                 {
225                         Output.WriteLine ("<h3>Removed Type {0}.{1}", State.Namespace, GetTypeName (source));
226                 }
227
228                 public virtual string GetTypeName (XElement type)
229                 {
230                         return type.GetAttribute ("name");
231                 }
232         }
233
234         public class NestedClassComparer : ClassComparer {
235
236                 public override void SetContext (XElement current)
237                 {
238                 }
239
240                 public override string GetTypeName (XElement type)
241                 {
242                         return State.Type + "." + base.GetTypeName (type);
243                 }
244         }
245 }