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)
72 string name = target.Attribute ("name").Value;
73 if (State.IgnoreNew.Any (re => re.IsMatch (name)))
75 Output.WriteLine ("<h3>New Type {0}.{1}</h3>", State.Namespace, name);
76 Output.WriteLine ("<pre>");
78 Output.WriteLine ("<font color='green'>");
82 Output.WriteLine ("</font>");
83 Output.WriteLine ("</pre>");
86 public void AddedInner (XElement target)
89 if (target.IsTrue ("serializable"))
90 Indent ().WriteLine ("[Serializable]");
92 var type = target.Attribute ("type").Value;
95 // check if [Flags] is present
96 var cattrs = target.Element ("attributes");
98 foreach (var ca in cattrs.Elements ("attribute")) {
99 if (ca.GetAttribute ("name") == "System.FlagsAttribute") {
100 Indent ().WriteLine ("[Flags]");
107 Indent ().Write ("public");
109 if (type != "enum") {
110 bool seal = target.IsTrue ("sealed");
111 bool abst = target.IsTrue ("abstract");
113 Output.Write (" static");
114 else if (seal && type != "struct")
115 Output.Write (" sealed");
116 else if (abst && type != "interface")
117 Output.Write (" abstract");
123 Output.Write (target.GetAttribute ("name"));
125 var baseclass = target.GetAttribute ("base");
126 if ((type != "enum") && (type != "struct")) {
127 if (baseclass != null) {
128 if (baseclass == "System.Object") {
129 // while true we do not need to be reminded every time...
132 Output.Write (" : ");
133 Output.Write (baseclass);
138 // interfaces on enums are "standard" not user provided - so we do not want to show them
139 if (type != "enum") {
140 var i = target.Element ("interfaces");
142 var interfaces = new List<string> ();
143 foreach (var iface in i.Elements ("interface"))
144 interfaces.Add (icomparer.GetDescription (iface));
145 Output.Write ((baseclass == null) ? " : " : ", ");
146 Output.Write (String.Join (", ", interfaces));
150 Output.WriteLine (" {");
152 var t = target.Element ("constructors");
154 Indent ().WriteLine ("\t// constructors");
155 foreach (var ctor in t.Elements ("constructor"))
156 ccomparer.Added (ctor);
159 t = target.Element ("fields");
162 Indent ().WriteLine ("\t// fields");
165 foreach (var field in t.Elements ("field"))
166 fcomparer.Added (field);
169 t = target.Element ("properties");
171 Indent ().WriteLine ("\t// properties");
172 foreach (var property in t.Elements ("property"))
173 pcomparer.Added (property);
176 t = target.Element ("events");
178 Indent ().WriteLine ("\t// events");
179 foreach (var evnt in t.Elements ("event"))
180 ecomparer.Added (evnt);
183 t = target.Element ("methods");
185 Indent ().WriteLine ("\t// methods");
186 foreach (var method in t.Elements ("method"))
187 mcomparer.Added (method);
190 t = target.Element ("classes");
193 Indent ().WriteLine ("\t// inner types");
194 kcomparer = new NestedClassComparer ();
196 foreach (var inner in t.Elements ("class"))
197 kcomparer.AddedInner (inner);
200 Indent ().WriteLine ("}");
203 public override void Modified (XElement source, XElement target, ApiChanges diff)
205 // hack - there could be changes that we're not monitoring (e.g. attributes properties)
207 State.Output = new StringWriter ();
209 ccomparer.Compare (source, target);
210 icomparer.Compare (source, target);
211 fcomparer.Compare (source, target);
212 pcomparer.Compare (source, target);
213 ecomparer.Compare (source, target);
214 mcomparer.Compare (source, target);
216 var si = source.Element ("classes");
218 var ti = target.Element ("classes");
219 kcomparer = new NestedClassComparer ();
220 kcomparer.Compare (si.Elements ("class"), ti == null ? null : ti.Elements ("class"));
223 var s = (Output as StringWriter).ToString ();
224 State.Output = output;
226 Output.WriteLine ("<h3>Type Changed: {0}.{1}</h3>", State.Namespace, GetTypeName (target));
227 Output.WriteLine (s);
231 public override void Removed (XElement source)
233 Output.WriteLine ("<h3>Removed Type {0}.{1}", State.Namespace, GetTypeName (source));
236 public virtual string GetTypeName (XElement type)
238 return type.GetAttribute ("name");
242 public class NestedClassComparer : ClassComparer {
244 public override void SetContext (XElement current)
248 public override string GetTypeName (XElement type)
250 return State.Type + "." + base.GetTypeName (type);