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