{ "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 {
+ static char[] CharsToCleanup = new char[] { '<', '>', '/' };
public static string CleanupTypeName (TypeReference type)
{
public static string CleanupTypeName (string t)
{
- return t.Replace ('<', '[').Replace ('>', ']').Replace ('/', '+');
+ if (t.IndexOfAny (CharsToCleanup) == -1)
+ return t;
+ var sb = new StringBuilder (t.Length);
+ for (int i = 0; i < t.Length; i++) {
+ var ch = t [i];
+ switch (ch) {
+ case '<':
+ sb.Append ('[');
+ break;
+ case '>':
+ sb.Append (']');
+ break;
+ case '/':
+ sb.Append ('+');
+ break;
+ default:
+ sb.Append (ch);
+ break;
+ }
+ }
+ return sb.ToString ();
}
}
if (File.Exists (assembly))
return TypeHelper.Resolver.ResolveFile (assembly);
- return TypeHelper.Resolver.Resolve (assembly);
+ return TypeHelper.Resolver.Resolve (AssemblyNameReference.Parse (assembly), new ReaderParameters ());
} catch (Exception e) {
Console.WriteLine (e);
return null;
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;
- var properties = type.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);
- bool hasGetter = (getMethod != null) && MustDocumentMethod (getMethod);
- bool hasSetter = (setMethod != null) && MustDocumentMethod (setMethod);
+ // if neither the getter or setter should be documented, then
+ // skip the property
+ if (hasGetter || hasSetter) {
- // if neither the getter or setter should be documented, then
- // skip the property
- if (hasGetter || hasSetter) {
- list.Add (property);
+ if (t != type && list.Any (l => l.Name == property.Name))
+ continue;
+
+ 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)
+ var pt = parameter.ParameterType;
+ var brt = pt as ByReferenceType;
+ if (brt != null) {
direction = parameter.IsOut ? "out" : "ref";
+ pt = brt.ElementType;
+ }
- TypeReference t = parameter.ParameterType;
- AddAttribute ("type", Utils.CleanupTypeName (t));
+ AddAttribute ("type", Utils.CleanupTypeName (pt));
if (parameter.IsOptional) {
AddAttribute ("optional", "true");
}
}
- class AttributeData : BaseData
+ class AttributeData
{
- IList<ICustomAttributeProvider> providers;
-
- AttributeData (XmlWriter writer, IList<ICustomAttributeProvider> providers)
- : base (writer)
- {
- this.providers = providers;
- }
-
- public override void DoOutput ()
+ public static void DoOutput (XmlWriter writer, IList<ICustomAttributeProvider> providers)
{
if (writer == null)
throw new InvalidOperationException ("Document not set");
string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
writer.WriteStartElement ("attribute");
- AddAttribute ("name", attName);
-
- var attribute_mapping = CreateAttributeMapping (att).Where ((kvp) => kvp.Key != "TypeId");
-
- if (attribute_mapping.Any ()) {
- writer.WriteStartElement ("properties");
- foreach (var kvp in attribute_mapping) {
- string name = kvp.Key;
- object o = kvp.Value;
-
- writer.WriteStartElement ("property");
- AddAttribute ("name", name);
-
- if (o == null) {
- AddAttribute ("value", "null");
- } else {
- string value = o.ToString ();
- if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
- value = value.ToUpper ();
- AddAttribute ("value", value);
+ writer.WriteAttributeString ("name", attName);
+
+ var attribute_mapping = CreateAttributeMapping (att);
+
+ if (attribute_mapping != null) {
+ var mapping = attribute_mapping.Where ((attr) => attr.Key != "TypeId");
+ if (mapping.Any ()) {
+ writer.WriteStartElement ("properties");
+ foreach (var kvp in mapping) {
+ string name = kvp.Key;
+ object o = kvp.Value;
+
+ writer.WriteStartElement ("property");
+ writer.WriteAttributeString ("name", name);
+
+ if (o == null) {
+ writer.WriteAttributeString ("value", "null");
+ } else {
+ string value = o.ToString ();
+ if (attName.EndsWith ("GuidAttribute", StringComparison.Ordinal))
+ value = value.ToUpper ();
+ writer.WriteAttributeString ("value", value);
+ }
+
+ writer.WriteEndElement (); // property
}
-
- writer.WriteEndElement (); // property
+ writer.WriteEndElement (); // properties
}
- writer.WriteEndElement (); // properties
}
writer.WriteEndElement (); // attribute
}
static Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
{
- var mapping = new Dictionary<string, object> ();
+ Dictionary<string, object> mapping = null;
- PopulateMapping (mapping, attribute);
+ PopulateMapping (ref mapping, attribute);
var constructor = attribute.Constructor.Resolve ();
if (constructor == null || !constructor.HasParameters)
return mapping;
- PopulateMapping (mapping, constructor, attribute);
+ PopulateMapping (ref mapping, constructor, attribute);
return mapping;
}
- static void PopulateMapping (Dictionary<string, object> mapping, CustomAttribute attribute)
+ static void PopulateMapping (ref Dictionary<string, object> mapping, CustomAttribute attribute)
{
if (!attribute.HasProperties)
return;
if (arg.Value is CustomAttributeArgument)
arg = (CustomAttributeArgument) arg.Value;
+ if (mapping == null)
+ mapping = new Dictionary<string, object> (StringComparer.Ordinal);
mapping.Add (name, GetArgumentValue (arg.Type, arg.Value));
}
}
static Dictionary<FieldReference, int> CreateArgumentFieldMapping (MethodDefinition constructor)
{
- Dictionary<FieldReference, int> field_mapping = new Dictionary<FieldReference, int> ();
+ Dictionary<FieldReference, int> field_mapping = null;
int? argument = null;
if (!argument.HasValue)
break;
+ if (field_mapping == null)
+ field_mapping = new Dictionary<FieldReference, int> ();
+
if (!field_mapping.ContainsKey (field))
field_mapping.Add (field, (int) argument - 1);
static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
{
- Dictionary<PropertyDefinition, FieldReference> property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
+ Dictionary<PropertyDefinition, FieldReference> property_mapping = null;
foreach (PropertyDefinition property in type.Properties) {
if (property.GetMethod == null)
if (field.DeclaringType.FullName != type.FullName)
continue;
+ if (property_mapping == null)
+ property_mapping = new Dictionary<PropertyDefinition, FieldReference> ();
property_mapping.Add (property, field);
break;
}
return property_mapping;
}
- static void PopulateMapping (Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
+ static void PopulateMapping (ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
{
if (!constructor.HasBody)
return;
new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (int) ca[2].Value, (int) ca[3].Value, (int) ca[4].Value) :
new DecimalConstantAttribute ((byte) ca[0].Value, (byte) ca[1].Value, (uint) ca[2].Value, (uint) ca[3].Value, (uint) ca[4].Value);
+ if (mapping == null)
+ mapping = new Dictionary<string, object> (StringComparer.Ordinal);
mapping.Add ("Value", dca.Value);
return;
case "System.ComponentModel.BindableAttribute":
if (ca.Count != 1)
break;
+ if (mapping == null)
+ mapping = new Dictionary<string, object> (StringComparer.Ordinal);
+
if (constructor.Parameters[0].ParameterType == constructor.Module.TypeSystem.Boolean) {
mapping.Add ("Bindable", ca[0].Value);
+ } else if (constructor.Parameters[0].ParameterType.FullName == "System.ComponentModel.BindableSupport") {
+ if ((int)ca[0].Value == 0)
+ mapping.Add ("Bindable", false);
+ else if ((int)ca[0].Value == 1)
+ mapping.Add ("Bindable", true);
+ else
+ throw new NotImplementedException ();
} else {
throw new NotImplementedException ();
}
}
var field_mapping = CreateArgumentFieldMapping (constructor);
- var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
-
- foreach (var pair in property_mapping) {
- int argument;
- if (!field_mapping.TryGetValue (pair.Value, out argument))
- continue;
-
- var ca_arg = ca [argument];
- if (ca_arg.Value is CustomAttributeArgument)
- ca_arg = (CustomAttributeArgument) ca_arg.Value;
-
- mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
+ if (field_mapping != null) {
+ var property_mapping = CreatePropertyFieldMapping ((TypeDefinition) constructor.DeclaringType);
+
+ if (property_mapping != null) {
+ foreach (var pair in property_mapping) {
+ int argument;
+ if (!field_mapping.TryGetValue (pair.Value, out argument))
+ continue;
+
+ var ca_arg = ca [argument];
+ if (ca_arg.Value is CustomAttributeArgument)
+ ca_arg = (CustomAttributeArgument)ca_arg.Value;
+
+ if (mapping == null)
+ mapping = new Dictionary<string, object> (StringComparer.Ordinal);
+ mapping.Add (pair.Key.Name, GetArgumentValue (ca_arg.Type, ca_arg.Value));
+ }
+ }
}
}
public static void OutputAttributes (XmlWriter writer, params ICustomAttributeProvider[] providers)
{
- AttributeData ad = new AttributeData (writer, providers);
- ad.DoOutput ();
+ AttributeData.DoOutput (writer, providers);
}
}
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;
+ string modifier = string.Empty;
+ if (info.ParameterType.IsByReference) {
+ if ((info.Attributes & ParameterAttributes.In) != 0)
+ modifier = "in";
+ else if ((info.Attributes & ParameterAttributes.Out) != 0)
+ modifier = "out";
+ }
if (modifier.Length > 0) {
signature.Append (modifier);
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);
}