[Mono-docs-list] Gtk# docs and the updater

Joshua Tauberer tauberer@for.net
Thu, 26 Feb 2004 18:19:44 -0500


This is a multi-part message in MIME format.
--------------090302010809020706000207
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Attached is stub.cs, which should probably replace the current updater 
program.  It has three functions:

1) Creating a new XML file for a particular type.  ex:
mono stub.exe --stub Gdk.Rectangle,gdk-sharp > path/to/Rectangle.xml

2) Updating an XML file.  Deleted members are removed from the xml file. 
  New members are added.  Each deleted/added member is printed to 
stdout. ex:
mono stub.exe --update ../../gtk-sharp/doc/en Gdk.Rectangle,gdk-sharp  > 
path/to/new/Rectangle.xml

Unfortunately, BindingFlags.IgnoreCase seems to not be working, so I 
couldn't quickly add a check to see if the case of the member names changed.

3) Creating a fresh XML file for a particular type, but importing the 
Docs nodes from an existing XML file.  Unlike (2), this guarantees the 
output XML file is properly structured.  But, it results in a file 
that's got a lot of whitespace differences from the original, which 
would make it difficult to make sure that the program hasn't deleted 
docs by accident.
ex:
mono stub.exe --regen ../../gtk-sharp/doc/en Gdk.Rectangle,gdk-sharp  > 
path/to/new/Rectangle.xml

John Luke wrote:
> It would be super sweet if it is capable of updating all the
> monodoc/class/* docs as well.  They really need an update, since they
> haven't been updated in ages.

Yup, it could do that.

Good luck to whoever uses this.  (Back up all of the docs first!)

-- 
- Joshua Tauberer

http://taubz.for.net

** Nothing Unreal Exists **

--------------090302010809020706000207
Content-Type: text/c-sharp;
 name="stub.cs"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="stub.cs"

using System;
using System.Collections;
using System.Text;
using System.Reflection;
using System.Xml;

public class Stub {
	
	static XmlDocument doc = new XmlDocument();
	
	public static void Main(string[] args) {
		if (args.Length == 0) {
			Console.WriteLine("Usage: mono stub.exe command");
			Console.WriteLine("commands:");
			Console.WriteLine("\t--stub type\tCreates a type stub file on stdout.");
			Console.WriteLine("\t--update basedir type\tUpdates the file for type to stdout, with the file located in basedir/type.Namespace/type.Name.xml, by adding and removing new members as necessary.");
			Console.WriteLine("\t--regen basedir type\tCreates a type stub file on stdout, importing the Docs nodes from the file located in basedir/type.Namespace/type.Name.xml as appropriate.");
			return;
		}
		
		switch (args[0]) {
			case "--stub":
				if (args.Length != 2) throw new InvalidOperationException();
				DoStubType(args[1]);
				break;
				
			case "--update":
				if (args.Length != 3) throw new InvalidOperationException();
				DoUpdateType(args[1], args[2]);
				break;

			case "--regen":
				if (args.Length != 3) throw new InvalidOperationException();
				DoRegenType(args[1], args[2]);
				break;

			default:
				Console.WriteLine("Invalid command.  Run with no arguments for help.");
				break;
		}
	}
	
	private static void WriteXml(XmlElement element, System.IO.TextWriter output) {
		XmlTextWriter writer = new XmlTextWriter(output);
		writer.Formatting = Formatting.Indented;
		writer.Indentation = 1;
		writer.IndentChar = '\t';
		element.WriteTo(writer);
		output.WriteLine();	
	}
	
	public static void DoStubType(string type) {
		WriteXml(StubType(type), Console.Out);
	}
	
	public static void DoUpdateType(string basepath, string typename) {
		Type type = Type.GetType(typename, true);
		
		XmlDocument basefile = new XmlDocument();
		basefile.PreserveWhitespace = true;
		basefile.Load(basepath + "/" + type.Namespace + "/" + type.Name + ".xml");
		
		XmlElement newfile = StubType(type);
		
		Hashtable seenmembers = new Hashtable();
		
		// Look for deleted members, remember what members are in the file
		foreach (XmlElement oldmember in basefile.SelectNodes("Type/Members/Member")) {
			MemberInfo oldmember2 = GetMember(type, oldmember);
			
			if (oldmember2 == null) {
				// Deleted (or signature changed)
				Console.Error.WriteLine("Member Deleted: " + oldmember.SelectSingleNode("MemberSignature/@Value").InnerText);
				oldmember.ParentNode.RemoveChild(oldmember);
				continue;
			}
			
			seenmembers[oldmember2] = 1;
		}

		XmlNode members = basefile.SelectSingleNode("Type/Members");
		foreach (MemberInfo m in type.GetMembers(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly)) {
			if (m is Type) continue;
			if (seenmembers.ContainsKey(m)) continue;
			
			XmlElement mm = MakeMember(m);
			if (mm == null) continue;
			members.AppendChild( basefile.ImportNode(mm, true) );
			members.AppendChild( members.OwnerDocument.CreateWhitespace("\n") );

			Console.Error.WriteLine("Member Added: " + mm.SelectSingleNode("MemberSignature/@Value").InnerText);
		}

			
		WriteXml(basefile.DocumentElement, Console.Out);
	}
	
	public static void DoRegenType(string basepath, string typename) {
		Type type = Type.GetType(typename, true);
		
		XmlDocument basefile = new XmlDocument();
		basefile.PreserveWhitespace = true;
		basefile.Load(basepath + "/" + type.Namespace + "/" + type.Name + ".xml");
		
		XmlElement newfile = StubType(type);
		
		// Copy old Type/Docs into new doc
		newfile.ReplaceChild(newfile.OwnerDocument.ImportNode(basefile.SelectSingleNode("Type/Docs"), true), newfile.SelectSingleNode("Docs"));
		
		// Copy old Type/Members/Member/Docs into new doc
		foreach (XmlElement oldmember in basefile.SelectNodes("Type/Members/Member")) {
			XmlElement newmember = FindMatchingMember(type, newfile, oldmember);
			if (newmember == null) {
				Console.Error.WriteLine("Member Deleted: " + oldmember.SelectSingleNode("MemberSignature/@Value").InnerText);
				continue;
			}
			newmember.ReplaceChild(newmember.OwnerDocument.ImportNode(oldmember.SelectSingleNode("Docs"), true), newmember.SelectSingleNode("Docs"));
		}

		WriteXml(newfile, Console.Out);
	}
	
	// UPDATE HELPER FUNCTIONS
	
	private static XmlElement FindMatchingMember(Type type, XmlElement newfile, XmlElement oldmember) {
		MemberInfo oldmember2 = GetMember(type, oldmember);
		if (oldmember2 == null) return null;
		
		string membername = oldmember.GetAttribute("MemberName");
		foreach (XmlElement newmember in newfile.SelectNodes("Members/Member[@MemberName='" + membername + "']")) {
			if (GetMember(type, newmember) == oldmember2) return newmember;
		}
		
		return null;
	}
	
	private static MemberInfo GetMember(Type type, XmlElement member) {
		string membertype = member.SelectSingleNode("MemberType").InnerText;
		
		// Get list of parameter types for member
		ArrayList memberparams = new ArrayList();
		foreach (XmlElement param in member.SelectNodes("Parameters/Parameter"))
			memberparams.Add(param.GetAttribute("Type"));
		
		// Loop through all members in this type with the same name
		MemberInfo[] mis = type.GetMember(member.GetAttribute("MemberName"), BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		foreach (MemberInfo mi in mis) {
			if (mi is Type) continue;
			if (GetMemberType(mi) != membertype) continue;
			
			ParameterInfo[] pis = null;
			if (mi is MethodInfo || mi is ConstructorInfo)
				pis = ((MethodBase)mi).GetParameters();
			else if (mi is PropertyInfo)
				pis = ((PropertyInfo)mi).GetIndexParameters();
			
			if (pis == null)
				pis = new ParameterInfo[0];
				
			if (pis.Length != memberparams.Count) continue;			
			
			bool good = true;
			for (int i = 0; i < pis.Length; i++)
				if (pis[i].ParameterType.FullName != (string)memberparams[i]) { good = false; break; }
			if (!good) continue;

			return mi;
		}
		
		return null;
	}
	
	// CREATE A STUB OF A DOCUMENTATION FILE	

	public static XmlElement StubType(string type) {
		return StubType(Type.GetType(type, true));
	}
	
	public static XmlElement StubType(Type type) {
		string typesig = MakeTypeSignature(type);
		if (typesig == null) return null; // not publicly visible
		
		XmlElement root = doc.CreateElement("Type");
		root.SetAttribute("Name", type.Name);
		root.SetAttribute("FullName", type.FullName);
		
		XmlElement sig = doc.CreateElement("TypeSignature");
		root.AppendChild(sig);
		sig.SetAttribute("Language", "C#");
		sig.SetAttribute("Value", typesig);
		
		XmlElement ass = doc.CreateElement("AssemblyInfo");
		root.AppendChild(ass);
		ass.AppendChild(SimpleElement("AssemblyName", type.Assembly.GetName().Name));
		ass.AppendChild(SimpleElement("AssemblyVersion", type.Assembly.GetName().Version.ToString()));
		ass.AppendChild(SimpleElement("AssemblyCulture", type.Assembly.GetName().CultureInfo.Name));
		XmlElement assattributes = MakeAttributes(type.Assembly);
		if (assattributes != null) ass.AppendChild(assattributes);
		
		XmlElement basetype = doc.CreateElement("Base");
		root.AppendChild(basetype);
		basetype.AppendChild(SimpleElement("BaseTypeName", type.BaseType.FullName));

		if (!IsDelegate(type) && !type.IsInterface) {
			XmlElement interfaces = doc.CreateElement("Interfaces");
			root.AppendChild(interfaces);
			foreach (Type i in type.GetInterfaces()) {
				XmlElement iface = doc.CreateElement("Interface");
				interfaces.AppendChild(iface);
				iface.AppendChild(SimpleElement("InterfaceName", i.FullName));
			}
		}

		XmlElement attributes = MakeAttributes(type);
		if (attributes != null) root.AppendChild(attributes);
		
		if (IsDelegate(type)) {
			root.AppendChild(MakeParameters(type.GetMethod("Invoke").GetParameters()));
			root.AppendChild(MakeReturnValue(type.GetMethod("Invoke").ReturnType));
		}
		
		if (!IsDelegate(type)) {
			XmlElement members = doc.CreateElement("Members");
			root.AppendChild(members);
			foreach (MemberInfo m in type.GetMembers(BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static|BindingFlags.Instance|BindingFlags.DeclaredOnly)) {
				if (m is Type) continue;
				XmlElement mm = MakeMember(m);
				if (mm == null) continue;
				members.AppendChild( mm );
			}
		}
		
		root.AppendChild(MakeDocNode(null, null, true));
		
		return root;
	}
	
	// STUB HELPER FUNCTIONS
	
	private static XmlElement SimpleElement(string name, string val) {
		XmlElement e = doc.CreateElement(name);
		e.InnerText = val;
		return e;
	}
	
	private static XmlElement MakeDocNode(ParameterInfo[] parameters, Type returntype, bool returnisreturn) {
		XmlElement e = doc.CreateElement("Docs");
		
		e.AppendChild(SimpleElement("summary", "To be added."));
		
		if (parameters != null) {
			foreach (ParameterInfo p in parameters) {
				XmlElement pe = SimpleElement("param", "To be added.");
				pe.SetAttribute("name", p.Name);
				e.AppendChild(pe);
			}
		}
		
		if (returntype != null && returntype != typeof(void)) {
			e.AppendChild(SimpleElement(returnisreturn ? "returns" : "value", "To be added."));
		}

		e.AppendChild(SimpleElement("remarks", "To be added."));
		
		return e;
	}
	
	private static XmlElement MakeAttributes(ICustomAttributeProvider attributes) {
		object[] at = attributes.GetCustomAttributes(false);
		if (at.Length == 0) return null;

		bool b = false;
		XmlElement e = doc.CreateElement("Attributes");
		foreach (Attribute a in at) {
			if (GetTypeVisibility(a.GetType().Attributes) == null) continue; // hide non-visible attributes
			b = true;
			
			ArrayList fields = new ArrayList();
			foreach (PropertyInfo f in a.GetType().GetProperties(BindingFlags.Public|BindingFlags.Instance)) {
				if (f.Name == "TypeId") continue;
				
				object v = f.GetValue(a, null);
				if (v == null) v = "null";
				else if (v is string) v = "\"" + v + "\"";
				else if (v is Type) v = "typeof(" + ((Type)v).FullName + ")";
				else if (v is Enum) v = v.GetType().FullName + "." + v;
					
				fields.Add(f.Name + "=" + v);
			}
			string a2 = String.Join(", ", (string[])fields.ToArray(typeof(string)));
			if (a2 != "") a2 = "(" + a2 + ")";
			
			XmlElement ae = doc.CreateElement("Attribute");
			e.AppendChild(ae);
			
			string name = a.GetType().FullName;
			if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length-"Attribute".Length);
			ae.AppendChild( SimpleElement("AttributeName", name + a2) );
		}
		
		if (!b) return null;
		
		return e;
	}
	
	private static XmlElement MakeParameters(ParameterInfo[] parameters) {
		XmlElement e = doc.CreateElement("Parameters");
		foreach (ParameterInfo p in parameters) {
			XmlElement pe = doc.CreateElement("Parameter");
			e.AppendChild(pe);
			pe.SetAttribute("Name", p.Name);
			pe.SetAttribute("Type", p.ParameterType.FullName);
			if (p.ParameterType.IsByRef) {
				if (p.IsOut) pe.SetAttribute("RefType", "out");
				else pe.SetAttribute("RefType", "ref");
			}
			XmlElement attributes = MakeAttributes(p);
			if (attributes != null) pe.AppendChild(attributes);
		}
		return e;
	}

	private static XmlElement MakeParameters(MemberInfo mi) {
		if (mi is ConstructorInfo) return MakeParameters(((ConstructorInfo)mi).GetParameters());
		if (mi is MethodInfo) return MakeParameters(((MethodInfo)mi).GetParameters());
		if (mi is PropertyInfo) {
			ParameterInfo[] parameters = ((PropertyInfo)mi).GetIndexParameters();
			if (parameters.Length > 0)
				return MakeParameters(parameters);
			else
				return null;
		}
		if (mi is FieldInfo) return null;
		if (mi is EventInfo) return null;
		throw new ArgumentException();
	}

	private static XmlElement MakeReturnValue(Type type, ICustomAttributeProvider attributes) {
		XmlElement e = doc.CreateElement("ReturnValue");
		e.AppendChild( SimpleElement("ReturnType", type.FullName) );
		if (attributes != null) {
			XmlElement a = MakeAttributes(attributes);
			if (a != null) e.AppendChild(a);
		}
		return e;
	}
	
	private static XmlElement MakeReturnValue(MemberInfo mi) {
		if (mi is ConstructorInfo) return null;
		if (mi is MethodInfo) return MakeReturnValue(((MethodInfo)mi).ReturnType, ((MethodInfo)mi).ReturnTypeCustomAttributes);
		if (mi is PropertyInfo) return MakeReturnValue(((PropertyInfo)mi).PropertyType, null);
		if (mi is FieldInfo) return MakeReturnValue(((FieldInfo)mi).FieldType, null);
		if (mi is EventInfo) return MakeReturnValue(((EventInfo)mi).EventHandlerType, null);
		throw new ArgumentException();
	}

	private static XmlElement MakeMember(MemberInfo mi) {
		string sigs = MakeMemberSignature(mi);
		if (sigs == null) return null; // not publicly visible
		
		// no documentation for property/event accessors.  Is there a better way of doing this?
		if (mi.Name.StartsWith("get_")) return null;
		if (mi.Name.StartsWith("set_")) return null;
		if (mi.Name.StartsWith("add_")) return null;
		if (mi.Name.StartsWith("remove_")) return null;
		if (mi.Name.StartsWith("raise_")) return null;
		
		XmlElement me = doc.CreateElement("Member");
		me.SetAttribute("MemberName", mi.Name);
		
		XmlElement sig = doc.CreateElement("MemberSignature");
		me.AppendChild(sig);
		sig.SetAttribute("Language", "C#");
		sig.SetAttribute("Value", sigs);
		
		me.AppendChild( SimpleElement("MemberType", GetMemberType(mi)) );
		
		XmlElement a = MakeAttributes(mi);
		if (a != null) me.AppendChild(a);
		
		XmlElement retval = MakeReturnValue(mi);
		if (retval != null) me.AppendChild(retval);
		
		XmlElement parameters = MakeParameters(mi);
		if (parameters != null) me.AppendChild(parameters);
		
		if (mi is FieldInfo && (((FieldInfo)mi).IsLiteral || (((FieldInfo)mi).IsStatic && ((FieldInfo)mi).IsInitOnly))) {
			object val = ((FieldInfo)mi).GetValue(null);
			if (val is IConvertible)
				me.AppendChild( SimpleElement("MemberValue", ((IConvertible)val).ToString(null)) );
		}
		
		if (mi is MethodInfo)
			me.AppendChild(MakeDocNode(((MethodInfo)mi).GetParameters(), ((MethodInfo)mi).ReturnType, true));
		else if (mi is ConstructorInfo)
			me.AppendChild(MakeDocNode(((ConstructorInfo)mi).GetParameters(), null, false));
		else if (mi is PropertyInfo)
			me.AppendChild(MakeDocNode(((PropertyInfo)mi).GetIndexParameters(), ((PropertyInfo)mi).PropertyType, false));
		else
			me.AppendChild(MakeDocNode(null, null, false));

		return me;
	}
	
	static bool IsDelegate(Type type) {
		return typeof(System.Delegate).IsAssignableFrom (type) && !type.IsAbstract;
	}
	
	/// SIGNATURE GENERATION FUNCTIONS
	
	static string GetTypeKind (Type t) {
			if (t.IsEnum) return "enum";
			if (t.IsClass) return "class";
			if (t.IsInterface) return "interface";
			if (t.IsValueType) return "struct";
			throw new ArgumentException();
	}

	static string GetTypeVisibility (TypeAttributes ta) {
			switch (ta & TypeAttributes.VisibilityMask){
			case TypeAttributes.Public:
			case TypeAttributes.NestedPublic:
					return "public";

			case TypeAttributes.NestedFamily:
			case TypeAttributes.NestedFamORAssem:
					return "protected";

			default:
					return null;
			}
	}

	static string MakeTypeSignature (Type type) {
		StringBuilder sig = new StringBuilder();
		
		string visibility = GetTypeVisibility(type.Attributes);
		if (visibility == null) return null;
		sig.Append(visibility);
		sig.Append(" ");

		if (type.IsAbstract) sig.Append("abstract ");
		if (type.IsSealed && !IsDelegate(type)) sig.Append("sealed ");

		if (IsDelegate(type)) {
			MethodInfo invoke = type.GetMethod ("Invoke");
			string arguments = GetMethodParameters(invoke.GetParameters());
			string return_value = ConvertCTSName(invoke.ReturnType.FullName);
			sig.Append(return_value);
			sig.Append(" ");
			sig.Append(type.Name);
			sig.Append("(");
			sig.Append(arguments);
			sig.Append(")");
			return sig.ToString();
		}
		
		sig.Append(GetTypeKind(type));
		sig.Append(" ");
		sig.Append(type.Name);

		if (!type.IsValueType && !type.IsEnum) {
			if ((type.BaseType != null && type.BaseType != typeof(object)) || type.GetInterfaces().Length > 0)
				sig.Append(" : ");
			
			if (type.BaseType != null && type.BaseType != typeof(object)) {
				sig.Append(type.BaseType.FullName);
				if (type.GetInterfaces().Length > 0)
					sig.Append(", ");
			}
			
			Type [] interfaces = type.GetInterfaces ();
			for (int i = 0; i < interfaces.Length; i ++){
					if (i != 0) sig.Append(", ");
					sig.Append(interfaces [i].FullName);
			}
		}

		return sig.ToString();
	}


	static string GetFieldVisibility (FieldInfo field) {
		if (field.IsPublic) return "public";
		if (field.IsFamily) return "protected";
		return null;
	}

	static string MakeFieldSignature (FieldInfo field) {
		string visibility = GetFieldVisibility (field);
		if (visibility == null) return null;
		
		
		string type = ConvertCTSName (field.FieldType.FullName);
		
		string modifiers = String.Empty;
		if (field.IsStatic) modifiers += " static";
		if (field.IsInitOnly) modifiers += " readonly";
		if (field.IsLiteral) modifiers += " const";

		return String.Format ("{0}{1} {2} {3}",
						visibility, modifiers, type, field.Name);
	}

	static string GetMethodVisibility (MethodBase method) {
		if (method.IsPublic) return "public";
		if (method.IsFamily) return "protected";
		return null;
	}

	static string GetMethodParameters (ParameterInfo[] pi) {
		if (pi.Length == 0) return "";
		
		StringBuilder sb = new StringBuilder ();

		int i = 0;
		string modifier;
		foreach (ParameterInfo parameter in pi) {
			if (i != 0) sb.Append (", ");
			if (parameter.ParameterType.IsByRef) {
				if (parameter.IsOut) sb.Append("out ");
				else sb.Append("ref ");
			}
			string param = ConvertCTSName (parameter.ParameterType.FullName, parameter.ParameterType.IsByRef);
			sb.Append (param);
			sb.Append (" ");
			sb.Append (parameter.Name);
			i++;
		}

		return sb.ToString();
	}

	static string MakeMethodSignature (MethodInfo method) {
		string visibility = GetMethodVisibility (method);
		if (visibility == null)
				return null;
		
		string modifiers = String.Empty;
		if (method.IsStatic) modifiers += " static";
		if (method.IsVirtual) {
				if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
				else modifiers += " override";
		}
		if (method.IsAbstract) modifiers += " abstract";
		if (method.IsFinal) modifiers += " sealed";

		string return_type = ConvertCTSName (method.ReturnType.FullName);
		string parameters = GetMethodParameters (method.GetParameters());

		string method_name = method.Name;
		
		// operators, default accessors need name rewriting

		return String.Format ("{0}{1} {2} {3}({4})",
						visibility, modifiers, return_type, method_name, parameters);
	}

	static string MakeConstructorSignature (ConstructorInfo constructor) {
		string visibility = GetMethodVisibility (constructor);
		if (visibility == null)
			return null;

		string name = constructor.DeclaringType.Name;
		string parameters = GetMethodParameters (constructor.GetParameters());

		return String.Format ("{0} {1}({2})",
						visibility, name, parameters);
	}


	static string MakePropertySignature (PropertyInfo property) {
		// pick an accessor
		MethodBase method = property.GetSetMethod (true);
		if (method == null)
			method = property.GetGetMethod (true);
	
		string visibility = GetMethodVisibility(method);
		if (visibility == null)
			return null;
	
		string modifiers = String.Empty;
		if (method.IsStatic) modifiers += " static";
		if (method.IsVirtual) {
				if ((method.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
				else modifiers += " override";
		}
		if (method.IsAbstract) modifiers += " abstract";
		if (method.IsFinal) modifiers += " sealed";
	
		string name = property.Name;
	
		string type_name = property.PropertyType.FullName;
		type_name = ConvertCTSName (type_name);
		
		string parameters = GetMethodParameters (property.GetIndexParameters());
		if (parameters != "") parameters = "[" + parameters + "]";		
		
		string accessors = null;
		if (property.CanRead && property.CanWrite)
			accessors = "{ set; get; }";
		else if (property.CanRead)
			accessors = "{ get; }";
		else if (property.CanWrite)
			accessors = "{ set; }";
	
		return String.Format ("{0}{1} {2} {3}{4} {5}",
						visibility, modifiers, type_name, name, parameters, accessors);
	}
		
	static string MakeEventSignature (EventInfo ev) {
		MethodInfo add = ev.GetAddMethod ();

		string visibility = GetMethodVisibility(add);
		if (visibility == null)
			return null;

		string modifiers = String.Empty;
		if (add.IsStatic) modifiers += " static";
		if (add.IsVirtual) {
				if ((add.Attributes & MethodAttributes.NewSlot) != 0) modifiers += " virtual";
				else modifiers += " override";
		}
		if (add.IsAbstract) modifiers += " abstract";
		if (add.IsFinal) modifiers += " sealed";
		
		string name = ev.Name;
		string type = ConvertCTSName(ev.EventHandlerType.FullName);

		return String.Format ("{0}{1} event {2} {3}",
						visibility, modifiers, type, name);
	}
	
	static string MakeMemberSignature(MemberInfo mi) {
		if (mi is ConstructorInfo) return MakeConstructorSignature((ConstructorInfo)mi);
		if (mi is MethodInfo) return MakeMethodSignature((MethodInfo)mi);
		if (mi is PropertyInfo) return MakePropertySignature((PropertyInfo)mi);
		if (mi is FieldInfo) return MakeFieldSignature((FieldInfo)mi);
		if (mi is EventInfo) return MakeEventSignature((EventInfo)mi);
		throw new ArgumentException(mi.ToString());
	}

	static string GetMemberType(MemberInfo mi) {
		if (mi is ConstructorInfo) return "Constructor";
		if (mi is MethodInfo) return "Method";
		if (mi is PropertyInfo) return "Property";
		if (mi is FieldInfo) return "Field";
		if (mi is EventInfo) return "Event";
		throw new ArgumentException();
	}

	static string ConvertCTSName (string type, bool shorten)
	{
			if (shorten)
					type =  type.Substring (0, type.Length - 1);

			string retval =  ConvertCTSName (type);

			return retval;
	}

	//
	// Utility function: converts a fully .NET qualified type name into a C#-looking one
	//
	static string ConvertCTSName (string type) {
		if (type.EndsWith ("[]"))
			return ConvertCTSName(type.Substring(0, type.Length - 2).TrimEnd()) + "[]";

		if (type.EndsWith ("&"))
			return ConvertCTSName(type.Substring(0, type.Length - 1).TrimEnd()) + "&";

		if (type.EndsWith ("*"))
			return ConvertCTSName(type.Substring(0, type.Length - 1).TrimEnd()) + "*";

		if (!type.StartsWith ("System."))
				return type;

		switch (type) {
		case "System.Byte": return "byte";
		case "System.SByte": return "sbyte";
		case "System.Int16": return "short";
		case "System.Int32": return "int";
		case "System.Int64": return "long";

		case "System.UInt16": return "ushort";
		case "System.UInt32": return "uint";
		case "System.UInt64": return "ulong";

		case "System.Single":  return "float";
		case "System.Double":  return "double";
		case "System.Decimal": return "decimal";
		case "System.Boolean": return "bool";
		case "System.Char":    return "char";
		case "System.Void":    return "void";
		case "System.String":  return "string";
		case "System.Object":  return "object";
		}

		return type;
	}
	

}

--------------090302010809020706000207--