bb4f6c6b075289e6256d3033099e6f9d84fc5b1e
[mono.git] / mcs / tools / corcompare / mono-api-html / FieldComparer.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.Reflection;
31 using System.Text;
32 using System.Xml.Linq;
33
34 namespace Xamarin.ApiDiff {
35
36         public class FieldComparer : MemberComparer {
37
38                 public override string GroupName {
39                         get { return "fields"; }
40                 }
41
42                 public override string ElementName {
43                         get { return "field"; }
44                 }
45
46                 void RenderFieldAttributes (FieldAttributes source, FieldAttributes target, ApiChange change)
47                 {
48                         var srcNotSerialized = (source & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized;
49                         var tgtNotSerialized = (target & FieldAttributes.NotSerialized) == FieldAttributes.NotSerialized;
50                         if (srcNotSerialized != tgtNotSerialized) {
51                                 // this is not a breaking change, so only render it if it changed.
52                                 if (srcNotSerialized) {
53                                         change.AppendRemoved ("[NonSerialized]\n");
54                                 } else {
55                                         change.AppendAdded ("[NonSerialized]\n");
56                                 }
57                         }
58
59                         // the visibility values are the same for MethodAttributes and FieldAttributes, so just use the same method.
60                         RenderVisibility ((MethodAttributes) source, (MethodAttributes) target, change);
61                         // same for the static flag
62                         RenderStatic ((MethodAttributes) source, (MethodAttributes) target, change);
63
64                         var srcLiteral = (source & FieldAttributes.Literal) != 0;
65                         var tgtLiteral = (target & FieldAttributes.Literal) != 0;
66
67                         if (srcLiteral) {
68                                 if (tgtLiteral) {
69                                         change.Append ("const ");
70                                 } else {
71                                         change.AppendRemoved ("const", true).Append (" ");
72                                 }
73                         } else if (tgtLiteral) {
74                                 change.AppendAdded ("const", true).Append (" ");
75                         }
76
77                         var srcInitOnly = (source & FieldAttributes.InitOnly) != 0;
78                         var tgtInitOnly = (target & FieldAttributes.InitOnly) != 0;
79                         if (srcInitOnly) {
80                                 if (tgtInitOnly) {
81                                         change.Append ("readonly ");
82                                 } else {
83                                         change.AppendRemoved ("readonly", false).Append (" ");
84                                 }
85                         } else if (tgtInitOnly) {
86                                 change.AppendAdded ("readonly", true).Append (" ");
87                         }
88                 }
89
90                 public override bool Equals (XElement source, XElement target, ApiChanges changes)
91                 {
92                         if (base.Equals (source, target, changes))
93                                 return true;
94
95                         var name = source.GetAttribute ("name");
96                         var srcValue = source.GetAttribute ("value");
97                         var tgtValue = target.GetAttribute ("value");
98                         var change = new ApiChange ();
99                         change.Header = "Modified " + GroupName;
100
101                         if (State.BaseType == "System.Enum") {
102                                 change.Append (name).Append (" = ");
103                                 if (srcValue != tgtValue) {
104                                         change.AppendModified (srcValue, tgtValue, true);
105                                 } else {
106                                         change.Append (srcValue);
107                                 }
108                         } else {
109                                 RenderFieldAttributes (source.GetFieldAttributes (), target.GetFieldAttributes (), change);
110
111                                 var srcType = source.GetTypeName ("fieldtype");
112                                 var tgtType = target.GetTypeName ("fieldtype");
113
114                                 if (srcType != tgtType) {
115                                         change.AppendModified (srcType, tgtType, true);
116                                 } else {
117                                         change.Append (srcType);
118                                 }
119                                 change.Append (" ");
120                                 change.Append (name);
121
122                                 if (srcType == "string" && srcValue != null)
123                                         srcValue = "\"" + srcValue + "\"";
124
125                                 if (tgtType == "string" && tgtValue != null)
126                                         tgtValue = "\"" + tgtValue + "\"";
127
128                                 if (srcValue != tgtValue) {
129                                         change.Append (" = ");
130                                         if (srcValue == null)
131                                                 srcValue = "null";
132                                         if (tgtValue == null)
133                                                 tgtValue = "null";
134                                         change.AppendModified (srcValue, tgtValue, true);
135                                 } else if (srcValue != null) {
136                                         change.Append (" = ");
137                                         change.Append (srcValue);
138                                 }
139                                 change.Append (";");
140                         }
141
142                         changes.Add (source, target, change);
143
144                         return false;
145                 }
146
147                 public override string GetDescription (XElement e)
148                 {
149                         var sb = new StringBuilder ();
150
151                         string name = e.GetAttribute ("name");
152                         string value = e.GetAttribute ("value");
153
154                         if (State.BaseType == "System.Enum") {
155                                 sb.Append (name).Append (" = ").Append (value).Append (',');
156                         } else {
157                                 var attribs = e.Attribute ("attrib");
158                                 if (attribs != null) {
159                                         var attr = (FieldAttributes)Int32.Parse (attribs.Value);
160                                         if ((attr & FieldAttributes.Public) != FieldAttributes.Public) {
161                                                 sb.Append ("protected ");
162                                         } else {
163                                                 sb.Append ("public ");
164                                         }
165
166                                         if ((attr & FieldAttributes.Static) != 0)
167                                                 sb.Append ("static ");
168
169                                         if ((attr & FieldAttributes.Literal) != 0)
170                                                 sb.Append ("const ");
171                                 }
172
173                                 string ftype = e.GetTypeName ("fieldtype");
174                                 sb.Append (ftype).Append (' ');
175                                 sb.Append (name);
176                                 if (ftype == "string" && e.Attribute ("value") != null) {
177                                         if (value == null)
178                                                 sb.Append (" = null");
179                                         else
180                                                 sb.Append (" = \"").Append (value).Append ('"');
181                                 }
182                                 sb.Append (';');
183                         }
184
185                         return sb.ToString ();
186                 }
187
188                 public override void BeforeAdding (IEnumerable<XElement> list)
189                 {
190                         first = true;
191                         if (State.BaseType == "System.Enum") {
192                                 Output.WriteLine ("<p>Added value{0}:</p>", list.Count () > 1 ? "s" : String.Empty);
193                                 Output.WriteLine (State.Colorize ? "<pre style='color: green'>" : "<pre>");
194                         } else {
195                                 base.BeforeAdding (list);
196                         }
197                 }
198
199                 public override void BeforeRemoving (IEnumerable<XElement> list)
200                 {
201                         first = true;
202                         if (State.BaseType == "System.Enum") {
203                                 Output.WriteLine ("<p>Removed value{0}:</p>", list.Count () > 1 ? "s" : String.Empty);
204                                 Output.WriteLine (State.Colorize ? "<pre style='color: red'>" : "<pre>");
205                         } else {
206                                 base.BeforeRemoving (list);
207                         }
208                 }
209         }
210 }