Merge pull request #1024 from ludovic-henry/pr10-proflog-counters
[mono.git] / mcs / tools / corcompare / mono-api-html / MemberComparer.cs
1 // 
2 // Authors
3 //    Sebastien Pouliot  <sebastien@xamarin.com>
4 //
5 // Copyright 2013-2014 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                                 Add (t.Elements (ElementName));
49                         } else if (t == null) {
50                                 Remove (s.Elements (ElementName));
51                         } else {
52                                 Compare (s.Elements (ElementName), t.Elements (ElementName));
53                         }
54                 }
55
56                 public override void SetContext (XElement current)
57                 {
58                 }
59
60                 public XElement Source { get; set; }
61
62                 public virtual bool Find (XElement e)
63                 {
64                         return e.GetAttribute ("name") == Source.GetAttribute ("name");
65                 }
66
67                 XElement Find (IEnumerable<XElement> target)
68                 {
69                         return State.Lax ? target.FirstOrDefault (Find) : target.SingleOrDefault (Find);
70                 }
71
72                 public override void Compare (IEnumerable<XElement> source, IEnumerable<XElement> target)
73                 {
74                         removed.Clear ();
75                         obsoleted.Clear ();
76
77                         foreach (var s in source) {
78                                 SetContext (s);
79                                 Source = s;
80                                 var t = Find (target);
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                                                 if (IsNowObsoleted (s, t)) {
88                                                         obsoleted.Add (t);
89                                                 }
90                                                 t.Remove ();
91                                                 continue;
92                                         }
93
94                                         // still in target so will be part of Added
95                                         removed.Add (s);
96                                         Modified (s, t);
97                                 }
98                         }
99                         // delayed, that way we show "Modified", "Added" and then "Removed"
100                         Remove (removed);
101
102                         // remaining == newly added in target
103                         Add (target);
104
105                         // obsolete (considering as added, they were not obsolete before, wrt regex)
106                         bool o = false;
107                         foreach (var item in obsoleted) {
108                                 SetContext (item);
109                                 if (State.IgnoreAdded.Any (re => re.IsMatch (GetDescription (item))))
110                                         continue;
111                                 if (!o) {
112                                         BeforeObsoleting (obsoleted);
113                                         o = true;
114                                 }
115                                 Obsoleted (item);
116                         }
117                         if (o)
118                                 AfterObsoleting ();
119                 }
120
121                 void Add (IEnumerable<XElement> elements)
122                 {
123                         bool a = false;
124                         foreach (var item in elements) {
125                                 SetContext (item);
126                                 if (State.IgnoreAdded.Any (re => re.IsMatch (GetDescription (item))))
127                                         continue;
128                                 if (!a) {
129                                         BeforeAdding (elements);
130                                         a = true;
131                                 }
132                                 Added (item);
133                         }
134                         if (a)
135                                 AfterAdding ();
136                 }
137
138                 void Remove (IEnumerable<XElement> elements)
139                 {
140                         bool r = false;
141                         foreach (var item in elements) {
142                                 if (State.IgnoreRemoved.Any (re => re.IsMatch (GetDescription (item))))
143                                         continue;
144                                 SetContext (item);
145                                 if (!r) {
146                                         BeforeRemoving (elements);
147                                         r = true;
148                                 }
149                                 Removed (item);
150                         }
151                         if (r)
152                                 AfterRemoving ();
153                 }
154
155                 public abstract string GetDescription (XElement e);
156
157                 protected StringBuilder GetObsoleteMessage (XElement e)
158                 {
159                         var sb = new StringBuilder ();
160                         string o = e.GetObsoleteMessage ();
161                         if (o != null) {
162                                 sb.Append ("[Obsolete");
163                                 if (o.Length > 0)
164                                         sb.Append (" (\"").Append (o).Append ("\")");
165                                 sb.AppendLine ("]");
166                                 for (int i = 0; i < State.Indent + 1; i++)
167                                         sb.Append ('\t');
168                         }
169                         return sb;
170                 }
171
172                 public override bool Equals (XElement source, XElement target)
173                 {
174                         if (base.Equals (source, target))
175                                 return true;
176
177                         return GetDescription (source) == GetDescription (target);
178                 }
179
180                 bool IsNowObsoleted (XElement source, XElement target)
181                 {
182                         var s = GetObsoleteMessage (source).ToString ();
183                         var t = GetObsoleteMessage (target).ToString ();
184                         // true if it was no [Obsolete] in the source but now is [Obsolete] in the target
185                         return (s.Length == 0 && t.Length > 0);
186                 }
187
188                 public virtual void BeforeAdding (IEnumerable<XElement> list)
189                 {
190                         Output.WriteLine ("<p>Added {0}:</p><pre>", list.Count () > 1 ? GroupName : ElementName);
191                 }
192
193                 public override void Added (XElement target)
194                 {
195                         Indent ().WriteLine ("\t{0}", GetDescription (target));
196                 }
197
198                 public virtual void AfterAdding ()
199                 {
200                         Output.WriteLine ("</pre>");
201                 }
202
203                 public virtual void BeforeObsoleting (IEnumerable<XElement> list)
204                 {
205                         Output.WriteLine ("<p>Obsoleted {0}:</p><pre>", list.Count () > 1 ? GroupName : ElementName);
206                 }
207
208                 public void Obsoleted (XElement target)
209                 {
210                         Indent ().WriteLine ("\t{0}{1}{2}", GetObsoleteMessage (target), GetDescription (target), Environment.NewLine);
211                 }
212
213                 public virtual void AfterObsoleting ()
214                 {
215                         Output.WriteLine ("</pre>");
216                 }
217
218                 public override void Modified (XElement source, XElement target)
219                 {
220                 }
221
222                 public virtual void BeforeRemoving (IEnumerable<XElement> list)
223                 {
224                         Output.WriteLine ("<p>Removed {0}:</p><pre>", list.Count () > 1 ? GroupName : ElementName);
225                 }
226
227                 public override void Removed (XElement source)
228                 {
229                         Indent ().WriteLine ("\t{0}", GetDescription (source));
230                 }
231
232                 public virtual void AfterRemoving ()
233                 {
234                         Output.WriteLine ("</pre>");
235                 }
236         }
237 }