//
// Authors:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Marek Safar (marek.safar@gmail.com)
//
-// (C) 2003 Novell, Inc (http://www.novell.com)
+// Maintainer:
+// C.J. Adams-Collier (cjac@colliertech.org)
//
+// (C) 2003 Novell, Inc (http://www.novell.com)
+// (C) 2009,2010 Collier Technologies (http://www.colliertech.org)
using System;
using System.Collections;
{
static int Main (string [] args)
{
- if (args.Length != 2)
+ if (args.Length != 2) {
+ Console.WriteLine ("Usage: mono mono-api-diff.exe <assembly 1 xml> <assembly 2 xml>");
return 1;
+ }
XMLAssembly ms = CreateXMLAssembly (args [0]);
XMLAssembly mono = CreateXMLAssembly (args [1]);
return (object []) list.ToArray (type);
}
+ public static bool IsMeaninglessAttribute (string s)
+ {
+ if (s == null)
+ return false;
+ if (s == "System.Runtime.CompilerServices.CompilerGeneratedAttribute")
+ return true;
+ return false;
+ }
+
+ public static bool IsMonoTODOAttribute (string s)
+ {
+ if (s == null)
+ return false;
+ if (//s.EndsWith ("MonoTODOAttribute") ||
+ s.EndsWith ("MonoDocumentationNoteAttribute") ||
+ s.EndsWith ("MonoExtensionAttribute") ||
+// s.EndsWith ("MonoInternalNoteAttribute") ||
+ s.EndsWith ("MonoLimitationAttribute") ||
+ s.EndsWith ("MonoNotSupportedAttribute"))
+ return true;
+ return s.EndsWith ("TODOAttribute");
+ }
+
protected void AddAttribute (XmlNode node, string name, string value)
{
XmlAttribute attr = document.CreateAttribute (name);
public bool HaveWarnings {
get { return haveWarnings; }
}
-
+
public Counters Counters {
get { return counters; }
}
-
+
public abstract void CompareTo (XmlDocument doc, XmlNode parent, object other);
}
-
+
abstract class XMLNameGroup : XMLData
{
protected XmlNode group;
newNS.Add (node);
AddAttribute (node, "name", xns.Name);
- if (oh.ContainsKey (xns.Name)) {
- int idx = (int) oh [xns.Name];
- xns.CompareTo (document, node, other [idx]);
+ int idx = -1;
+ if (oh.ContainsKey (xns.Name))
+ idx = (int) oh [xns.Name];
+ XMLNamespace ons = idx >= 0 ? (XMLNamespace) other [idx] : null;
+ xns.CompareTo (document, node, ons);
+ if (idx >= 0)
other [idx] = null;
- xns.AddCountersAttributes (node);
- counters.Present++;
- counters.PresentTotal++;
- counters.AddPartialToTotal (xns.Counters);
- } else {
- AddAttribute (node, "presence", "missing");
- counters.Missing++;
- counters.MissingTotal++;
- }
+ xns.AddCountersAttributes (node);
+ counters.Present++;
+ counters.PresentTotal++;
+ counters.AddPartialToTotal (xns.Counters);
}
if (other != null) {
this.document = doc;
XmlNode parent = doc.CreateElement ("assemblies", null);
doc.AppendChild (parent);
-
+
CompareTo (doc, parent, other);
XmlNode decl = doc.CreateXmlDeclaration ("1.0", null, null);
XmlNode childA = doc.CreateElement ("classes", null);
parent.AppendChild (childA);
- CompareTypes (childA, nspace.types);
+ CompareTypes (childA, nspace != null ? nspace.types : new XMLClass [0]);
}
void CompareTypes (XmlNode parent, XMLClass [] other)
AddAttribute (node, "name", xclass.Name);
AddAttribute (node, "type", xclass.Type);
- if (oh.ContainsKey (xclass.Name)) {
- int idx = (int) oh [xclass.Name];
- xclass.CompareTo (document, node, other [idx]);
+ int idx = -1;
+ if (oh.ContainsKey (xclass.Name))
+ idx = (int) oh [xclass.Name];
+ xclass.CompareTo (document, node, idx >= 0 ? other [idx] : new XMLClass ());
+ if (idx >= 0)
other [idx] = null;
- counters.AddPartialToPartial (xclass.Counters);
- } else {
- AddAttribute (node, "presence", "missing");
- counters.Missing++;
- counters.MissingTotal++;
- }
+ counters.AddPartialToPartial (xclass.Counters);
}
if (other != null) {
count = other.Length;
for (int i = 0; i < count; i++) {
XMLClass c = other [i];
- if (c == null || c.Name.EndsWith ("TODOAttribute"))
+ if (c == null || IsMonoTODOAttribute (c.Name))
continue;
node = document.CreateElement ("class", null);
XMLEvents events;
XMLMethods methods;
XMLClass [] nested;
-
+
public override void LoadData (XmlNode node)
{
if (node == null)
// Console.Error.WriteLine ("Empty class {0} {1}", name, type);
return;
}
-
+
if (child.Name == "attributes") {
attributes = new XMLAttributes ();
attributes.LoadData (child);
child = child.NextSibling;
}
+ if (child != null && child.Name == "generic-parameters") {
+ // HACK: ignore this tag as it doesn't seem to
+ // add any value when checking for differences
+ return;
+ }
+
if (child == null)
return;
for (int i = 0; i < count; i++) {
XMLClass xclass = nested [i];
- node = document.CreateElement ("nestedclass", null);
+ node = document.CreateElement ("class", null);
newNodes.Add (node);
AddAttribute (node, "name", xclass.Name);
AddAttribute (node, "type", xclass.Type);
count = other.Length;
for (int i = 0; i < count; i++) {
XMLClass c = other [i];
- if (c == null || c.Name.EndsWith ("TODOAttribute"))
+ if (c == null || IsMonoTODOAttribute (c.Name))
continue;
- node = document.CreateElement ("nestedclass", null);
+ node = document.CreateElement ("class", null);
newNodes.Add (node);
AddAttribute (node, "name", c.Name);
+ AddAttribute (node, "type", c.Type);
AddExtra (node);
counters.Extra++;
counters.ExtraTotal++;
bool isUnsafe;
bool isOptional;
string defaultValue;
+ XMLAttributes attributes;
public override void LoadData (XmlNode node)
{
isOptional = bool.Parse (node.Attributes["optional"].Value);
if (node.Attributes["defaultValue"] != null)
defaultValue = node.Attributes["defaultValue"].Value;
+
+ XmlNode child = node.FirstChild;
+ if (child == null)
+ return;
+
+ if (child.Name == "attributes") {
+ attributes = new XMLAttributes ();
+ attributes.LoadData (child);
+ child = child.NextSibling;
+ }
}
public override void CompareTo (XmlDocument doc, XmlNode parent, object other)
XMLParameter oparm = (XMLParameter) other;
+ if (name != oparm.name)
+ AddWarning (parent, "Parameter name is wrong: {0} != {1}", name, oparm.name);
+
if (type != oparm.type)
AddWarning (parent, "Parameter type is wrong: {0} != {1}", type, oparm.type);
-
+
if (attrib != oparm.attrib)
AddWarning (parent, "Parameter attributes wrong: {0} != {1}", attrib, oparm.attrib);
if (defaultValue != oparm.defaultValue)
AddWarning (parent, "Parameter default value wrong: {0} != {1}", (defaultValue == null) ? "(no default value)" : defaultValue, (oparm.defaultValue == null) ? "(no default value)" : oparm.defaultValue);
+
+ if (attributes != null || oparm.attributes != null) {
+ if (attributes == null)
+ attributes = new XMLAttributes ();
+
+ attributes.CompareTo (doc, parent, oparm.attributes);
+ counters.AddPartialToPartial (attributes.Counters);
+ if (oparm.attributes != null && oparm.attributes.IsTodo) {
+ counters.Todo++;
+ counters.TodoTotal++;
+ counters.ErrorTotal++;
+ AddAttribute (parent, "error", "todo");
+ if (oparm.attributes.Comment != null)
+ AddAttribute (parent, "comment", oparm.attributes.Comment);
+ }
+ }
}
public string Name {
if (de.Value.Equals (other_value))
continue;
- AddWarning (parent, "Property '{0}' is '{1}' and should be '{2}'",
+ AddWarning (parent, "Property '{0}' is '{1}' and should be '{2}'",
de.Key, de.Value, other_value == null ? "null" : other_value);
}
}
protected override bool CheckIfAdd (string value, XmlNode node)
{
- if (value.EndsWith ("TODOAttribute")) {
+ if (IsMonoTODOAttribute (value)) {
isTodo = true;
XmlNode pNode = node.SelectSingleNode ("properties");
- if (pNode.ChildNodes [0].Attributes ["value"] != null) {
+ if (pNode != null && pNode.ChildNodes.Count > 0 && pNode.ChildNodes [0].Attributes ["value"] != null) {
comment = pNode.ChildNodes [0].Attributes ["value"].Value;
}
return false;
}
- return true;
+ return !IsMeaninglessAttribute (value);
}
protected override void CompareToInner (string name, XmlNode node, XMLNameGroup other)
{
string key = null;
- // if multiple attributes with the same name (type) exist, then we
+ // if multiple attributes with the same name (type) exist, then we
// cannot be sure which attributes correspond, so we must use the
// name of the attribute (type) and the name/value of its properties
// as key
}
}
- // sort properties by name, as order of properties in XML is
+ // sort properties by name, as order of properties in XML is
// undefined
keyParts.Sort ();
{
XmlNode pNode = node.SelectSingleNode ("properties");
- if (name.EndsWith ("TODOAttribute")) {
+ if (IsMonoTODOAttribute (name)) {
isTodo = true;
if (pNode.ChildNodes [0].Attributes ["value"] != null) {
comment = pNode.ChildNodes [0].Attributes ["value"].Value;
XmlAttribute xatt = node.Attributes ["attrib"];
if (xatt != null)
access [name] = xatt.Value;
-
+
XmlNode orig = node;
node = node.FirstChild;
return null;
}
}
-
+
class XMLFields : XMLMember
{
Hashtable fieldTypes;
public override string GetNodeKey (string name, XmlNode node)
{
XmlAttributeCollection atts = node.Attributes;
- return String.Format ("{0}:{1}:{2}", atts ["name"].Value,
- atts ["ptype"].Value,
- atts ["params"].Value);
+ return String.Format ("{0}:{1}:{2}",
+ (atts["name"] != null ? atts["name"].Value : ""),
+ (atts["ptype"] != null ? atts["ptype"].Value : ""),
+ (atts["params"] != null ? atts["params"].Value : "")
+ );
}
public override string GroupName {
class XMLEvents : XMLMember
{
Hashtable eventTypes;
+ Hashtable nameToMethod = new Hashtable ();
protected override void LoadExtraData (string name, XmlNode node)
{
eventTypes [name] = xatt.Value;
}
+ XmlNode child = node.FirstChild;
+ while (child != null) {
+ if (child != null && child.Name == "methods") {
+ XMLMethods m = new XMLMethods ();
+ XmlNode parent = child.ParentNode;
+ string key = GetNodeKey (name, parent);
+ m.LoadData (child);
+ nameToMethod [key] = m;
+ break;
+ }
+ child = child.NextSibling;
+ }
+
base.LoadExtraData (name, node);
}
if (etype != oetype)
AddWarning (parent, "Event type is {0} and should be {1}", oetype, etype);
+
+ XMLMethods m = nameToMethod [name] as XMLMethods;
+ XMLMethods om = evt.nameToMethod [name] as XMLMethods;
+ if (m != null || om != null) {
+ if (m == null)
+ m = new XMLMethods ();
+
+ m.CompareTo (document, parent, om);
+ counters.AddPartialToPartial (m.Counters);
+ }
} finally {
AddCountersAttributes (parent);
copy.AddPartialToPartial (counters);
None = 0,
Abstract = 1,
Virtual = 2,
- Static = 4
+ Static = 4,
+ Final = 8,
}
protected override void LoadExtraData (string name, XmlNode node)
flags |= SignatureFlags.Static;
if (((XmlElement) node).GetAttribute ("virtual") == "true")
flags |= SignatureFlags.Virtual;
+ if (((XmlElement) node).GetAttribute ("final") == "true")
+ flags |= SignatureFlags.Final;
if (flags != SignatureFlags.None) {
if (signatureFlags == null)
signatureFlags = new Hashtable ();
base.LoadExtraData (name, node);
}
+ public override string GetNodeKey (string name, XmlNode node)
+ {
+ // for explicit/implicit operators we need to include the return
+ // type in the key to allow matching; as a side-effect, differences
+ // in return types will be reported as extra/missing methods
+ //
+ // for regular methods we do not need to take into account the
+ // return type for matching methods; differences in return types
+ // will be reported as a warning on the method
+ if (name.StartsWith ("op_")) {
+ XmlAttribute xatt = node.Attributes ["returntype"];
+ string returnType = xatt != null ? xatt.Value + " " : string.Empty;
+ return returnType + name;
+ }
+ return name;
+ }
+
protected override void CompareToInner (string name, XmlNode parent, XMLNameGroup other)
{
// create backup of actual counters
if ((ma & MethodAttributes.RequireSecObject) != 0)
ma = (MethodAttributes) (att - (int) MethodAttributes.RequireSecObject);
- // we don't care if the implementation is forwarded through PInvoke
+ // we don't care if the implementation is forwarded through PInvoke
if ((ma & MethodAttributes.PinvokeImpl) != 0)
ma = (MethodAttributes) (att - (int) MethodAttributes.PinvokeImpl);