Merge pull request #463 from strawd/concurrent-requests
[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.Linq;
31 using System.Xml.Linq;
32
33 namespace Xamarin.ApiDiff {
34
35         public class ClassComparer : Comparer {
36
37                 InterfaceComparer icomparer;
38                 ConstructorComparer ccomparer;
39                 FieldComparer fcomparer;
40                 PropertyComparer pcomparer;
41                 EventComparer ecomparer;
42                 MethodComparer mcomparer;
43                 ClassComparer kcomparer;
44
45                 public ClassComparer ()
46                 {
47                         icomparer = new InterfaceComparer ();
48                         ccomparer = new ConstructorComparer ();
49                         fcomparer = new FieldComparer ();
50                         pcomparer = new PropertyComparer ();
51                         ecomparer = new EventComparer ();
52                         mcomparer = new MethodComparer ();
53                 }
54
55                 public override void SetContext (XElement current)
56                 {
57                         State.Type = current.GetAttribute ("name");
58                         State.BaseType = current.GetAttribute ("base");
59                 }
60
61                 public void Compare (XElement source, XElement target)
62                 {
63                         var s = source.Element ("classes");
64                         var t = target.Element ("classes");
65                         if (XNode.DeepEquals (s, t))
66                                 return;
67                         Compare (s.Elements ("class"), t.Elements ("class"));
68                 }
69
70                 public override void Added (XElement target)
71                 {
72                         string name = target.Attribute ("name").Value;
73                         if (State.IgnoreNew.Any (re => re.IsMatch (name)))
74                                 return;
75                         Output.WriteLine ("<h3>New Type {0}.{1}</h3>", State.Namespace, name);
76                         Output.WriteLine (State.Colorize ? "<pre style='color: green'>" : "<pre>");
77                         State.Indent = 0;
78                         AddedInner (target);
79                         Output.WriteLine ("</pre>");
80                 }
81
82                 public void AddedInner (XElement target)
83                 {
84                         SetContext (target);
85                         if (target.IsTrue ("serializable"))
86                                 Indent ().WriteLine ("[Serializable]");
87
88                         var type = target.Attribute ("type").Value;
89
90                         if (type == "enum") {
91                                 // check if [Flags] is present
92                                 var cattrs = target.Element ("attributes");
93                                 if (cattrs != null) {
94                                         foreach (var ca in cattrs.Elements ("attribute")) {
95                                                 if (ca.GetAttribute ("name") == "System.FlagsAttribute") {
96                                                         Indent ().WriteLine ("[Flags]");
97                                                         break;
98                                                 }
99                                         }
100                                 }
101                         }
102
103                         Indent ().Write ("public");
104
105                         if (type != "enum") {
106                                 bool seal = target.IsTrue ("sealed");
107                                 bool abst = target.IsTrue ("abstract");
108                                 if (seal && abst)
109                                         Output.Write (" static");
110                                 else if (seal && type != "struct")
111                                         Output.Write (" sealed");
112                                 else if (abst && type != "interface")
113                                         Output.Write (" abstract");
114                         }
115
116                         Output.Write (' ');
117                         Output.Write (type);
118                         Output.Write (' ');
119                         Output.Write (target.GetAttribute ("name"));
120
121                         var baseclass = target.GetAttribute ("base");
122                         if ((type != "enum") && (type != "struct")) {
123                                 if (baseclass != null) {
124                                         if (baseclass == "System.Object") {
125                                                 // while true we do not need to be reminded every time...
126                                                 baseclass = null;
127                                         } else {
128                                                 Output.Write (" : ");
129                                                 Output.Write (baseclass);
130                                         }
131                                 }
132                         }
133
134                         // interfaces on enums are "standard" not user provided - so we do not want to show them
135                         if (type != "enum") {
136                                 var i = target.Element ("interfaces");
137                                 if (i != null) {
138                                         var interfaces = new List<string> ();
139                                         foreach (var iface in i.Elements ("interface"))
140                                                 interfaces.Add (icomparer.GetDescription (iface));
141                                         Output.Write ((baseclass == null) ? " : " : ", ");
142                                         Output.Write (String.Join (", ", interfaces));
143                                 }
144                         }
145
146                         Output.WriteLine (" {");
147
148                         var t = target.Element ("constructors");
149                         if (t != null) {
150                                 Indent ().WriteLine ("\t// constructors");
151                                 foreach (var ctor in t.Elements ("constructor"))
152                                         ccomparer.Added (ctor);
153                         }
154
155                         t = target.Element ("fields");
156                         if (t != null) {
157                                 if (type != "enum")
158                                         Indent ().WriteLine ("\t// fields");
159                                 else
160                                         SetContext (target);
161                                 foreach (var field in t.Elements ("field"))
162                                         fcomparer.Added (field);
163                         }
164
165                         t = target.Element ("properties");
166                         if (t != null) {
167                                 Indent ().WriteLine ("\t// properties");
168                                 foreach (var property in t.Elements ("property"))
169                                         pcomparer.Added (property);
170                         }
171
172                         t = target.Element ("events");
173                         if (t != null) {
174                                 Indent ().WriteLine ("\t// events");
175                                 foreach (var evnt in t.Elements ("event"))
176                                         ecomparer.Added (evnt);
177                         }
178
179                         t = target.Element ("methods");
180                         if (t != null) {
181                                 Indent ().WriteLine ("\t// methods");
182                                 foreach (var method in t.Elements ("method"))
183                                         mcomparer.Added (method);
184                         }
185
186                         t = target.Element ("classes");
187                         if (t != null) {
188                                 Output.WriteLine ();
189                                 Indent ().WriteLine ("\t// inner types");
190                                 kcomparer = new NestedClassComparer ();
191                                 State.Indent++;
192                                 foreach (var inner in t.Elements ("class"))
193                                         kcomparer.AddedInner (inner);
194                                 State.Indent--;
195                         }
196                         Indent ().WriteLine ("}");
197                 }
198
199                 public override void Modified (XElement source, XElement target, ApiChanges diff)
200                 {
201                         // hack - there could be changes that we're not monitoring (e.g. attributes properties)
202                         var output = Output;
203                         State.Output = new StringWriter ();
204
205                         var sb = source.GetAttribute ("base");
206                         var tb = target.GetAttribute ("base");
207                         if (sb != tb) {
208                                 Output.Write ("Modified base type: ");
209                                 Output.WriteLine (new ApiChange ().AppendModified (sb, tb, true).Member.ToString ());
210                         }
211
212                         ccomparer.Compare (source, target);
213                         icomparer.Compare (source, target);
214                         fcomparer.Compare (source, target);
215                         pcomparer.Compare (source, target);
216                         ecomparer.Compare (source, target);
217                         mcomparer.Compare (source, target);
218
219                         var si = source.Element ("classes");
220                         if (si != null) {
221                                 var ti = target.Element ("classes");
222                                 kcomparer = new NestedClassComparer ();
223                                 kcomparer.Compare (si.Elements ("class"), ti == null ? null : ti.Elements ("class"));
224                         }
225
226                         var s = (Output as StringWriter).ToString ();
227                         State.Output = output;
228                         if (s.Length > 0) {
229                                 Output.WriteLine ("<h3>Type Changed: {0}.{1}</h3>", State.Namespace, GetTypeName (target));
230                                 Output.WriteLine (s);
231                         }
232                 }
233
234                 public override void Removed (XElement source)
235                 {
236                         var style = string.Empty;
237                         if (State.Colorize)
238                                 style = "style='color: red'";
239                         Output.Write ("<h3>Removed Type <span {0}>{1}.{2}</span></h3>", style, State.Namespace, GetTypeName (source));
240                 }
241
242                 public virtual string GetTypeName (XElement type)
243                 {
244                         return type.GetAttribute ("name");
245                 }
246         }
247
248         public class NestedClassComparer : ClassComparer {
249
250                 public override void SetContext (XElement current)
251                 {
252                 }
253
254                 public override string GetTypeName (XElement type)
255                 {
256                         return State.Type + "." + base.GetTypeName (type);
257                 }
258         }
259 }