Xamarin Public Jenkins (auto-signing) 95fdb59ea6 Imported Upstream version 6.6.0.89
Former-commit-id: b39a328747c2f3414dc52e009fb6f0aa80ca2492
2019-09-24 08:53:40 +00:00

1832 lines
50 KiB
C#

//
// mono-api-info.cs - Dumps public assembly information to an xml file.
//
// Authors:
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
//
// Copyright (C) 2003-2008 Novell, Inc (http://www.novell.com)
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text;
using System.Xml;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.IO;
namespace Mono.ApiTools {
#if !EXCLUDE_DRIVER
class Driver
{
public static int Main (string [] args)
{
bool showHelp = false;
string output = null;
List<string> asms = null;
ApiInfoConfig config = new ApiInfoConfig ();
var options = new Mono.Options.OptionSet {
{ "abi",
"Generate ABI, not API; contains only classes with instance fields which are not [NonSerialized].",
v => config.AbiMode = v != null },
{ "f|follow-forwarders",
"Follow type forwarders.",
v => config.FollowForwarders = v != null },
{ "ignore-inherited-interfaces",
"Ignore interfaces on the base type.",
v => config.IgnoreInheritedInterfaces = v != null },
{ "ignore-resolution-errors",
"Ignore any assemblies that cannot be found.",
v => config.IgnoreResolutionErrors = v != null },
{ "d|L|lib|search-directory=",
"Check for assembly references in {DIRECTORY}.",
v => config.SearchDirectories.Add (v) },
{ "r=",
"Read and register the file {ASSEMBLY}, and add the directory containing ASSEMBLY to the search path.",
v => config.ResolveFiles.Add (v) },
{ "o|out|output=",
"The output file. If not specified the output will be written to stdout.",
v => output = v },
{ "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 => config.FullApiSet = v != null },
};
try {
asms = options.Parse (args);
} catch (Mono.Options.OptionException e) {
Console.WriteLine ("Option error: {0}", e.Message);
asms = null;
}
if (showHelp || asms == null || asms.Count == 0) {
Console.WriteLine ("usage: mono-api-info [OPTIONS+] ASSEMBLY+");
Console.WriteLine ();
Console.WriteLine ("Expose IL structure of CLR assemblies as XML.");
Console.WriteLine ();
Console.WriteLine ("Available Options:");
Console.WriteLine ();
options.WriteOptionDescriptions (Console.Out);
Console.WriteLine ();
return showHelp ? 0 : 1;
}
TextWriter outputStream = null;
try {
if (!string.IsNullOrEmpty (output))
outputStream = new StreamWriter (output);
ApiInfo.Generate (asms, null, outputStream ?? Console.Out, config);
} catch (Exception e) {
Console.Error.WriteLine (e);
return 1;
} finally {
outputStream?.Dispose ();
}
return 0;
}
}
#endif
class State
{
public bool AbiMode { get; set; } = false;
public bool FollowForwarders { get; set; } = false;
public bool FullApiSet { get; set; } = false;
public bool IgnoreResolutionErrors { get; set; } = false;
public bool IgnoreInheritedInterfaces { get; set; } = false;
public List<string> SearchDirectories { get; } = new List<string> ();
public List<string> ResolveFiles { get; } = new List<string> ();
public List<Stream> ResolveStreams { get; } = new List<Stream> ();
public TypeHelper TypeHelper { get; private set; }
public void ResolveTypes ()
{
TypeHelper = new TypeHelper (IgnoreResolutionErrors, IgnoreInheritedInterfaces);
if (SearchDirectories != null) {
foreach (var v in SearchDirectories)
TypeHelper.Resolver.AddSearchDirectory (v);
}
if (ResolveFiles != null) {
foreach (var v in ResolveFiles)
TypeHelper.Resolver.ResolveFile (v);
}
if (ResolveStreams != null) {
foreach (var v in ResolveStreams)
TypeHelper.Resolver.ResolveStream (v);
}
}
}
public class ApiInfoConfig
{
public bool AbiMode { get; set; } = false;
public bool FollowForwarders { get; set; } = false;
public bool FullApiSet { get; set; } = false;
public bool IgnoreResolutionErrors { get; set; } = false;
public bool IgnoreInheritedInterfaces { get; set; } = false;
public List<string> SearchDirectories { get; set; } = new List<string> ();
public List<string> ResolveFiles { get; set; } = new List<string> ();
public List<Stream> ResolveStreams { get; set; } = new List<Stream> ();
}
public static class ApiInfo
{
public static void Generate (string assemblyPath, TextWriter outStream, ApiInfoConfig config = null)
{
if (assemblyPath == null)
throw new ArgumentNullException (nameof (assemblyPath));
Generate (new [] { assemblyPath }, null, outStream, config);
}
public static void Generate (Stream assemblyStream, TextWriter outStream, ApiInfoConfig config = null)
{
if (assemblyStream == null)
throw new ArgumentNullException (nameof (assemblyStream));
Generate (null, new [] { assemblyStream }, outStream, config);
}
public static void Generate (IEnumerable<string> assemblyPaths, TextWriter outStream, ApiInfoConfig config = null)
{
Generate (assemblyPaths, null, outStream, config);
}
public static void Generate (IEnumerable<Stream> assemblyStreams, TextWriter outStream, ApiInfoConfig config = null)
{
Generate (null, assemblyStreams, outStream, config);
}
public static void Generate (IEnumerable<string> assemblyPaths, IEnumerable<Stream> assemblyStreams, TextWriter outStream, ApiInfoConfig config = null)
{
if (outStream == null)
throw new ArgumentNullException (nameof (outStream));
if (config == null)
config = new ApiInfoConfig ();
var state = new State {
AbiMode = config.AbiMode,
FollowForwarders = config.FollowForwarders,
FullApiSet = config.FullApiSet,
IgnoreResolutionErrors = config.IgnoreResolutionErrors,
IgnoreInheritedInterfaces = config.IgnoreInheritedInterfaces,
};
state.SearchDirectories.AddRange (config.SearchDirectories);
state.ResolveFiles.AddRange (config.ResolveFiles);
state.ResolveStreams.AddRange (config.ResolveStreams);
Generate (assemblyPaths, assemblyStreams, outStream, state);
}
internal static void Generate (IEnumerable<string> assemblyFiles, IEnumerable<Stream> assemblyStreams, TextWriter outStream, State state = null)
{
if (outStream == null)
throw new ArgumentNullException (nameof (outStream));
if (state == null)
state = new State ();
state.ResolveTypes ();
string windir = Environment.GetFolderPath (Environment.SpecialFolder.Windows);
string pf = Environment.GetFolderPath (Environment.SpecialFolder.ProgramFiles);
state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"assembly\GAC\MSDATASRC\7.0.3300.0__b03f5f7f11d50a3a"));
var acoll = new AssemblyCollection (state);
if (assemblyFiles != null) {
foreach (string arg in assemblyFiles) {
acoll.Add (arg);
if (arg.Contains ("v3.0")) {
state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
} else if (arg.Contains ("v3.5")) {
state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v2.0.50727"));
state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v3.0\Windows Communication Foundation"));
} else if (arg.Contains ("v4.0")) {
if (arg.Contains ("Silverlight")) {
state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (pf, @"Microsoft Silverlight\4.0.51204.0"));
} else {
state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319"));
state.TypeHelper.Resolver.AddSearchDirectory (Path.Combine (windir, @"Microsoft.NET\Framework\v4.0.30319\WPF"));
}
} else {
state.TypeHelper.Resolver.AddSearchDirectory (Path.GetDirectoryName (arg));
}
}
}
if (assemblyStreams != null) {
foreach (var arg in assemblyStreams) {
acoll.Add (arg);
}
}
var settings = new XmlWriterSettings {
Indent = true,
};
using (var textWriter = XmlWriter.Create (outStream, settings)) {
var writer = new WellFormedXmlWriter (textWriter);
writer.WriteStartDocument ();
acoll.Writer = writer;
acoll.DoOutput ();
writer.WriteEndDocument ();
writer.Flush ();
}
}
}
class Utils {
static char[] CharsToCleanup = new char[] { '<', '>', '/' };
public static string CleanupTypeName (TypeReference type)
{
return CleanupTypeName (type.FullName);
}
public static string CleanupTypeName (string t)
{
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 ();
}
}
class AssemblyCollection
{
XmlWriter writer;
List<AssemblyDefinition> assemblies = new List<AssemblyDefinition> ();
State state;
public AssemblyCollection (State state)
{
this.state = state;
}
public bool Add (string name)
{
AssemblyDefinition ass = LoadAssembly (name);
assemblies.Add (ass);
return true;
}
public bool Add (Stream stream)
{
AssemblyDefinition ass = LoadAssembly (stream);
assemblies.Add (ass);
return true;
}
public void DoOutput ()
{
if (writer == null)
throw new InvalidOperationException ("Document not set");
writer.WriteStartElement ("assemblies");
foreach (AssemblyDefinition a in assemblies) {
AssemblyData data = new AssemblyData (writer, a, state);
data.DoOutput ();
}
writer.WriteEndElement ();
}
public XmlWriter Writer {
set { writer = value; }
}
AssemblyDefinition LoadAssembly (string assembly)
{
if (File.Exists (assembly))
return state.TypeHelper.Resolver.ResolveFile (assembly);
return state.TypeHelper.Resolver.Resolve (AssemblyNameReference.Parse (assembly), new ReaderParameters ());
}
AssemblyDefinition LoadAssembly (Stream assembly)
{
return state.TypeHelper.Resolver.ResolveStream (assembly);
}
}
abstract class BaseData
{
protected XmlWriter writer;
protected State state;
protected BaseData (XmlWriter writer, State state)
{
this.writer = writer;
this.state = state;
}
public abstract void DoOutput ();
protected void AddAttribute (string name, string value)
{
writer.WriteAttributeString (name, value);
}
}
class TypeForwardedToData : BaseData
{
AssemblyDefinition ass;
public TypeForwardedToData (XmlWriter writer, AssemblyDefinition ass, State state)
: base (writer, state)
{
this.ass = ass;
}
public override void DoOutput ()
{
foreach (ExportedType type in ass.MainModule.ExportedTypes) {
if (((uint)type.Attributes & 0x200000u) == 0)
continue;
writer.WriteStartElement ("attribute");
AddAttribute ("name", typeof (TypeForwardedToAttribute).FullName);
writer.WriteStartElement ("properties");
writer.WriteStartElement ("property");
AddAttribute ("name", "Destination");
AddAttribute ("value", Utils.CleanupTypeName (type.FullName));
writer.WriteEndElement (); // properties
writer.WriteEndElement (); // properties
writer.WriteEndElement (); // attribute
}
}
public static void OutputForwarders (XmlWriter writer, AssemblyDefinition ass, State state)
{
TypeForwardedToData tftd = new TypeForwardedToData (writer, ass, state);
tftd.DoOutput ();
}
}
class AssemblyData : BaseData
{
AssemblyDefinition ass;
public AssemblyData (XmlWriter writer, AssemblyDefinition ass, State state)
: base (writer, state)
{
this.ass = ass;
}
public override void DoOutput ()
{
if (writer == null)
throw new InvalidOperationException ("Document not set");
writer.WriteStartElement ("assembly");
AssemblyNameDefinition aname = ass.Name;
AddAttribute ("name", aname.Name);
AddAttribute ("version", aname.Version.ToString ());
AttributeData.OutputAttributes (writer, state, ass);
var types = new List<TypeDefinition> ();
if (ass.MainModule.Types != null) {
types.AddRange (ass.MainModule.Types);
}
if (state.FollowForwarders && ass.MainModule.ExportedTypes != null) {
foreach (var t in ass.MainModule.ExportedTypes) {
var forwarded = t.Resolve ();
if (forwarded == null) {
throw new Exception ("Could not resolve forwarded type " + t.FullName + " in " + ass.Name);
}
types.Add (forwarded);
}
}
if (types.Count == 0) {
writer.WriteEndElement (); // assembly
return;
}
types.Sort (TypeReferenceComparer.Default);
writer.WriteStartElement ("namespaces");
string current_namespace = "$%&$&";
bool in_namespace = false;
foreach (TypeDefinition t in types) {
if (string.IsNullOrEmpty (t.Namespace))
continue;
if (!state.AbiMode && ((t.Attributes & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
continue;
if (t.DeclaringType != null)
continue; // enforce !nested
if (t.Namespace != current_namespace) {
current_namespace = t.Namespace;
if (in_namespace) {
writer.WriteEndElement (); // classes
writer.WriteEndElement (); // namespace
} else {
in_namespace = true;
}
writer.WriteStartElement ("namespace");
AddAttribute ("name", current_namespace);
writer.WriteStartElement ("classes");
}
TypeData bd = new TypeData (writer, t, state);
bd.DoOutput ();
}
if (in_namespace) {
writer.WriteEndElement (); // classes
writer.WriteEndElement (); // namespace
}
writer.WriteEndElement (); // namespaces
writer.WriteEndElement (); // assembly
}
}
abstract class MemberData : BaseData
{
MemberReference [] members;
public MemberData (XmlWriter writer, MemberReference [] members, State state)
: base (writer, state)
{
this.members = members;
}
protected virtual ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
{
return null;
}
public override void DoOutput ()
{
writer.WriteStartElement (ParentTag);
foreach (MemberReference member in members) {
writer.WriteStartElement (Tag);
AddAttribute ("name", GetName (member));
if (!NoMemberAttributes)
AddAttribute ("attrib", GetMemberAttributes (member));
AddExtraAttributes (member);
AttributeData.OutputAttributes (writer, state, (ICustomAttributeProvider) member, GetAdditionalCustomAttributeProvider (member));
AddExtraData (member);
writer.WriteEndElement (); // Tag
}
writer.WriteEndElement (); // ParentTag
}
protected virtual void AddExtraData (MemberReference memberDefenition)
{
}
protected virtual void AddExtraAttributes (MemberReference memberDefinition)
{
}
protected virtual string GetName (MemberReference memberDefenition)
{
return "NoNAME";
}
protected virtual string GetMemberAttributes (MemberReference memberDefenition)
{
return null;
}
public virtual bool NoMemberAttributes {
get { return false; }
set {}
}
public virtual string ParentTag {
get { return "NoPARENTTAG"; }
}
public virtual string Tag {
get { return "NoTAG"; }
}
public static void OutputGenericParameters (XmlWriter writer, IGenericParameterProvider provider, State state)
{
if (provider.GenericParameters.Count == 0)
return;
var gparameters = provider.GenericParameters;
writer.WriteStartElement ("generic-parameters");
foreach (GenericParameter gp in gparameters) {
writer.WriteStartElement ("generic-parameter");
writer.WriteAttributeString ("name", gp.Name);
writer.WriteAttributeString ("attributes", ((int) gp.Attributes).ToString ());
AttributeData.OutputAttributes (writer, state, gp);
var constraints = gp.Constraints;
if (constraints.Count == 0) {
writer.WriteEndElement (); // generic-parameter
continue;
}
writer.WriteStartElement ("generic-parameter-constraints");
foreach (GenericParameterConstraint constraint in constraints) {
writer.WriteStartElement ("generic-parameter-constraint");
writer.WriteAttributeString ("name", Utils.CleanupTypeName (constraint.ConstraintType));
writer.WriteEndElement (); // generic-parameter-constraint
}
writer.WriteEndElement (); // generic-parameter-constraints
writer.WriteEndElement (); // generic-parameter
}
writer.WriteEndElement (); // generic-parameters
}
}
class TypeData : MemberData
{
TypeDefinition type;
public TypeData (XmlWriter writer, TypeDefinition type, State state)
: base (writer, null, state)
{
this.type = type;
}
public override void DoOutput ()
{
if (writer == null)
throw new InvalidOperationException ("Document not set");
writer.WriteStartElement ("class");
AddAttribute ("name", type.Name);
string classType = GetClassType (type);
AddAttribute ("type", classType);
if (type.BaseType != null)
AddAttribute ("base", Utils.CleanupTypeName (type.BaseType));
if (type.IsSealed)
AddAttribute ("sealed", "true");
if (type.IsAbstract)
AddAttribute ("abstract", "true");
if ( (type.Attributes & TypeAttributes.Serializable) != 0 || type.IsEnum)
AddAttribute ("serializable", "true");
string charSet = GetCharSet (type);
AddAttribute ("charset", charSet);
string layout = GetLayout (type);
if (layout != null)
AddAttribute ("layout", layout);
if (type.PackingSize >= 0) {
AddAttribute ("pack", type.PackingSize.ToString ());
}
if (type.ClassSize >= 0) {
AddAttribute ("size", type.ClassSize.ToString ());
}
if (type.IsEnum) {
var value_type = GetEnumValueField (type);
if (value_type == null)
throw new NotSupportedException ();
AddAttribute ("enumtype", Utils.CleanupTypeName (value_type.FieldType));
}
AttributeData.OutputAttributes (writer, state, type);
var ifaces = state.TypeHelper.GetInterfaces (type).
Where ((iface) => state.TypeHelper.IsPublic (iface)). // we're only interested in public interfaces
OrderBy (s => s.FullName, StringComparer.Ordinal);
if (ifaces.Any ()) {
writer.WriteStartElement ("interfaces");
foreach (TypeReference iface in ifaces) {
writer.WriteStartElement ("interface");
AddAttribute ("name", Utils.CleanupTypeName (iface));
writer.WriteEndElement (); // interface
}
writer.WriteEndElement (); // interfaces
}
MemberData.OutputGenericParameters (writer, type, state);
ArrayList members = new ArrayList ();
FieldDefinition [] fields = GetFields (type);
if (fields.Length > 0) {
Array.Sort (fields, MemberReferenceComparer.Default);
FieldData fd = new FieldData (writer, fields, state);
members.Add (fd);
}
if (!state.AbiMode) {
MethodDefinition [] ctors = GetConstructors (type);
if (ctors.Length > 0) {
Array.Sort (ctors, MethodDefinitionComparer.Default);
members.Add (new ConstructorData (writer, ctors, state));
}
PropertyDefinition[] properties = GetProperties (type, state.FullApiSet);
if (properties.Length > 0) {
Array.Sort (properties, PropertyDefinitionComparer.Default);
members.Add (new PropertyData (writer, properties, state));
}
EventDefinition [] events = GetEvents (type);
if (events.Length > 0) {
Array.Sort (events, MemberReferenceComparer.Default);
members.Add (new EventData (writer, events, state));
}
MethodDefinition [] methods = GetMethods (type, state.FullApiSet);
if (methods.Length > 0) {
Array.Sort (methods, MethodDefinitionComparer.Default);
members.Add (new MethodData (writer, methods, state));
}
}
foreach (MemberData md in members)
md.DoOutput ();
var nested = type.NestedTypes;
//remove non public(familiy) and nested in second degree
for (int i = nested.Count - 1; i >= 0; i--) {
TypeDefinition t = nested [i];
if ((t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic ||
(t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily ||
(t.Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem) {
// public
if (t.DeclaringType == type)
continue; // not nested of nested
}
nested.RemoveAt (i);
}
if (nested.Count > 0) {
var nestedArray = nested.ToArray ();
Array.Sort (nestedArray, TypeReferenceComparer.Default);
writer.WriteStartElement ("classes");
foreach (TypeDefinition t in nestedArray) {
TypeData td = new TypeData (writer, t, state);
td.DoOutput ();
}
writer.WriteEndElement (); // classes
}
writer.WriteEndElement (); // class
}
static FieldReference GetEnumValueField (TypeDefinition type)
{
foreach (FieldDefinition field in type.Fields)
if (field.IsSpecialName && field.Name == "value__")
return field;
return null;
}
protected override string GetMemberAttributes (MemberReference member)
{
if (member != type)
throw new InvalidOperationException ("odd");
return ((int) type.Attributes).ToString (CultureInfo.InvariantCulture);
}
public static bool MustDocumentMethod (MethodDefinition method) {
// All other methods
MethodAttributes maskedAccess = method.Attributes & MethodAttributes.MemberAccessMask;
return maskedAccess == MethodAttributes.Public
|| maskedAccess == MethodAttributes.Family
|| maskedAccess == MethodAttributes.FamORAssem;
}
string GetClassType (TypeDefinition t)
{
if (t.IsEnum)
return "enum";
if (t.IsValueType)
return "struct";
if (t.IsInterface)
return "interface";
if (state.TypeHelper.IsDelegate(t))
return "delegate";
if (t.IsPointer)
return "pointer";
return "class";
}
static string GetCharSet (TypeDefinition type)
{
TypeAttributes maskedStringFormat = type.Attributes & TypeAttributes.StringFormatMask;
if (maskedStringFormat == TypeAttributes.AnsiClass)
return CharSet.Ansi.ToString ();
if (maskedStringFormat == TypeAttributes.AutoClass)
return CharSet.Auto.ToString ();
if (maskedStringFormat == TypeAttributes.UnicodeClass)
return CharSet.Unicode.ToString ();
return CharSet.None.ToString ();
}
static string GetLayout (TypeDefinition type)
{
TypeAttributes maskedLayout = type.Attributes & TypeAttributes.LayoutMask;
if (maskedLayout == TypeAttributes.AutoLayout)
return LayoutKind.Auto.ToString ();
if (maskedLayout == TypeAttributes.ExplicitLayout)
return LayoutKind.Explicit.ToString ();
if (maskedLayout == TypeAttributes.SequentialLayout)
return LayoutKind.Sequential.ToString ();
return null;
}
FieldDefinition [] GetFields (TypeDefinition type) {
ArrayList list = new ArrayList ();
var fields = type.Fields;
foreach (FieldDefinition field in fields) {
if (field.IsSpecialName)
continue;
if (state.AbiMode && field.IsStatic)
continue;
// we're only interested in public or protected members
FieldAttributes maskedVisibility = (field.Attributes & FieldAttributes.FieldAccessMask);
if (state.AbiMode && !field.IsNotSerialized) {
list.Add (field);
} else {
if (maskedVisibility == FieldAttributes.Public
|| maskedVisibility == FieldAttributes.Family
|| maskedVisibility == FieldAttributes.FamORAssem) {
list.Add (field);
}
}
}
return (FieldDefinition []) list.ToArray (typeof (FieldDefinition));
}
internal 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);
// if neither the getter or setter should be documented, then
// skip the property
if (hasGetter || hasSetter) {
if (t != type && list.Any (l => l.Name == property.Name))
continue;
list.Add (property);
}
}
if (!fullAPI)
break;
if (t.IsInterface || t.IsEnum)
break;
if (t.BaseType == null || t.BaseType.FullName == "System.Object")
t = null;
else
t = state.TypeHelper.GetBaseType (t);
} while (t != null);
return list.ToArray ();
}
private MethodDefinition[] GetMethods (TypeDefinition type, bool fullAPI)
{
var list = new List<MethodDefinition> ();
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;
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;
}
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);
}
if (!fullAPI)
break;
if (t.IsInterface || t.IsEnum)
break;
if (t.BaseType == null || t.BaseType.FullName == "System.Object")
t = null;
else
t = state.TypeHelper.GetBaseType (t);
} 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;
}
public int GetHashCode (ParameterDefinition obj)
{
return obj.ParameterType.Name.GetHashCode ();
}
}
static bool IsFinalizer (MethodDefinition method)
{
if (method.Name != "Finalize")
return false;
if (!method.IsVirtual)
return false;
if (method.Parameters.Count != 0)
return false;
return true;
}
private MethodDefinition [] GetConstructors (TypeDefinition type)
{
ArrayList list = new ArrayList ();
var ctors = type.Methods.Where (m => m.IsConstructor);//type.GetConstructors (flags);
foreach (MethodDefinition constructor in ctors) {
// we're only interested in public or protected members
if (!MustDocumentMethod(constructor))
continue;
list.Add (constructor);
}
return (MethodDefinition []) list.ToArray (typeof (MethodDefinition));
}
private EventDefinition[] GetEvents (TypeDefinition type)
{
ArrayList list = new ArrayList ();
var events = type.Events;//type.GetEvents (flags);
foreach (EventDefinition eventDef in events) {
MethodDefinition addMethod = eventDef.AddMethod;//eventInfo.GetAddMethod (true);
if (addMethod == null || !MustDocumentMethod (addMethod))
continue;
list.Add (eventDef);
}
return (EventDefinition []) list.ToArray (typeof (EventDefinition));
}
}
class FieldData : MemberData
{
public FieldData (XmlWriter writer, FieldDefinition [] members, State state)
: base (writer, members, state)
{
}
protected override string GetName (MemberReference memberDefenition)
{
FieldDefinition field = (FieldDefinition) memberDefenition;
return field.Name;
}
protected override string GetMemberAttributes (MemberReference memberDefenition)
{
FieldDefinition field = (FieldDefinition) memberDefenition;
return ((int) field.Attributes).ToString (CultureInfo.InvariantCulture);
}
protected override void AddExtraAttributes (MemberReference memberDefinition)
{
base.AddExtraAttributes (memberDefinition);
FieldDefinition field = (FieldDefinition) memberDefinition;
AddAttribute ("fieldtype", Utils.CleanupTypeName (field.FieldType));
if (field.IsLiteral) {
object value = field.Constant;//object value = field.GetValue (null);
string stringValue = null;
//if (value is Enum) {
// // FIXME: when Mono bug #60090 has been
// // fixed, we should just be able to use
// // Convert.ToString
// stringValue = ((Enum) value).ToString ("D", CultureInfo.InvariantCulture);
//}
//else {
stringValue = Convert.ToString (value, CultureInfo.InvariantCulture);
//}
if (stringValue != null)
AddAttribute ("value", stringValue);
}
}
public override string ParentTag {
get { return "fields"; }
}
public override string Tag {
get { return "field"; }
}
}
class PropertyData : MemberData
{
public PropertyData (XmlWriter writer, PropertyDefinition [] members, State state)
: base (writer, members, state)
{
}
protected override string GetName (MemberReference memberDefenition)
{
PropertyDefinition prop = (PropertyDefinition) memberDefenition;
return prop.Name;
}
MethodDefinition [] GetMethods (PropertyDefinition prop, out bool haveParameters)
{
MethodDefinition _get = prop.GetMethod;
MethodDefinition _set = prop.SetMethod;
bool haveGet = (_get != null && TypeData.MustDocumentMethod(_get));
bool haveSet = (_set != null && TypeData.MustDocumentMethod(_set));
haveParameters = haveGet || (haveSet && _set.Parameters.Count > 1);
MethodDefinition [] methods;
if (haveGet && haveSet) {
methods = new MethodDefinition [] { _get, _set };
} else if (haveGet) {
methods = new MethodDefinition [] { _get };
} else if (haveSet) {
methods = new MethodDefinition [] { _set };
} else {
//odd
return null;
}
return methods;
}
protected override void AddExtraAttributes (MemberReference memberDefinition)
{
base.AddExtraAttributes (memberDefinition);
PropertyDefinition prop = (PropertyDefinition) memberDefinition;
AddAttribute ("ptype", Utils.CleanupTypeName (prop.PropertyType));
bool haveParameters;
MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefinition, out haveParameters);
if (methods != null && haveParameters) {
string parms = Parameters.GetSignature (methods [0].Parameters);
if (!string.IsNullOrEmpty (parms))
AddAttribute ("params", parms);
}
}
protected override void AddExtraData (MemberReference memberDefenition)
{
base.AddExtraData (memberDefenition);
bool haveParameters;
MethodDefinition [] methods = GetMethods ((PropertyDefinition) memberDefenition, out haveParameters);
if (methods == null)
return;
MethodData data = new MethodData (writer, methods, state);
//data.NoMemberAttributes = true;
data.DoOutput ();
}
protected override string GetMemberAttributes (MemberReference memberDefenition)
{
PropertyDefinition prop = (PropertyDefinition) memberDefenition;
return ((int) prop.Attributes).ToString (CultureInfo.InvariantCulture);
}
public override string ParentTag {
get { return "properties"; }
}
public override string Tag {
get { return "property"; }
}
}
class EventData : MemberData
{
public EventData (XmlWriter writer, EventDefinition [] members, State state)
: base (writer, members, state)
{
}
protected override string GetName (MemberReference memberDefenition)
{
EventDefinition evt = (EventDefinition) memberDefenition;
return evt.Name;
}
protected override string GetMemberAttributes (MemberReference memberDefenition)
{
EventDefinition evt = (EventDefinition) memberDefenition;
return ((int) evt.Attributes).ToString (CultureInfo.InvariantCulture);
}
protected override void AddExtraAttributes (MemberReference memberDefinition)
{
base.AddExtraAttributes (memberDefinition);
EventDefinition evt = (EventDefinition) memberDefinition;
AddAttribute ("eventtype", Utils.CleanupTypeName (evt.EventType));
}
public override string ParentTag {
get { return "events"; }
}
public override string Tag {
get { return "event"; }
}
}
class MethodData : MemberData
{
bool noAtts;
public MethodData (XmlWriter writer, MethodDefinition [] members, State state)
: base (writer, members, state)
{
}
protected override string GetName (MemberReference memberDefenition)
{
MethodDefinition method = (MethodDefinition) memberDefenition;
string name = method.Name;
string parms = Parameters.GetSignature (method.Parameters);
return string.Format ("{0}({1})", name, parms);
}
protected override string GetMemberAttributes (MemberReference memberDefenition)
{
MethodDefinition method = (MethodDefinition) memberDefenition;
return ((int)( method.Attributes)).ToString (CultureInfo.InvariantCulture);
}
protected override ICustomAttributeProvider GetAdditionalCustomAttributeProvider (MemberReference member)
{
var mbase = (MethodDefinition) member;
return mbase.MethodReturnType;
}
protected override void AddExtraAttributes (MemberReference memberDefinition)
{
base.AddExtraAttributes (memberDefinition);
if (!(memberDefinition is MethodDefinition))
return;
MethodDefinition mbase = (MethodDefinition) memberDefinition;
if (mbase.IsAbstract)
AddAttribute ("abstract", "true");
if (mbase.IsVirtual)
AddAttribute ("virtual", "true");
if (mbase.IsFinal && mbase.IsVirtual && mbase.IsReuseSlot)
AddAttribute ("sealed", "true");
if (mbase.IsStatic)
AddAttribute ("static", "true");
var baseMethod = state.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 (mbase.MethodReturnType.HasCustomAttributes)
// AttributeData.OutputAttributes (writer, mbase.MethodReturnType);
}
protected override void AddExtraData (MemberReference memberDefenition)
{
base.AddExtraData (memberDefenition);
if (!(memberDefenition is MethodDefinition))
return;
MethodDefinition mbase = (MethodDefinition)memberDefenition;
ParameterData parms = new ParameterData (writer, mbase.Parameters, state) {
HasExtensionParameter = mbase.CustomAttributes.Any (l => l.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
};
parms.DoOutput ();
MemberData.OutputGenericParameters (writer, mbase, state);
}
public override bool NoMemberAttributes {
get { return noAtts; }
set { noAtts = value; }
}
public override string ParentTag {
get { return "methods"; }
}
public override string Tag {
get { return "method"; }
}
}
class ConstructorData : MethodData
{
public ConstructorData (XmlWriter writer, MethodDefinition [] members, State state)
: base (writer, members, state)
{
}
public override string ParentTag {
get { return "constructors"; }
}
public override string Tag {
get { return "constructor"; }
}
}
class ParameterData : BaseData
{
private IList<ParameterDefinition> parameters;
public ParameterData (XmlWriter writer, IList<ParameterDefinition> parameters, State state)
: base (writer, state)
{
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 ("name", parameter.Name);
AddAttribute ("position", parameter.Method.Parameters.IndexOf(parameter).ToString(CultureInfo.InvariantCulture));
AddAttribute ("attrib", ((int) parameter.Attributes).ToString());
string direction = first && HasExtensionParameter ? "this" : "in";
first = false;
var pt = parameter.ParameterType;
var brt = pt as ByReferenceType;
if (brt != null) {
direction = parameter.IsOut ? "out" : "ref";
pt = brt.ElementType;
}
AddAttribute ("type", Utils.CleanupTypeName (pt));
if (parameter.IsOptional) {
AddAttribute ("optional", "true");
if (parameter.HasConstant)
AddAttribute ("defaultValue", parameter.Constant == null ? "NULL" : parameter.Constant.ToString ());
}
if (direction != "in")
AddAttribute ("direction", direction);
AttributeData.OutputAttributes (writer, state, parameter);
writer.WriteEndElement (); // parameter
}
writer.WriteEndElement (); // parameters
}
}
class AttributeData
{
State state;
public AttributeData (State state)
{
this.state = state;
}
public void DoOutput (XmlWriter writer, IList<ICustomAttributeProvider> providers)
{
if (writer == null)
throw new InvalidOperationException ("Document not set");
if (providers == null || providers.Count == 0)
return;
if (!providers.Any ((provider) => provider != null && provider.HasCustomAttributes))
return;
writer.WriteStartElement ("attributes");
foreach (var provider in providers) {
if (provider == null)
continue;
if (!provider.HasCustomAttributes)
continue;
var ass = provider as AssemblyDefinition;
if (ass != null && !state.FollowForwarders)
TypeForwardedToData.OutputForwarders (writer, ass, state);
var attributes = provider.CustomAttributes.
Where ((att) => !SkipAttribute (att)).
OrderBy ((a) => a.Constructor.DeclaringType.FullName, StringComparer.Ordinal);
foreach (var att in attributes) {
string attName = Utils.CleanupTypeName (att.Constructor.DeclaringType);
writer.WriteStartElement ("attribute");
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 (); // properties
}
}
writer.WriteEndElement (); // attribute
}
}
writer.WriteEndElement (); // attributes
}
Dictionary<string, object> CreateAttributeMapping (CustomAttribute attribute)
{
Dictionary<string, object> mapping = null;
if (!state.TypeHelper.TryResolve (attribute))
return mapping;
PopulateMapping (ref mapping, attribute);
var constructor = state.TypeHelper.GetMethod (attribute.Constructor);
if (constructor == null || !constructor.HasParameters)
return mapping;
PopulateMapping (ref mapping, constructor, attribute);
return mapping;
}
static void PopulateMapping (ref Dictionary<string, object> mapping, CustomAttribute attribute)
{
if (!attribute.HasProperties)
return;
foreach (var named_argument in attribute.Properties) {
var name = named_argument.Name;
var arg = named_argument.Argument;
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 = null;
int? argument = null;
foreach (Instruction instruction in constructor.Body.Instructions) {
switch (instruction.OpCode.Code) {
case Code.Ldarg_1:
argument = 1;
break;
case Code.Ldarg_2:
argument = 2;
break;
case Code.Ldarg_3:
argument = 3;
break;
case Code.Ldarg:
case Code.Ldarg_S:
argument = ((ParameterDefinition) instruction.Operand).Index + 1;
break;
case Code.Stfld:
FieldReference field = (FieldReference) instruction.Operand;
if (field.DeclaringType.FullName != constructor.DeclaringType.FullName)
continue;
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);
argument = null;
break;
}
}
return field_mapping;
}
static Dictionary<PropertyDefinition, FieldReference> CreatePropertyFieldMapping (TypeDefinition type)
{
Dictionary<PropertyDefinition, FieldReference> property_mapping = null;
foreach (PropertyDefinition property in type.Properties) {
if (property.GetMethod == null)
continue;
if (!property.GetMethod.HasBody)
continue;
foreach (Instruction instruction in property.GetMethod.Body.Instructions) {
if (instruction.OpCode.Code != Code.Ldfld)
continue;
FieldReference field = (FieldReference) instruction.Operand;
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 (ref Dictionary<string, object> mapping, MethodDefinition constructor, CustomAttribute attribute)
{
if (!constructor.HasBody)
return;
// Custom handling for attributes with arguments which cannot be easily extracted
var ca = attribute.ConstructorArguments;
switch (constructor.DeclaringType.FullName) {
case "System.Runtime.CompilerServices.DecimalConstantAttribute":
var dca = constructor.Parameters[2].ParameterType == constructor.Module.TypeSystem.Int32 ?
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 ();
}
return;
}
var field_mapping = CreateArgumentFieldMapping (constructor);
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));
}
}
}
}
static object GetArgumentValue (TypeReference reference, object value)
{
var type = reference.Resolve ();
if (type == null)
return value;
if (type.IsEnum) {
if (IsFlaggedEnum (type))
return GetFlaggedEnumValue (type, value);
return GetEnumValue (type, value);
}
return value;
}
static bool IsFlaggedEnum (TypeDefinition type)
{
if (!type.IsEnum)
return false;
if (!type.HasCustomAttributes)
return false;
foreach (CustomAttribute attribute in type.CustomAttributes)
if (attribute.Constructor.DeclaringType.FullName == "System.FlagsAttribute")
return true;
return false;
}
static object GetFlaggedEnumValue (TypeDefinition type, object value)
{
if (value is ulong)
return GetFlaggedEnumValue (type, (ulong)value);
long flags = Convert.ToInt64 (value);
var signature = new StringBuilder ();
for (int i = type.Fields.Count - 1; i >= 0; i--) {
FieldDefinition field = type.Fields [i];
if (!field.HasConstant)
continue;
long flag = Convert.ToInt64 (field.Constant);
if (flag == 0)
continue;
if ((flags & flag) == flag) {
if (signature.Length != 0)
signature.Append (", ");
signature.Append (field.Name);
flags -= flag;
}
}
return signature.ToString ();
}
static object GetFlaggedEnumValue (TypeDefinition type, ulong flags)
{
var signature = new StringBuilder ();
for (int i = type.Fields.Count - 1; i >= 0; i--) {
FieldDefinition field = type.Fields [i];
if (!field.HasConstant)
continue;
ulong flag = Convert.ToUInt64 (field.Constant);
if (flag == 0)
continue;
if ((flags & flag) == flag) {
if (signature.Length != 0)
signature.Append (", ");
signature.Append (field.Name);
flags -= flag;
}
}
return signature.ToString ();
}
static object GetEnumValue (TypeDefinition type, object value)
{
foreach (FieldDefinition field in type.Fields) {
if (!field.HasConstant)
continue;
if (Comparer.Default.Compare (field.Constant, value) == 0)
return field.Name;
}
return value;
}
bool SkipAttribute (CustomAttribute attribute)
{
if (!state.TypeHelper.IsPublic (attribute))
return true;
return attribute.Constructor.DeclaringType.Name.EndsWith ("TODOAttribute", StringComparison.Ordinal);
}
public static void OutputAttributes (XmlWriter writer, State state, params ICustomAttributeProvider[] providers)
{
var data = new AttributeData (state);
data.DoOutput (writer, providers);
}
}
static class Parameters {
public static string GetSignature (IList<ParameterDefinition> infos)
{
if (infos == null || infos.Count == 0)
return string.Empty;
var signature = new StringBuilder ();
for (int i = 0; i < infos.Count; i++) {
if (i > 0)
signature.Append (", ");
ParameterDefinition info = infos [i];
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);
signature.Append (" ");
}
signature.Append (Utils.CleanupTypeName (info.ParameterType));
}
return signature.ToString ();
}
}
class TypeReferenceComparer : IComparer<TypeReference>
{
public static TypeReferenceComparer Default = new TypeReferenceComparer ();
public int Compare (TypeReference a, TypeReference b)
{
int result = String.Compare (a.Namespace, b.Namespace, StringComparison.Ordinal);
if (result != 0)
return result;
return String.Compare (a.Name, b.Name, StringComparison.Ordinal);
}
}
class MemberReferenceComparer : IComparer
{
public static MemberReferenceComparer Default = new MemberReferenceComparer ();
public int Compare (object a, object b)
{
MemberReference ma = (MemberReference) a;
MemberReference mb = (MemberReference) b;
return String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
}
}
class PropertyDefinitionComparer : IComparer<PropertyDefinition>
{
public static PropertyDefinitionComparer Default = new PropertyDefinitionComparer ();
public int Compare (PropertyDefinition ma, PropertyDefinition mb)
{
int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
if (res != 0)
return res;
if (!ma.HasParameters && !mb.HasParameters)
return 0;
if (!ma.HasParameters)
return -1;
if (!mb.HasParameters)
return 1;
return MethodDefinitionComparer.Compare (ma.Parameters, mb.Parameters);
}
}
class MethodDefinitionComparer : IComparer
{
public static MethodDefinitionComparer Default = new MethodDefinitionComparer ();
public int Compare (object a, object b)
{
MethodDefinition ma = (MethodDefinition) a;
MethodDefinition mb = (MethodDefinition) b;
int res = String.Compare (ma.Name, mb.Name, StringComparison.Ordinal);
if (res != 0)
return res;
if (!ma.HasParameters && !mb.HasParameters)
return 0;
if (!ma.HasParameters)
return -1;
if (!mb.HasParameters)
return 1;
res = Compare (ma.Parameters, mb.Parameters);
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);
}
public static int Compare (IList<ParameterDefinition> pia, IList<ParameterDefinition> pib)
{
var res = pia.Count - pib.Count;
if (res != 0)
return res;
string siga = Parameters.GetSignature (pia);
string sigb = Parameters.GetSignature (pib);
return String.Compare (siga, sigb, StringComparison.Ordinal);
}
}
}