{ "h|?|help",
"Show this message and exit.",
v => showHelp = v != null },
+ { "contract-api",
+ "Produces contract API with all members at each level of inheritance hierarchy",
+ v => FullAPISet = v != null },
};
var asms = options.Parse (args);
internal static bool AbiMode { get; private set; }
internal static bool FollowForwarders { get; private set; }
+ internal static bool FullAPISet { get; set; }
}
public class Utils {
members.Add (new ConstructorData (writer, ctors));
}
- PropertyDefinition[] properties = GetProperties (type);
+ PropertyDefinition[] properties = GetProperties (type, Driver.FullAPISet);
if (properties.Length > 0) {
Array.Sort (properties, PropertyDefinitionComparer.Default);
members.Add (new PropertyData (writer, properties));
members.Add (new EventData (writer, events));
}
- MethodDefinition [] methods = GetMethods (type);
+ MethodDefinition [] methods = GetMethods (type, Driver.FullAPISet);
if (methods.Length > 0) {
Array.Sort (methods, MethodDefinitionComparer.Default);
members.Add (new MethodData (writer, methods));
}
- internal static PropertyDefinition [] GetProperties (TypeDefinition type) {
- ArrayList list = new ArrayList ();
+ internal static PropertyDefinition [] GetProperties (TypeDefinition type, bool fullAPI) {
+ var list = new List<PropertyDefinition> ();
+
+ var t = type;
+ do {
+ var properties = t.Properties;//type.GetProperties (flags);
+ foreach (PropertyDefinition property in properties) {
+ MethodDefinition getMethod = property.GetMethod;
+ MethodDefinition setMethod = property.SetMethod;
+
+ bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
+ bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
- var properties = type.Properties;//type.GetProperties (flags);
- foreach (PropertyDefinition property in properties) {
- MethodDefinition getMethod = property.GetMethod;
- MethodDefinition setMethod = property.SetMethod;
+ // if neither the getter or setter should be documented, then
+ // skip the property
+ if (hasGetter || hasSetter) {
- bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
- bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
+ if (t != type && list.Any (l => l.Name == property.Name))
+ continue;
- // if neither the getter or setter should be documented, then
- // skip the property
- if (hasGetter || hasSetter) {
- list.Add (property);
+ list.Add (property);
+ }
}
- }
- return (PropertyDefinition []) list.ToArray (typeof (PropertyDefinition));
+ if (!fullAPI)
+ break;
+
+ if (t.IsInterface || t.IsEnum)
+ break;
+
+ if (t.BaseType == null || t.BaseType.FullName == "System.Object")
+ t = null;
+ else
+ t = t.BaseType.Resolve ();
+
+ } while (t != null);
+
+ return list.ToArray ();
}
- private MethodDefinition[] GetMethods (TypeDefinition type)
+ private MethodDefinition[] GetMethods (TypeDefinition type, bool fullAPI)
{
- ArrayList list = new ArrayList ();
+ var list = new List<MethodDefinition> ();
- var methods = type.Methods;//type.GetMethods (flags);
- foreach (MethodDefinition method in methods) {
- if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal))
- continue;
+ var t = type;
+ do {
+ var methods = t.Methods;//type.GetMethods (flags);
+ foreach (MethodDefinition method in methods) {
+ if (method.IsSpecialName && !method.Name.StartsWith ("op_", StringComparison.Ordinal))
+ continue;
- // we're only interested in public or protected members
- if (!MustDocumentMethod(method))
- continue;
+ // we're only interested in public or protected members
+ if (!MustDocumentMethod (method))
+ continue;
- if (IsFinalizer (method)) {
- string name = method.DeclaringType.Name;
- int arity = name.IndexOf ('`');
- if (arity > 0)
- name = name.Substring (0, arity);
+ if (t == type && IsFinalizer (method)) {
+ string name = method.DeclaringType.Name;
+ int arity = name.IndexOf ('`');
+ if (arity > 0)
+ name = name.Substring (0, arity);
- method.Name = "~" + name;
+ method.Name = "~" + name;
+ }
+
+ if (t != type && list.Any (l => l.DeclaringType != method.DeclaringType && l.Name == method.Name && l.Parameters.Count == method.Parameters.Count &&
+ l.Parameters.SequenceEqual (method.Parameters, new ParameterComparer ())))
+ continue;
+
+ list.Add (method);
}
- list.Add (method);
+ if (!fullAPI)
+ break;
+
+ if (t.IsInterface || t.IsEnum)
+ break;
+
+ if (t.BaseType == null || t.BaseType.FullName == "System.Object")
+ t = null;
+ else
+ t = t.BaseType.Resolve ();
+
+ } while (t != null);
+
+ return list.ToArray ();
+ }
+
+ sealed class ParameterComparer : IEqualityComparer<ParameterDefinition>
+ {
+ public bool Equals (ParameterDefinition x, ParameterDefinition y)
+ {
+ return x.ParameterType.Name == y.ParameterType.Name;
}
- return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
+ public int GetHashCode (ParameterDefinition obj)
+ {
+ return obj.ParameterType.Name.GetHashCode ();
+ }
}
static bool IsFinalizer (MethodDefinition method)
AddAttribute ("sealed", "true");
if (mbase.IsStatic)
AddAttribute ("static", "true");
+ var baseMethod = TypeHelper.GetBaseMethodInTypeHierarchy (mbase);
+ if (baseMethod != null && baseMethod != mbase) {
+ // This indicates whether this method is an override of another method.
+ // This information is not necessarily available in the api info for any
+ // particular assembly, because a method is only overriding another if
+ // there is a base virtual function with the same signature, and that
+ // base method can come from another assembly.
+ AddAttribute ("is-override", "true");
+ }
string rettype = Utils.CleanupTypeName (mbase.MethodReturnType.ReturnType);
if (rettype != "System.Void" || !mbase.IsConstructor)
AddAttribute ("returntype", (rettype));
if (!(memberDefenition is MethodDefinition))
return;
- MethodDefinition mbase = (MethodDefinition) memberDefenition;
+ MethodDefinition mbase = (MethodDefinition)memberDefenition;
+
+ ParameterData parms = new ParameterData (writer, mbase.Parameters) {
+ HasExtensionParameter = mbase.CustomAttributes.Any (l => l.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
+ };
- ParameterData parms = new ParameterData (writer, mbase.Parameters);
parms.DoOutput ();
MemberData.OutputGenericParameters (writer, mbase);
this.parameters = parameters;
}
+ public bool HasExtensionParameter { get; set; }
+
public override void DoOutput ()
{
+ bool first = true;
writer.WriteStartElement ("parameters");
foreach (ParameterDefinition parameter in parameters) {
writer.WriteStartElement ("parameter");
AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
AddAttribute ("attrib", ((int) parameter.Attributes).ToString());
- string direction = "in";
+ string direction = first && HasExtensionParameter ? "this" : "in";
+ first = false;
if (parameter.ParameterType is ByReferenceType)
direction = parameter.IsOut ? "out" : "ref";
ParameterDefinition info = infos [i];
- string modifier;
- if ((info.Attributes & ParameterAttributes.In) != 0)
- modifier = "in";
- else if ((info.Attributes & ParameterAttributes.Out) != 0)
- modifier = "out";
- else
- modifier = string.Empty;
+ if (info.ParameterType.IsByReference) {
+ string modifier;
+ if ((info.Attributes & (ParameterAttributes.Out | ParameterAttributes.In)) == ParameterAttributes.Out)
+ modifier = "out";
+ else
+ modifier = "ref";
- if (modifier.Length > 0) {
signature.Append (modifier);
signature.Append (" ");
}
if (res != 0)
return res;
+ if (ma.HasGenericParameters != mb.HasGenericParameters)
+ return ma.HasGenericParameters ? -1 : 1;
+
+ if (ma.HasGenericParameters && mb.HasGenericParameters) {
+ res = ma.GenericParameters.Count - mb.GenericParameters.Count;
+ if (res != 0)
+ return res;
+ }
+
// operators can differ by only return type
return string.CompareOrdinal (ma.ReturnType.FullName, mb.ReturnType.FullName);
}