3 // Sebastien Pouliot <sebastien@xamarin.com>
5 // Copyright 2013 Xamarin Inc. http://www.xamarin.com
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:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
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.
28 using System.Collections.Generic;
31 using System.Xml.Linq;
33 namespace Xamarin.ApiDiff {
35 public class ClassComparer : Comparer {
37 InterfaceComparer icomparer;
38 ConstructorComparer ccomparer;
39 FieldComparer fcomparer;
40 PropertyComparer pcomparer;
41 EventComparer ecomparer;
42 MethodComparer mcomparer;
43 ClassComparer kcomparer;
45 public ClassComparer ()
47 icomparer = new InterfaceComparer ();
48 ccomparer = new ConstructorComparer ();
49 fcomparer = new FieldComparer ();
50 pcomparer = new PropertyComparer ();
51 ecomparer = new EventComparer ();
52 mcomparer = new MethodComparer ();
55 public override void SetContext (XElement current)
57 State.Type = current.GetAttribute ("name");
58 State.BaseType = current.GetAttribute ("base");
61 public void Compare (XElement source, XElement target)
63 var s = source.Element ("classes");
64 var t = target.Element ("classes");
65 if (XNode.DeepEquals (s, t))
67 Compare (s.Elements ("class"), t.Elements ("class"));
70 public override void Added (XElement target, bool wasParentAdded)
72 string name = target.Attribute ("name").Value;
73 if (State.IgnoreNew.Any (re => re.IsMatch (name)))
75 Output.WriteLine ("<div> <!-- start type {0} -->", name);
76 Output.WriteLine ("<h3>New Type {0}.{1}</h3>", State.Namespace, name);
77 Output.WriteLine ("<pre class='added' data-is-non-breaking>");
80 Output.WriteLine ("</pre>");
81 Output.WriteLine ("</div> <!-- end type {0} -->", name);
84 public void AddedInner (XElement target)
87 if (target.IsTrue ("serializable"))
88 Indent ().WriteLine ("[Serializable]");
90 var type = target.Attribute ("type").Value;
93 // check if [Flags] is present
94 var cattrs = target.Element ("attributes");
96 foreach (var ca in cattrs.Elements ("attribute")) {
97 if (ca.GetAttribute ("name") == "System.FlagsAttribute") {
98 Indent ().WriteLine ("[Flags]");
105 Indent ().Write ("public");
107 if (type != "enum") {
108 bool seal = target.IsTrue ("sealed");
109 bool abst = target.IsTrue ("abstract");
111 Output.Write (" static");
112 else if (seal && type != "struct")
113 Output.Write (" sealed");
114 else if (abst && type != "interface")
115 Output.Write (" abstract");
121 Output.Write (target.GetAttribute ("name"));
123 var baseclass = target.GetAttribute ("base");
124 if ((type != "enum") && (type != "struct")) {
125 if (baseclass != null) {
126 if (baseclass == "System.Object") {
127 // while true we do not need to be reminded every time...
130 Output.Write (" : ");
131 Output.Write (baseclass);
136 // interfaces on enums are "standard" not user provided - so we do not want to show them
137 if (type != "enum") {
138 var i = target.Element ("interfaces");
140 var interfaces = new List<string> ();
141 foreach (var iface in i.Elements ("interface"))
142 interfaces.Add (icomparer.GetDescription (iface));
143 Output.Write ((baseclass == null) ? " : " : ", ");
144 Output.Write (String.Join (", ", interfaces));
148 Output.WriteLine (" {");
150 var t = target.Element ("constructors");
152 Indent ().WriteLine ("\t// constructors");
153 foreach (var ctor in t.Elements ("constructor"))
154 ccomparer.Added (ctor, true);
157 t = target.Element ("fields");
160 Indent ().WriteLine ("\t// fields");
163 foreach (var field in t.Elements ("field"))
164 fcomparer.Added (field, true);
167 t = target.Element ("properties");
169 Indent ().WriteLine ("\t// properties");
170 foreach (var property in t.Elements ("property"))
171 pcomparer.Added (property, true);
174 t = target.Element ("events");
176 Indent ().WriteLine ("\t// events");
177 foreach (var evnt in t.Elements ("event"))
178 ecomparer.Added (evnt, true);
181 t = target.Element ("methods");
183 Indent ().WriteLine ("\t// methods");
184 foreach (var method in t.Elements ("method"))
185 mcomparer.Added (method, true);
188 t = target.Element ("classes");
191 Indent ().WriteLine ("\t// inner types");
192 kcomparer = new NestedClassComparer ();
194 foreach (var inner in t.Elements ("class"))
195 kcomparer.AddedInner (inner);
198 Indent ().WriteLine ("}");
201 public override void Modified (XElement source, XElement target, ApiChanges diff)
203 // hack - there could be changes that we're not monitoring (e.g. attributes properties)
205 State.Output = new StringWriter ();
207 var sb = source.GetAttribute ("base");
208 var tb = target.GetAttribute ("base");
210 Output.Write ("Modified base type: ");
211 Output.WriteLine (new ApiChange ().AppendModified (sb, tb, true).Member.ToString ());
214 ccomparer.Compare (source, target);
215 icomparer.Compare (source, target);
216 fcomparer.Compare (source, target);
217 pcomparer.Compare (source, target);
218 ecomparer.Compare (source, target);
219 mcomparer.Compare (source, target);
221 var si = source.Element ("classes");
223 var ti = target.Element ("classes");
224 kcomparer = new NestedClassComparer ();
225 kcomparer.Compare (si.Elements ("class"), ti == null ? null : ti.Elements ("class"));
228 var s = (Output as StringWriter).ToString ();
229 State.Output = output;
231 var tn = GetTypeName (target);
232 Output.WriteLine ("<!-- start type {0} --> <div>", tn);
233 Output.WriteLine ("<h3>Type Changed: {0}.{1}</h3>", State.Namespace, GetTypeName (target));
234 Output.WriteLine (s);
235 Output.WriteLine ("</div> <!-- end type {0} -->", tn);
239 public override void Removed (XElement source)
241 Output.Write ("<h3>Removed Type <span class='breaking' data-is-breaking>{0}.{1}</span></h3>", State.Namespace, GetTypeName (source));
244 public virtual string GetTypeName (XElement type)
246 return type.GetAttribute ("name");
250 public class NestedClassComparer : ClassComparer {
252 public override void SetContext (XElement current)
256 public override string GetTypeName (XElement type)
258 return State.Type + "." + base.GetTypeName (type);