Merge pull request #823 from DavidKarlas/master
[mono.git] / mcs / tools / corcompare / mono-api-html / MemberComparer.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.Linq;
30 using System.Text;
31 using System.Xml.Linq;
32
33 namespace Xamarin.ApiDiff {
34
35         public abstract class MemberComparer : Comparer {
36
37                 public abstract string GroupName { get; }
38                 public abstract string ElementName { get; }
39
40                 public void Compare (XElement source, XElement target)
41                 {
42                         var s = source.Element (GroupName);
43                         var t = target.Element (GroupName);
44                         if (XNode.DeepEquals (s, t))
45                                 return;
46
47                         if (s == null) {
48                                 BeforeAdding ();
49                                 foreach (var item in t.Elements (ElementName))
50                                         Added (item);
51                                 AfterAdding ();
52                         } else if (t == null) {
53                                 BeforeRemoving ();
54                                 foreach (var item in s.Elements (ElementName))
55                                         Removed (item);
56                                 AfterRemoving ();
57                         } else {
58                                 Compare (s.Elements (ElementName), t.Elements (ElementName));
59                         }
60                 }
61
62                 public override void SetContext (XElement current)
63                 {
64                 }
65
66                 public XElement Source { get; set; }
67
68                 public virtual bool Find (XElement e)
69                 {
70                         return e.GetAttribute ("name") == Source.GetAttribute ("name");
71                 }
72
73                 public override void Compare (IEnumerable<XElement> source, IEnumerable<XElement> target)
74                 {
75                         removed.Clear ();
76
77                         foreach (var s in source) {
78                                 SetContext (s);
79                                 Source = s;
80                                 var t = target.SingleOrDefault (Find);
81                                 if (t == null) {
82                                         // not in target, it was removed
83                                         removed.Add (s);
84                                 } else {
85                                         // possibly modified
86                                         if (Equals (s, t)) {
87                                                 t.Remove ();
88                                                 continue;
89                                         }
90
91                                         // still in target so will be part of Added
92                                         removed.Add (s);
93                                         Modified (s, t);
94                                 }
95                         }
96                         // delayed, that way we show "Modified", "Added" and then "Removed"
97                         bool r = false;
98                         foreach (var item in removed) {
99                                 SetContext (item);
100                                 if (!r) {
101                                         BeforeRemoving ();
102                                         r = true;
103                                 }
104                                 Removed (item);
105                         }
106                         if (r)
107                                 AfterRemoving ();
108                         // remaining == newly added in target
109                         bool a = false;
110                         foreach (var item in target) {
111                                 SetContext (item);
112                                 if (!a) {
113                                         BeforeAdding ();
114                                         a = true;
115                                 }
116                                 Added (item);
117                         }
118                         if (a)
119                                 AfterAdding ();
120                 }
121
122                 public abstract string GetDescription (XElement e);
123
124                 protected StringBuilder GetObsoleteMessage (XElement e)
125                 {
126                         var sb = new StringBuilder ();
127                         string o = e.GetObsoleteMessage ();
128                         if (o != null) {
129                                 sb.Append ("[Obsolete (\"").Append (o).AppendLine ("\")]");
130                                 for (int i = 0; i < State.Indent + 1; i++)
131                                         sb.Append ('\t');
132                         }
133                         return sb;
134                 }
135
136                 public override bool Equals (XElement source, XElement target)
137                 {
138                         if (base.Equals (source, target))
139                                 return true;
140
141                         return GetDescription (source) == GetDescription (target);
142                 }
143
144                 public virtual void BeforeAdding ()
145                 {
146                         Output.WriteLine ("<p>Added {0}:</p><pre>", GroupName);
147                 }
148
149                 public override void Added (XElement target)
150                 {
151                         Indent ().WriteLine ("\t{0}", GetDescription (target));
152                 }
153
154                 public virtual void AfterAdding ()
155                 {
156                         Output.WriteLine ("</pre>");
157                 }
158
159                 public override void Modified (XElement source, XElement target)
160                 {
161                 }
162
163                 public virtual void BeforeRemoving ()
164                 {
165                         Output.WriteLine ("<p>Removed {0}:</p><pre>", GroupName);
166                 }
167
168                 public override void Removed (XElement source)
169                 {
170                         Indent ().WriteLine ("\t{0}", GetDescription (source));
171                 }
172
173                 public virtual void AfterRemoving ()
174                 {
175                         Output.WriteLine ("</pre>");
176                 }
177         }
178 }