Merge pull request #1349 from martinjt/MachineKeyProtect
[mono.git] / mcs / tools / corcompare / mono-api-html / PropertyComparer.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.Reflection;
30 using System.Text;
31 using System.Xml.Linq;
32
33 namespace Xamarin.ApiDiff {
34
35         public class PropertyComparer : MemberComparer {
36
37                 public override string GroupName {
38                         get { return "properties"; }
39                 }
40
41                 public override string ElementName {
42                         get { return "property"; }
43                 }
44
45                 public override bool Find (XElement e)
46                 {
47                         if (!base.Find (e))
48                                 return false;
49                         // the same Item (indexer) property can have different parameters
50                         return e.GetAttribute ("params") == Source.GetAttribute ("params");
51                 }
52
53                 void GetAccessors (XElement element, out XElement getter, out XElement setter)
54                 {
55                         var methods = element.Element ("methods");
56
57                         getter = null;
58                         setter = null;
59
60                         if (methods == null)
61                                 return;
62                                 
63                         foreach (var m in methods.Elements ("method")) {
64                                 var n = m.GetAttribute ("name");
65                                 if (n.StartsWith ("get_", StringComparison.Ordinal)) {
66                                         getter = m;
67                                 } else if (n.StartsWith ("set_", StringComparison.Ordinal)) {
68                                         setter = m;
69                                 }
70                         }
71                 }
72
73                 MethodAttributes GetMethodAttributes (XElement getter, XElement setter)
74                 {
75                         if (getter == null)
76                                 return setter.GetMethodAttributes ();
77                         else if (setter == null)
78                                 return getter.GetMethodAttributes ();
79
80                         var gAttr = getter.GetMethodAttributes ();
81                         var sAttr = setter.GetMethodAttributes ();
82                         var g = gAttr & MethodAttributes.MemberAccessMask;
83                         var s = sAttr & MethodAttributes.MemberAccessMask;
84                         // Visibility is ordered numerically (higher value = more visible).
85                         // We want the most visible.
86                         var visibility = (MethodAttributes) Math.Max ((int) g, (int) s);
87                         // Do a bitwise or with the rest of the flags
88                         var g_no_visibility = gAttr & ~MethodAttributes.MemberAccessMask;
89                         var s_no_visibility = sAttr & ~MethodAttributes.MemberAccessMask;
90                         return g_no_visibility | s_no_visibility | visibility;
91                 }
92
93                 void RenderPropertyType (XElement source, XElement target, ApiChange change)
94                 {
95                         var srcType = source.GetTypeName ("ptype");
96                         var tgtType = target.GetTypeName ("ptype");
97
98                         if (srcType == tgtType) {
99                                 change.Append (tgtType);
100                         } else {
101                                 change.AppendModified (srcType, tgtType, true);
102                         }
103                         change.Append (" ");
104                 }
105
106                 void RenderAccessors (XElement srcGetter, XElement tgtGetter, XElement srcSetter, XElement tgtSetter, ApiChange change)
107                 {
108                         // FIXME: this doesn't render changes in the accessor visibility (a protected setter can become public for instance).
109                         change.Append (" {");
110                         if (tgtGetter != null) {
111                                 if (srcGetter != null) {
112                                         change.Append (" ").Append ("get;");
113                                 } else {
114                                         change.Append (" ").AppendAdded ("get;");
115                                 }
116                         } else if (srcGetter != null) {
117                                 change.Append (" ").AppendRemoved ("get;");
118                         }
119
120                         if (tgtSetter != null) {
121                                 if (srcSetter != null) {
122                                         change.Append (" ").Append ("set;");
123                                 } else {
124                                         change.Append (" ").AppendAdded ("set;");
125                                 }
126                         } else if (srcSetter != null) {
127                                 change.Append (" ").AppendRemoved ("set;");
128                         }
129
130                         change.Append (" }");
131
132                         // Ignore added property setters if asked to
133                         if (srcSetter == null && tgtSetter != null && State.IgnoreAddedPropertySetters && !change.Breaking) {
134                                 change.AnyChange = false;
135                                 change.HasIgnoredChanges = true;
136                         }
137                 }
138
139                 public override bool Equals (XElement source, XElement target, ApiChanges changes)
140                 {
141                         if (base.Equals (source, target, changes))
142                                 return true;
143
144                         XElement srcGetter, srcSetter;
145                         XElement tgtGetter, tgtSetter;
146                         GetAccessors (source, out srcGetter, out srcSetter);
147                         GetAccessors (target, out tgtGetter, out tgtSetter);
148
149                         var change = new ApiChange ();
150                         change.Header = "Modified " + GroupName;
151                         RenderMethodAttributes (GetMethodAttributes (srcGetter, srcSetter), GetMethodAttributes (tgtGetter, tgtSetter), change);
152                         RenderPropertyType (source, target, change);
153                         RenderName (source, target, change);
154                         RenderGenericParameters (source, target, change);
155                         RenderAccessors (srcGetter, tgtGetter, srcSetter, tgtSetter, change);
156
157                         changes.Add (source, target, change);
158
159                         return false;
160                 }
161
162                 void GetProperties (XElement e, out bool @virtual, out bool @override, out bool @static, out bool getter, out bool setter, out bool family)
163                 {
164                         @virtual = @override = @static = getter = setter = family = false;
165
166                         var methods = e.Element ("methods");
167                         if (methods != null) {
168                                 foreach (var m in methods.Elements ("method")) {
169                                         @virtual |= m.IsTrue ("virtual");
170                                         @static |= m.IsTrue ("static");
171                                         var n = m.GetAttribute ("name");
172                                         getter |= n.StartsWith ("get_", StringComparison.Ordinal);
173                                         setter |= n.StartsWith ("set_", StringComparison.Ordinal);
174                                         var attribs = (MethodAttributes) Int32.Parse (m.GetAttribute ("attrib"));
175                                         family = ((attribs & MethodAttributes.Public) != MethodAttributes.Public);
176                                         @override |= (attribs & MethodAttributes.NewSlot) == 0;
177                                 }
178                         }
179                 }
180
181                 public override string GetDescription (XElement e)
182                 {
183                         string name = e.Attribute ("name").Value;
184                         string ptype = e.GetTypeName ("ptype");
185
186                         bool virt = false;
187                         bool over = false;
188                         bool stat = false;
189                         bool getter = false;
190                         bool setter = false;
191                         bool family = false;
192                         GetProperties (e, out virt, out over, out stat, out getter, out setter, out family);
193
194                         var sb = new StringBuilder ();
195
196                         sb.Append (family ? "protected " : "public ");
197                         if (virt && !State.IgnoreVirtualChanges)
198                                 sb.Append (over ? "override " : "virtual ");
199                         else if (stat)
200                                 sb.Append ("static ");
201                         sb.Append (ptype).Append (' ').Append (name).Append (" { ");
202                         if (getter)
203                                 sb.Append ("get; ");
204                         if (setter)
205                                 sb.Append ("set; ");
206                         sb.Append ("}");
207
208                         return sb.ToString ();
209                 }
210         }
211 }