3 // Adam Treat (manyoso@yahoo.com)
6 // DocStub is based heavily upon the NDoc project
7 // ndoc.sourceforge.net
9 // This program is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
16 using System.Collections;
17 using System.Collections.Specialized;
18 using System.Diagnostics;
20 using System.Reflection;
30 string assembly_file, directory, language, classname, currentNamespace, docname;
35 "docstub -l <lang> -d <directory> -a <assembly>\n\n" +
36 " -d || /-d || --dir <directory> The directory to write the xml files to.\n" +
37 " -a || /-a || --assembly <assembly> Specifies the target assembly to load and parse.\n" +
38 " -l || /-l || --language <two-letter ISO code> Specifies the language encoding.\n\n");
41 public static void Main(string[] args)
43 DocStub stub = new DocStub(args);
46 public DocStub(string [] args)
50 int argc = args.Length;
52 for(int i = 0; i < argc; i++)
56 // The "/" switch is there for wine users, like me ;-)
57 if(arg.StartsWith("-") || arg.StartsWith("/"))
62 case "-d": case "/-d": case "--directory":
68 directory = args[++i];
71 case "-a": case "/-a": case "--assembly":
77 assembly_file = args[++i];
79 case "-l": case "/-l": case "--language":
95 if(assembly_file == null)
99 } else if(directory == null)
105 if (!Directory.Exists(directory) && directory != null)
107 Directory.CreateDirectory(directory);
110 // Call the main driver to get some things done
114 // Builds an XmlDocument with the reflected metadata
115 private void MakeXml()
119 assembly = LoadAssembly(Path.GetFullPath(assembly_file));
123 Console.WriteLine(e.Message);
130 foreach(Module module in assembly.GetModules())
132 WriteNamespaces(module);
136 private void WriteNamespaces(Module module)
138 Type[] types = module.GetTypes();
139 StringCollection namespaceNames = GetNamespaceNames(types);
140 XmlTextWriter dummy = new XmlTextWriter(".temp.xml", null);
141 foreach (string namespaceName in namespaceNames)
143 currentNamespace = namespaceName;
144 WriteClasses(dummy, types);
145 WriteInterfaces(dummy, types);
146 WriteStructures(dummy, types);
147 WriteDelegates(dummy, types);
148 WriteEnumerations(dummy, types);
150 File.Delete(".temp.xml");
153 private XmlTextWriter StartDocument()
155 if (!Directory.Exists(directory+"/"+currentNamespace) && directory != null)
157 Directory.CreateDirectory(directory+"/"+currentNamespace);
159 string filename = directory+"/"+currentNamespace+"/"+docname+".xml";
160 XmlTextWriter writer = new XmlTextWriter (filename, null);
161 writer.Formatting = Formatting.Indented;
162 writer.Indentation=4;
163 writer.WriteStartDocument();
164 writer.WriteStartElement("monodoc");
165 writer.WriteAttributeString("language",language);
169 private void EndDocument(XmlTextWriter writer)
171 writer.WriteEndElement();
172 writer.WriteEndDocument();
177 private bool IsDelegate(Type type)
179 return type.BaseType.FullName == "System.Delegate" ||
180 type.BaseType.FullName == "System.MulticastDelegate";
183 private string GetTypeName(Type type)
185 return type.FullName.Replace('+', '.');
188 private StringCollection GetNamespaceNames(Type[] types)
190 StringCollection namespaceNames = new StringCollection();
192 foreach (Type type in types)
194 if (namespaceNames.Contains(type.Namespace) == false)
196 namespaceNames.Add(type.Namespace);
200 return namespaceNames;
203 private bool IsAlsoAnEvent(Type type, string fullName)
205 bool isEvent = false;
207 BindingFlags bindingFlags =
208 BindingFlags.Instance |
209 BindingFlags.Static |
210 BindingFlags.Public |
211 BindingFlags.NonPublic |
212 BindingFlags.DeclaredOnly;
214 foreach (EventInfo eventInfo in type.GetEvents(bindingFlags))
216 if (eventInfo.EventHandlerType.FullName == fullName)
226 private bool IsAlsoAnEvent(FieldInfo field)
228 return IsAlsoAnEvent(field.DeclaringType, field.FieldType.FullName);
231 private bool IsAlsoAnEvent(PropertyInfo property)
233 return IsAlsoAnEvent(property.DeclaringType, property.PropertyType.FullName);
236 // Loads an assembly.
237 public static Assembly LoadAssembly(string filename)
239 if (!File.Exists(filename))
241 throw new ApplicationException("can't find assembly " + filename);
244 FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read);
245 byte[] buffer = new byte[fs.Length];
246 fs.Read(buffer, 0, (int)fs.Length);
249 return Assembly.Load(buffer);
252 private string GetParameterTypes(ParameterInfo[] parameters)
254 if (parameters.Length != 0) {
255 StringBuilder sb = new StringBuilder();
257 foreach (ParameterInfo parameter in parameters)
259 sb.Append(GetTypeName(parameter.ParameterType) + ", ");
261 sb.Remove(sb.Length-2, 2);
263 return sb.ToString();
269 private void WriteClasses(XmlTextWriter writer, Type[] types)
271 foreach (Type type in types)
273 if (type.IsClass && !IsDelegate(type) && type.Namespace.Equals(currentNamespace))
275 classname = type.FullName;
279 writer = StartDocument();
280 WriteClass(writer, type);
283 WriteClass(writer, type);
289 private void WriteInterfaces(XmlTextWriter writer, Type[] types)
291 foreach (Type type in types)
293 if (type.IsInterface && type.Namespace.Equals(currentNamespace))
295 classname = type.FullName;
299 writer = StartDocument();
300 WriteInterface(writer, type);
303 WriteInterface(writer, type);
309 private void WriteStructures(XmlTextWriter writer, Type[] types)
311 foreach (Type type in types)
313 if (type.IsValueType && !type.IsEnum && type.Namespace.Equals(currentNamespace))
315 classname = type.FullName;
319 writer = StartDocument();
320 WriteClass(writer, type);
323 WriteClass(writer, type);
329 private void WriteDelegates(XmlTextWriter writer, Type[] types)
331 foreach (Type type in types)
333 if (type.IsClass && IsDelegate(type) && type.Namespace.Equals(currentNamespace))
335 classname = type.FullName;
339 writer = StartDocument();
340 WriteDelegate(writer, type);
343 WriteDelegate(writer, type);
349 private void WriteEnumerations(XmlTextWriter writer, Type[] types)
351 foreach (Type type in types)
353 if (type.IsEnum && type.Namespace.Equals(currentNamespace))
355 classname = type.FullName;
359 writer = StartDocument();
360 WriteEnumeration(writer, type);
363 WriteEnumeration(writer, type);
369 // Writes XML documenting a class or struct.
370 private void WriteClass(XmlTextWriter writer, Type type)
372 Type[] types = type.GetNestedTypes();
373 AssemblyName assemblyName = assembly.GetName();
374 bool isStruct = type.IsValueType;
377 writer.WriteStartElement(isStruct ? "struct" : "class");
378 writer.WriteAttributeString("name", type.FullName);
379 writer.WriteAttributeString("assembly", assemblyName.Name);
380 writer.WriteElementString("summary","TODO");
381 writer.WriteElementString("remarks","TODO");
383 WriteClasses(writer, types);
384 WriteInterfaces(writer, types);
385 WriteStructures(writer, types);
386 WriteDelegates(writer, types);
387 WriteEnumerations(writer, types);
389 WriteConstructors(writer, type);
390 WriteFields(writer, type);
391 WriteProperties(writer, type);
392 WriteMethods(writer, type);
393 WriteOperators(writer, type);
394 WriteEvents(writer, type);
396 writer.WriteEndElement();
399 // Writes XML documenting an interface.
400 private void WriteInterface(XmlTextWriter writer, Type type)
402 Type[] types = type.GetNestedTypes();
403 AssemblyName assemblyName = assembly.GetName();
405 writer.WriteStartElement("interface");
406 writer.WriteAttributeString("name", type.FullName);
407 writer.WriteAttributeString("assembly", assemblyName.Name);
408 writer.WriteElementString("summary","TODO");
409 writer.WriteElementString("remarks","TODO");
410 writer.WriteStartElement("seealso");
411 writer.WriteAttributeString("cref", "TODO");
412 writer.WriteEndElement();
413 writer.WriteEndElement();
416 // Writes XML documenting a delegate.
417 private void WriteDelegate(XmlTextWriter writer, Type type)
419 Type[] types = type.GetNestedTypes();
420 AssemblyName assemblyName = assembly.GetName();
422 writer.WriteStartElement("delegate");
423 writer.WriteAttributeString("name", type.FullName);
424 writer.WriteAttributeString("assembly", assemblyName.Name);
425 writer.WriteElementString("summary","TODO");
426 writer.WriteElementString("remarks","TODO");
427 writer.WriteStartElement("seealso");
428 writer.WriteAttributeString("cref", "TODO");
429 writer.WriteEndElement();
433 writer.WriteEndElement();
436 // Writes XML documenting an enumeration.
437 private void WriteEnumeration(XmlTextWriter writer, Type type)
439 Type[] types = type.GetNestedTypes();
440 AssemblyName assemblyName = assembly.GetName();
442 writer.WriteStartElement("enum");
443 writer.WriteAttributeString("name", type.FullName);
444 writer.WriteAttributeString("assembly", assemblyName.Name);
445 writer.WriteElementString("summary","TODO");
446 writer.WriteElementString("remarks","TODO");
448 writer.WriteStartElement("member");
449 writer.WriteAttributeString("name", "TODO");
450 writer.WriteEndElement();
452 writer.WriteEndElement();
455 private void WriteConstructors(XmlTextWriter writer, Type type)
457 BindingFlags bindingFlags =
458 BindingFlags.Instance |
459 BindingFlags.Public |
460 BindingFlags.NonPublic;
462 ConstructorInfo[] constructors = type.GetConstructors(bindingFlags);
464 foreach (ConstructorInfo constructor in constructors)
466 WriteConstructor(writer, constructor);
470 private void WriteFields(XmlTextWriter writer, Type type)
472 BindingFlags bindingFlags =
473 BindingFlags.Instance |
474 BindingFlags.Static |
475 BindingFlags.Public |
476 BindingFlags.NonPublic;
478 foreach (FieldInfo field in type.GetFields(bindingFlags))
480 if (!IsAlsoAnEvent(field))
482 WriteField(writer, field);
487 private void WriteProperties(XmlTextWriter writer, Type type)
489 BindingFlags bindingFlags =
490 BindingFlags.Instance |
491 BindingFlags.Static |
492 BindingFlags.Public |
493 BindingFlags.NonPublic;
495 PropertyInfo[] properties = type.GetProperties(bindingFlags);
497 foreach (PropertyInfo property in properties)
499 MethodInfo getMethod = property.GetGetMethod(true);
500 MethodInfo setMethod = property.GetSetMethod(true);
502 bool hasGetter = (getMethod != null);
503 bool hasSetter = (setMethod != null);
505 if ((hasGetter || hasSetter) && !IsAlsoAnEvent(property))
507 WriteProperty(writer, property, property.DeclaringType.FullName != type.FullName);
512 private void WriteMethods(XmlTextWriter writer, Type type)
514 BindingFlags bindingFlags =
515 BindingFlags.Instance |
516 BindingFlags.Static |
517 BindingFlags.Public |
518 BindingFlags.NonPublic;
520 MethodInfo[] methods = type.GetMethods(bindingFlags);
522 foreach (MethodInfo method in methods)
524 if (!(method.Name.StartsWith("get_")) &&
525 !(method.Name.StartsWith("set_")) &&
526 !(method.Name.StartsWith("add_")) &&
527 !(method.Name.StartsWith("remove_")) &&
528 !(method.Name.StartsWith("op_")))
530 WriteMethod(writer, method, method.DeclaringType.FullName != type.FullName);
535 private void WriteOperators(XmlTextWriter writer, Type type)
537 BindingFlags bindingFlags =
538 BindingFlags.Instance |
539 BindingFlags.Static |
540 BindingFlags.Public |
541 BindingFlags.NonPublic;
543 MethodInfo[] methods = type.GetMethods(bindingFlags);
545 foreach (MethodInfo method in methods)
547 if (method.Name.StartsWith("op_"))
549 WriteOperator(writer, method);
554 private void WriteEvents(XmlTextWriter writer, Type type)
556 BindingFlags bindingFlags =
557 BindingFlags.Instance |
558 BindingFlags.Static |
559 BindingFlags.Public |
560 BindingFlags.NonPublic |
561 BindingFlags.DeclaredOnly;
563 foreach (EventInfo eventInfo in type.GetEvents(bindingFlags))
565 MethodInfo addMethod = eventInfo.GetAddMethod(true);
567 if (addMethod != null)
569 WriteEvent(writer, eventInfo);
574 // Writes XML documenting a field.
575 private void WriteField(XmlTextWriter writer, FieldInfo field)
577 writer.WriteStartElement("field");
578 writer.WriteAttributeString("name", field.Name);
579 writer.WriteElementString("summary","TODO");
580 writer.WriteElementString("remarks","TODO");
581 writer.WriteStartElement("seealso");
582 writer.WriteAttributeString("cref", "TODO");
583 writer.WriteEndElement();
585 writer.WriteEndElement();
588 // Writes XML documenting an event.
589 private void WriteEvent(XmlTextWriter writer, EventInfo eventInfo)
591 writer.WriteStartElement("event");
592 writer.WriteAttributeString("name", eventInfo.Name);
593 writer.WriteElementString("summary","TODO");
594 writer.WriteElementString("remarks","TODO");
595 writer.WriteElementString("data","TODO");
596 writer.WriteStartElement("seealso");
597 writer.WriteAttributeString("cref", "TODO");
598 writer.WriteEndElement();
600 writer.WriteEndElement();
603 // Writes XML documenting a constructor.
604 private void WriteConstructor(XmlTextWriter writer, ConstructorInfo constructor)
606 writer.WriteStartElement("constructor");
607 writer.WriteAttributeString("name", docname + GetParameterTypes(constructor.GetParameters()));
608 writer.WriteElementString("summary","TODO");
609 writer.WriteElementString("remarks","TODO");
611 foreach (ParameterInfo parameter in constructor.GetParameters())
613 WriteParameter(writer, parameter);
616 writer.WriteStartElement("seealso");
617 writer.WriteAttributeString("cref", "TODO");
618 writer.WriteEndElement();
620 writer.WriteEndElement();
623 // Writes XML documenting a property.
624 private void WriteProperty(XmlTextWriter writer, PropertyInfo property, bool inherited )
628 writer.WriteStartElement("property");
629 writer.WriteAttributeString("name", property.Name);
630 writer.WriteElementString("summary","TODO");
631 writer.WriteElementString("remarks","TODO");
632 writer.WriteElementString("value","TODO");
633 writer.WriteStartElement("seealso");
634 writer.WriteAttributeString("cref", "TODO");
635 writer.WriteEndElement();
637 writer.WriteEndElement();
641 // Writes XML documenting an operator.
642 private void WriteOperator(XmlTextWriter writer, MethodInfo method)
646 writer.WriteStartElement("operator");
647 writer.WriteAttributeString("name", method.Name + GetParameterTypes(method.GetParameters()));
648 writer.WriteElementString("summary","TODO");
649 writer.WriteElementString("remarks","TODO");
651 foreach (ParameterInfo parameter in method.GetParameters())
653 WriteParameter(writer, parameter);
656 writer.WriteElementString("returnType", method.ReturnType.FullName);
657 writer.WriteStartElement("seealso");
658 writer.WriteAttributeString("cref", "TODO");
659 writer.WriteEndElement();
661 writer.WriteEndElement();
665 // Writes XML documenting a method.
666 private void WriteMethod(XmlTextWriter writer, MethodInfo method, bool inherited)
668 if (!inherited && method != null)
670 writer.WriteStartElement("method");
671 writer.WriteAttributeString("name", method.Name + GetParameterTypes(method.GetParameters()));
672 writer.WriteElementString("summary","TODO");
673 writer.WriteElementString("remarks","TODO");
675 foreach (ParameterInfo parameter in method.GetParameters())
677 WriteParameter(writer, parameter);
680 writer.WriteElementString("returnType", method.ReturnType.FullName);
681 writer.WriteStartElement("seealso");
682 writer.WriteAttributeString("cref", "TODO");
683 writer.WriteEndElement();
685 writer.WriteEndElement();
689 private void WriteParameter(XmlTextWriter writer, ParameterInfo parameter)
691 writer.WriteStartElement("param");
692 writer.WriteAttributeString("name", parameter.Name);
693 writer.WriteString("TODO");
694 writer.WriteEndElement();