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);
152 File.Delete(".temp.xml");
155 private XmlTextWriter StartDocument()
157 if (!Directory.Exists(directory+"/"+currentNamespace) && directory != null)
159 Directory.CreateDirectory(directory+"/"+currentNamespace);
161 string filename = directory+"/"+currentNamespace+"/"+docname+".xml";
162 XmlTextWriter writer = new XmlTextWriter (filename, null);
163 writer.Formatting = Formatting.Indented;
164 writer.Indentation=4;
165 writer.WriteStartDocument();
166 writer.WriteStartElement("monodoc");
167 writer.WriteAttributeString("language",language);
171 private void EndDocument(XmlTextWriter writer)
173 writer.WriteEndElement();
174 writer.WriteEndDocument();
179 private bool IsDelegate(Type type)
181 return type.BaseType.FullName == "System.Delegate" ||
182 type.BaseType.FullName == "System.MulticastDelegate";
185 private string GetTypeName(Type type)
187 return type.FullName.Replace('+', '.');
190 private StringCollection GetNamespaceNames(Type[] types)
192 StringCollection namespaceNames = new StringCollection();
194 foreach (Type type in types)
196 if (namespaceNames.Contains(type.Namespace) == false)
198 namespaceNames.Add(type.Namespace);
202 return namespaceNames;
205 private bool IsAlsoAnEvent(Type type, string fullName)
207 bool isEvent = false;
209 BindingFlags bindingFlags =
210 BindingFlags.Instance |
211 BindingFlags.Static |
212 BindingFlags.Public |
213 BindingFlags.NonPublic |
214 BindingFlags.DeclaredOnly;
216 foreach (EventInfo eventInfo in type.GetEvents(bindingFlags))
218 if (eventInfo.EventHandlerType.FullName == fullName)
228 private bool IsAlsoAnEvent(FieldInfo field)
230 return IsAlsoAnEvent(field.DeclaringType, field.FieldType.FullName);
233 private bool IsAlsoAnEvent(PropertyInfo property)
235 return IsAlsoAnEvent(property.DeclaringType, property.PropertyType.FullName);
238 // Loads an assembly.
239 public static Assembly LoadAssembly(string filename)
241 if (!File.Exists(filename))
243 throw new ApplicationException("can't find assembly " + filename);
246 FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read);
247 byte[] buffer = new byte[fs.Length];
248 fs.Read(buffer, 0, (int)fs.Length);
251 return Assembly.Load(buffer);
254 private string GetParameterTypes(ParameterInfo[] parameters)
256 if (parameters.Length != 0) {
257 StringBuilder sb = new StringBuilder();
259 foreach (ParameterInfo parameter in parameters)
261 sb.Append(GetTypeName(parameter.ParameterType) + ", ");
263 sb.Remove(sb.Length-2, 2);
265 return sb.ToString();
271 private void WriteClasses(XmlTextWriter writer, Type[] types)
273 foreach (Type type in types)
275 if (type.IsClass && !IsDelegate(type) && type.Namespace.Equals(currentNamespace))
277 classname = type.FullName;
281 writer = StartDocument();
282 WriteClass(writer, type);
285 WriteClass(writer, type);
291 private void WriteInterfaces(XmlTextWriter writer, Type[] types)
293 foreach (Type type in types)
295 if (type.IsInterface && type.Namespace.Equals(currentNamespace))
297 classname = type.FullName;
301 writer = StartDocument();
302 WriteInterface(writer, type);
305 WriteInterface(writer, type);
311 private void WriteStructures(XmlTextWriter writer, Type[] types)
313 foreach (Type type in types)
315 if (type.IsValueType && !type.IsEnum && type.Namespace.Equals(currentNamespace))
317 classname = type.FullName;
321 writer = StartDocument();
322 WriteClass(writer, type);
325 WriteClass(writer, type);
331 private void WriteDelegates(XmlTextWriter writer, Type[] types)
333 foreach (Type type in types)
335 if (type.IsClass && IsDelegate(type) && type.Namespace.Equals(currentNamespace))
337 classname = type.FullName;
341 writer = StartDocument();
342 WriteDelegate(writer, type);
345 WriteDelegate(writer, type);
351 private void WriteEnumerations(XmlTextWriter writer, Type[] types)
353 foreach (Type type in types)
355 if (type.IsEnum && type.Namespace.Equals(currentNamespace))
357 classname = type.FullName;
361 writer = StartDocument();
362 WriteEnumeration(writer, type);
365 WriteEnumeration(writer, type);
371 // Writes XML documenting a class or struct.
372 private void WriteClass(XmlTextWriter writer, Type type)
374 Type[] types = type.GetNestedTypes();
375 AssemblyName assemblyName = assembly.GetName();
376 bool isStruct = type.IsValueType;
379 writer.WriteStartElement(isStruct ? "struct" : "class");
380 writer.WriteAttributeString("name", type.FullName);
381 writer.WriteAttributeString("assembly", assemblyName.Name);
382 writer.WriteElementString("summary","TODO");
383 writer.WriteElementString("remarks","TODO");
385 WriteClasses(writer, types);
386 WriteInterfaces(writer, types);
387 WriteStructures(writer, types);
388 WriteDelegates(writer, types);
389 WriteEnumerations(writer, types);
391 WriteConstructors(writer, type);
392 WriteFields(writer, type);
393 WriteProperties(writer, type);
394 WriteMethods(writer, type);
395 WriteOperators(writer, type);
396 WriteEvents(writer, type);
398 writer.WriteEndElement();
401 // Writes XML documenting an interface.
402 private void WriteInterface(XmlTextWriter writer, Type type)
404 Type[] types = type.GetNestedTypes();
405 AssemblyName assemblyName = assembly.GetName();
407 writer.WriteStartElement("interface");
408 writer.WriteAttributeString("name", type.FullName);
409 writer.WriteAttributeString("assembly", assemblyName.Name);
410 writer.WriteElementString("summary","TODO");
411 writer.WriteElementString("remarks","TODO");
412 writer.WriteEndElement();
415 // Writes XML documenting a delegate.
416 private void WriteDelegate(XmlTextWriter writer, Type type)
418 Type[] types = type.GetNestedTypes();
419 AssemblyName assemblyName = assembly.GetName();
421 writer.WriteStartElement("delegate");
422 writer.WriteAttributeString("name", type.FullName);
423 writer.WriteAttributeString("assembly", assemblyName.Name);
424 writer.WriteElementString("summary","TODO");
425 writer.WriteElementString("remarks","TODO");
429 writer.WriteEndElement();
432 // Writes XML documenting an enumeration.
433 private void WriteEnumeration(XmlTextWriter writer, Type type)
435 Type[] types = type.GetNestedTypes();
436 AssemblyName assemblyName = assembly.GetName();
438 writer.WriteStartElement("enum");
439 writer.WriteAttributeString("name", type.FullName);
440 writer.WriteAttributeString("assembly", assemblyName.Name);
441 writer.WriteElementString("summary","TODO");
442 writer.WriteElementString("remarks","TODO");
444 writer.WriteStartElement("member");
445 writer.WriteAttributeString("name", "TODO");
446 writer.WriteEndElement();
448 writer.WriteEndElement();
451 private void WriteConstructors(XmlTextWriter writer, Type type)
453 BindingFlags bindingFlags =
454 BindingFlags.Instance |
455 BindingFlags.Public |
456 BindingFlags.NonPublic;
458 ConstructorInfo[] constructors = type.GetConstructors(bindingFlags);
460 foreach (ConstructorInfo constructor in constructors)
462 WriteConstructor(writer, constructor);
466 private void WriteFields(XmlTextWriter writer, Type type)
468 BindingFlags bindingFlags =
469 BindingFlags.Instance |
470 BindingFlags.Static |
471 BindingFlags.Public |
472 BindingFlags.NonPublic;
474 foreach (FieldInfo field in type.GetFields(bindingFlags))
476 if (!IsAlsoAnEvent(field))
478 WriteField(writer, field);
483 private void WriteProperties(XmlTextWriter writer, Type type)
485 BindingFlags bindingFlags =
486 BindingFlags.Instance |
487 BindingFlags.Static |
488 BindingFlags.Public |
489 BindingFlags.NonPublic;
491 PropertyInfo[] properties = type.GetProperties(bindingFlags);
493 foreach (PropertyInfo property in properties)
495 MethodInfo getMethod = property.GetGetMethod(true);
496 MethodInfo setMethod = property.GetSetMethod(true);
498 bool hasGetter = (getMethod != null);
499 bool hasSetter = (setMethod != null);
501 if ((hasGetter || hasSetter) && !IsAlsoAnEvent(property))
503 WriteProperty(writer, property, property.DeclaringType.FullName != type.FullName);
508 private void WriteMethods(XmlTextWriter writer, Type type)
510 BindingFlags bindingFlags =
511 BindingFlags.Instance |
512 BindingFlags.Static |
513 BindingFlags.Public |
514 BindingFlags.NonPublic;
516 MethodInfo[] methods = type.GetMethods(bindingFlags);
518 foreach (MethodInfo method in methods)
520 if (!(method.Name.StartsWith("get_")) &&
521 !(method.Name.StartsWith("set_")) &&
522 !(method.Name.StartsWith("add_")) &&
523 !(method.Name.StartsWith("remove_")) &&
524 !(method.Name.StartsWith("op_")))
526 WriteMethod(writer, method, method.DeclaringType.FullName != type.FullName);
531 private void WriteOperators(XmlTextWriter writer, Type type)
533 BindingFlags bindingFlags =
534 BindingFlags.Instance |
535 BindingFlags.Static |
536 BindingFlags.Public |
537 BindingFlags.NonPublic;
539 MethodInfo[] methods = type.GetMethods(bindingFlags);
541 foreach (MethodInfo method in methods)
543 if (method.Name.StartsWith("op_"))
545 WriteOperator(writer, method);
550 private void WriteEvents(XmlTextWriter writer, Type type)
552 BindingFlags bindingFlags =
553 BindingFlags.Instance |
554 BindingFlags.Static |
555 BindingFlags.Public |
556 BindingFlags.NonPublic |
557 BindingFlags.DeclaredOnly;
559 foreach (EventInfo eventInfo in type.GetEvents(bindingFlags))
561 MethodInfo addMethod = eventInfo.GetAddMethod(true);
563 if (addMethod != null)
565 WriteEvent(writer, eventInfo);
570 // Writes XML documenting a field.
571 private void WriteField(XmlTextWriter writer, FieldInfo field)
573 writer.WriteStartElement("field");
574 writer.WriteAttributeString("name", field.Name);
575 writer.WriteElementString("summary","TODO");
576 writer.WriteElementString("remarks","TODO");
577 writer.WriteEndElement();
580 // Writes XML documenting an event.
581 private void WriteEvent(XmlTextWriter writer, EventInfo eventInfo)
583 writer.WriteStartElement("event");
584 writer.WriteAttributeString("name", eventInfo.Name);
585 writer.WriteElementString("summary","TODO");
586 writer.WriteElementString("remarks","TODO");
587 writer.WriteElementString("data","TODO");
589 writer.WriteEndElement();
592 // Writes XML documenting a constructor.
593 private void WriteConstructor(XmlTextWriter writer, ConstructorInfo constructor)
595 writer.WriteStartElement("constructor");
596 writer.WriteAttributeString("name", docname + GetParameterTypes(constructor.GetParameters()));
597 writer.WriteElementString("summary","TODO");
598 writer.WriteElementString("remarks","TODO");
600 foreach (ParameterInfo parameter in constructor.GetParameters())
602 WriteParameter(writer, parameter);
606 writer.WriteEndElement();
609 // Writes XML documenting a property.
610 private void WriteProperty(XmlTextWriter writer, PropertyInfo property, bool inherited )
614 writer.WriteStartElement("property");
615 writer.WriteAttributeString("name", property.Name);
616 writer.WriteElementString("summary","TODO");
617 writer.WriteElementString("remarks","TODO");
618 writer.WriteElementString("value","TODO");
620 writer.WriteEndElement();
624 // Writes XML documenting an operator.
625 private void WriteOperator(XmlTextWriter writer, MethodInfo method)
629 writer.WriteStartElement("operator");
630 writer.WriteAttributeString("name", method.Name + GetParameterTypes(method.GetParameters()));
631 writer.WriteElementString("summary","TODO");
632 writer.WriteElementString("remarks","TODO");
634 foreach (ParameterInfo parameter in method.GetParameters())
636 WriteParameter(writer, parameter);
639 writer.WriteElementString("returns", "TODO");
641 writer.WriteEndElement();
645 // Writes XML documenting a method.
646 private void WriteMethod(XmlTextWriter writer, MethodInfo method, bool inherited)
648 if (!inherited && method != null)
650 writer.WriteStartElement("method");
651 writer.WriteAttributeString("name", method.Name + GetParameterTypes(method.GetParameters()));
652 writer.WriteElementString("summary","TODO");
653 writer.WriteElementString("remarks","TODO");
655 foreach (ParameterInfo parameter in method.GetParameters())
657 WriteParameter(writer, parameter);
660 writer.WriteElementString("returns", "TODO");
662 writer.WriteEndElement();
666 private void WriteParameter(XmlTextWriter writer, ParameterInfo parameter)
668 writer.WriteStartElement("param");
669 writer.WriteAttributeString("name", parameter.Name);
670 writer.WriteString("TODO");
671 writer.WriteEndElement();