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