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>");
79 Output.WriteLine ("</pre>");
82 public void AddedInner (XElement target)
85 if (target.IsTrue ("serializable"))
86 Indent ().WriteLine ("[Serializable]");
88 var type = target.Attribute ("type").Value;
91 // check if [Flags] is present
92 var cattrs = target.Element ("attributes");
94 foreach (var ca in cattrs.Elements ("attribute")) {
95 if (ca.GetAttribute ("name") == "System.FlagsAttribute") {
96 Indent ().WriteLine ("[Flags]");
103 Indent ().Write ("public");
105 if (type != "enum") {
106 bool seal = target.IsTrue ("sealed");
107 bool abst = target.IsTrue ("abstract");
109 Output.Write (" static");
110 else if (seal && type != "struct")
111 Output.Write (" sealed");
112 else if (abst && type != "interface")
113 Output.Write (" abstract");
119 Output.Write (target.GetAttribute ("name"));
121 var baseclass = target.GetAttribute ("base");
122 if ((type != "enum") && (type != "struct")) {
123 if (baseclass != null) {
124 if (baseclass == "System.Object") {
125 // while true we do not need to be reminded every time...
128 Output.Write (" : ");
129 Output.Write (baseclass);
134 // interfaces on enums are "standard" not user provided - so we do not want to show them
135 if (type != "enum") {
136 var i = target.Element ("interfaces");
138 var interfaces = new List<string> ();
139 foreach (var iface in i.Elements ("interface"))
140 interfaces.Add (icomparer.GetDescription (iface));
141 Output.Write ((baseclass == null) ? " : " : ", ");
142 Output.Write (String.Join (", ", interfaces));
146 Output.WriteLine (" {");
148 var t = target.Element ("constructors");
150 Indent ().WriteLine ("\t// constructors");
151 foreach (var ctor in t.Elements ("constructor"))
152 ccomparer.Added (ctor);
155 t = target.Element ("fields");
158 Indent ().WriteLine ("\t// fields");
161 foreach (var field in t.Elements ("field"))
162 fcomparer.Added (field);
165 t = target.Element ("properties");
167 Indent ().WriteLine ("\t// properties");
168 foreach (var property in t.Elements ("property"))
169 pcomparer.Added (property);
172 t = target.Element ("events");
174 Indent ().WriteLine ("\t// events");
175 foreach (var evnt in t.Elements ("event"))
176 ecomparer.Added (evnt);
179 t = target.Element ("methods");
181 Indent ().WriteLine ("\t// methods");
182 foreach (var method in t.Elements ("method"))
183 mcomparer.Added (method);
186 t = target.Element ("classes");
189 Indent ().WriteLine ("\t// inner types");
190 kcomparer = new NestedClassComparer ();
192 foreach (var inner in t.Elements ("class"))
193 kcomparer.AddedInner (inner);
196 Indent ().WriteLine ("}");
199 public override void Modified (XElement source, XElement target)
201 // hack - there could be changes that we're not monitoring (e.g. attributes properties)
203 State.Output = new StringWriter ();
205 ccomparer.Compare (source, target);
206 icomparer.Compare (source, target);
207 fcomparer.Compare (source, target);
208 pcomparer.Compare (source, target);
209 ecomparer.Compare (source, target);
210 mcomparer.Compare (source, target);
212 var si = source.Element ("classes");
214 var ti = target.Element ("classes");
215 kcomparer = new NestedClassComparer ();
216 kcomparer.Compare (si.Elements ("class"), ti == null ? null : ti.Elements ("class"));
219 var s = (Output as StringWriter).ToString ();
220 State.Output = output;
222 Output.WriteLine ("<h3>Type Changed: {0}.{1}</h3>", State.Namespace, GetTypeName (target));
223 Output.WriteLine (s);
227 public override void Removed (XElement source)
229 Output.WriteLine ("<h3>Removed Type {0}.{1}", State.Namespace, GetTypeName (source));
232 public virtual string GetTypeName (XElement type)
234 return type.GetAttribute ("name");
238 public class NestedClassComparer : ClassComparer {
240 public override void SetContext (XElement current)
244 public override string GetTypeName (XElement type)
246 return State.Type + "." + base.GetTypeName (type);