docstub.cs: Changed <constructor name=""> to use short form for ctor name.
[mono.git] / mcs / doctools / docstub.cs
1 //      docstub.cs
2 //
3 //      Adam Treat (manyoso@yahoo.com)
4 //      (C) 2002 Adam Treat
5 //
6 //      DocStub is based heavily upon the NDoc project
7 //      ndoc.sourceforge.net
8 //
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.
13
14
15 using System;
16 using System.Collections;
17 using System.Collections.Specialized;
18 using System.Diagnostics;
19 using System.IO;
20 using System.Reflection;
21 using System.Xml;
22 using System.Text;
23
24 namespace Mono.Util
25 {
26         class DocStub
27         {
28                 Assembly assembly;
29                 bool nested;
30                 string assembly_file, directory, language, classname, currentNamespace, docname;
31
32                 void Usage()
33                 {
34                         Console.Write (
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");
39                 }
40
41                 public static void Main(string[] args)
42                 {
43                         DocStub stub = new DocStub(args);
44                 }
45
46                 public DocStub(string [] args)
47                 {
48                         assembly_file = null;
49                         directory = null;
50                         int argc = args.Length;
51
52                         for(int i = 0; i < argc; i++)
53                         {
54                                 string arg = args[i];
55
56                                 // The "/" switch is there for wine users, like me ;-)
57                                 if(arg.StartsWith("-") || arg.StartsWith("/"))
58                                 {
59                                         switch(arg)
60                                         {
61
62                                         case "-d": case "/-d": case "--directory":
63                                                 if((i + 1) >= argc)
64                                                 {
65                                                         Usage();
66                                                         return;
67                                                 }
68                                                 directory = args[++i];
69                                                 continue;
70
71                                         case "-a": case "/-a": case "--assembly":
72                                                 if((i + 1) >= argc)
73                                                 {
74                                                         Usage();
75                                                         return;
76                                                 }
77                                                 assembly_file = args[++i];
78                                                 continue;
79                                         case "-l": case "/-l": case "--language":
80                                                 if((i + 1) >= argc)
81                                                 {
82                                                         Usage();
83                                                         return;
84                                                 }
85                                                 language = args[++i];
86                                                 continue;
87
88                                         default:
89                                                 Usage();
90                                                 return;
91                                         }
92                                 }
93                         }
94
95                         if(assembly_file == null)
96                         {
97                                 Usage();
98                                 return;
99                         } else if(directory == null)
100                         {
101                                 Usage();
102                                 return;
103                         }
104
105                         if (!Directory.Exists(directory) && directory != null)
106                         {
107                 Directory.CreateDirectory(directory);
108             }
109
110                         // Call the main driver to get some things done
111                         MakeXml();
112                 }
113
114                 // Builds an XmlDocument with the reflected metadata
115                 private void MakeXml()
116                 {
117                         try
118                         {
119                                 assembly = LoadAssembly(Path.GetFullPath(assembly_file));
120                         }
121                         catch (Exception e)
122                         {
123                                 Console.WriteLine(e.Message);
124                         }
125                         Write();
126                 }
127
128                 private void Write()
129                 {
130                         foreach(Module module in assembly.GetModules())
131                         {
132                                 WriteNamespaces(module);
133                         }
134                 }
135
136                 private void WriteNamespaces(Module module)
137                 {
138                         Type[] types = module.GetTypes();
139                         StringCollection namespaceNames = GetNamespaceNames(types);
140                         XmlTextWriter dummy = new XmlTextWriter(".temp.xml", null);
141                         foreach (string namespaceName in namespaceNames)
142                         {
143                                 currentNamespace = namespaceName;
144                                 WriteClasses(dummy, types);
145                                 WriteInterfaces(dummy, types);
146                                 WriteStructures(dummy, types);
147                                 WriteDelegates(dummy, types);
148                                 WriteEnumerations(dummy, types);
149                         }
150                         File.Delete(".temp.xml");
151                 }
152
153                 private XmlTextWriter StartDocument()
154                 {
155                         if (!Directory.Exists(directory+"/"+currentNamespace) && directory != null)
156                         {
157                 Directory.CreateDirectory(directory+"/"+currentNamespace);
158             }
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);
166                         return writer;
167                 }
168
169                 private void EndDocument(XmlTextWriter writer)
170                 {
171                         writer.WriteEndElement();
172                         writer.WriteEndDocument();
173                         nested = false;
174                         writer.Close();
175                 }
176
177                 private bool IsDelegate(Type type)
178                 {
179                         return type.BaseType.FullName == "System.Delegate" ||
180                                 type.BaseType.FullName == "System.MulticastDelegate";
181                 }
182
183                 private string GetTypeName(Type type)
184                 {
185                         return type.FullName.Replace('+', '.');
186                 }
187
188                 private StringCollection GetNamespaceNames(Type[] types)
189                 {
190                         StringCollection namespaceNames = new StringCollection();
191
192                         foreach (Type type in types)
193                         {
194                                 if (namespaceNames.Contains(type.Namespace) == false)
195                                 {
196                                         namespaceNames.Add(type.Namespace);
197                                 }
198                         }
199
200                         return namespaceNames;
201                 }
202
203                 private bool IsAlsoAnEvent(Type type, string fullName)
204                 {
205                         bool isEvent = false;
206
207                         BindingFlags bindingFlags =
208                                 BindingFlags.Instance |
209                                 BindingFlags.Static |
210                                 BindingFlags.Public |
211                                 BindingFlags.NonPublic |
212                                 BindingFlags.DeclaredOnly;
213
214                         foreach (EventInfo eventInfo in type.GetEvents(bindingFlags))
215                         {
216                                 if (eventInfo.EventHandlerType.FullName == fullName)
217                                 {
218                                         isEvent = true;
219                                         break;
220                                 }
221                         }
222
223                         return isEvent;
224                 }
225
226                 private bool IsAlsoAnEvent(FieldInfo field)
227                 {
228                         return IsAlsoAnEvent(field.DeclaringType, field.FieldType.FullName);
229                 }
230
231                 private bool IsAlsoAnEvent(PropertyInfo property)
232                 {
233                         return IsAlsoAnEvent(property.DeclaringType, property.PropertyType.FullName);
234                 }
235
236                 // Loads an assembly.
237                 public static Assembly LoadAssembly(string filename)
238                 {
239                         if (!File.Exists(filename))
240                         {
241                                 throw new ApplicationException("can't find assembly " + filename);
242                         }
243
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);
247                         fs.Close();
248
249                         return Assembly.Load(buffer);
250                 }
251
252                 private string GetParameterTypes(ParameterInfo[] parameters)
253                 {
254                         if (parameters.Length != 0) {
255                                 StringBuilder sb = new StringBuilder();
256                                 sb.Append("(");
257                                 foreach (ParameterInfo parameter in parameters)
258                                 {
259                                         sb.Append(GetTypeName(parameter.ParameterType) + ", ");
260                                 }
261                                 sb.Remove(sb.Length-2, 2);
262                                 sb.Append(")");
263                                 return sb.ToString();
264                         } else {
265                                 return "";
266                         }
267                 }
268
269                 private void WriteClasses(XmlTextWriter writer, Type[] types)
270                 {
271                         foreach (Type type in types)
272                         {
273                                 if (type.IsClass && !IsDelegate(type) && type.Namespace.Equals(currentNamespace))
274                                 {
275                                         classname = type.FullName;
276                                         docname = type.Name;
277                                         if (!nested)
278                                         {
279                                                 writer = StartDocument();
280                                                 WriteClass(writer, type);
281                                                 EndDocument(writer);
282                                         } else {
283                                                 WriteClass(writer, type);
284                                         }
285                                 }
286                         }
287                 }
288
289                 private void WriteInterfaces(XmlTextWriter writer, Type[] types)
290                 {
291                         foreach (Type type in types)
292                         {
293                                 if (type.IsInterface && type.Namespace.Equals(currentNamespace))
294                                 {
295                                         classname = type.FullName;
296                                         docname = type.Name;
297                                         if (!nested)
298                                         {
299                                                 writer = StartDocument();
300                                                 WriteInterface(writer, type);
301                                                 EndDocument(writer);
302                                         } else {
303                                                 WriteInterface(writer, type);
304                                         }
305                                 }
306                         }
307                 }
308
309                 private void WriteStructures(XmlTextWriter writer, Type[] types)
310                 {
311                         foreach (Type type in types)
312                         {
313                                 if (type.IsValueType && !type.IsEnum && type.Namespace.Equals(currentNamespace))
314                                 {
315                                         classname = type.FullName;
316                                         docname = type.Name;
317                                         if (!nested)
318                                         {
319                                                 writer = StartDocument();
320                                                 WriteClass(writer, type);
321                                                 EndDocument(writer);
322                                         } else {
323                                                 WriteClass(writer, type);
324                                         }
325                                 }
326                         }
327                 }
328
329                 private void WriteDelegates(XmlTextWriter writer, Type[] types)
330                 {
331                         foreach (Type type in types)
332                         {
333                                 if (type.IsClass && IsDelegate(type) && type.Namespace.Equals(currentNamespace))
334                                 {
335                                         classname = type.FullName;
336                                         docname = type.Name;
337                                         if (!nested)
338                                         {
339                                                 writer = StartDocument();
340                                                 WriteDelegate(writer, type);
341                                                 EndDocument(writer);
342                                         } else {
343                                                 WriteDelegate(writer, type);
344                                         }
345                                 }
346                         }
347                 }
348
349                 private void WriteEnumerations(XmlTextWriter writer, Type[] types)
350                 {
351                         foreach (Type type in types)
352                         {
353                                 if (type.IsEnum && type.Namespace.Equals(currentNamespace))
354                                 {
355                                         classname = type.FullName;
356                                         docname = type.Name;
357                                         if (!nested)
358                                         {
359                                                 writer = StartDocument();
360                                                 WriteEnumeration(writer, type);
361                                                 EndDocument(writer);
362                                         } else {
363                                                 WriteEnumeration(writer, type);
364                                         }
365                                 }
366                         }
367                 }
368
369                 // Writes XML documenting a class or struct.
370                 private void WriteClass(XmlTextWriter writer, Type type)
371                 {
372                         Type[] types = type.GetNestedTypes();
373                         AssemblyName assemblyName = assembly.GetName();
374                         bool isStruct = type.IsValueType;
375                         nested = true;
376
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");
382
383                         WriteClasses(writer, types);
384                         WriteInterfaces(writer, types);
385                         WriteStructures(writer, types);
386                         WriteDelegates(writer, types);
387                         WriteEnumerations(writer, types);
388
389                         WriteConstructors(writer, type);
390                         WriteFields(writer, type);
391                         WriteProperties(writer, type);
392                         WriteMethods(writer, type);
393                         WriteOperators(writer, type);
394                         WriteEvents(writer, type);
395
396                         writer.WriteEndElement();
397                 }
398
399                 // Writes XML documenting an interface.
400                 private void WriteInterface(XmlTextWriter writer, Type type)
401                 {
402                         Type[] types = type.GetNestedTypes();
403                         AssemblyName assemblyName = assembly.GetName();
404
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();
414                 }
415
416                 // Writes XML documenting a delegate.
417                 private void WriteDelegate(XmlTextWriter writer, Type type)
418                 {
419                         Type[] types = type.GetNestedTypes();
420                         AssemblyName assemblyName = assembly.GetName();
421
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();
430
431                         //param
432
433                         writer.WriteEndElement();
434                 }
435
436                 // Writes XML documenting an enumeration.
437                 private void WriteEnumeration(XmlTextWriter writer, Type type)
438                 {
439                         Type[] types = type.GetNestedTypes();
440                         AssemblyName assemblyName = assembly.GetName();
441
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");
447
448                         writer.WriteStartElement("member");
449                         writer.WriteAttributeString("name", "TODO");
450                         writer.WriteEndElement();
451
452                         writer.WriteEndElement();
453                 }
454
455                 private void WriteConstructors(XmlTextWriter writer, Type type)
456                 {
457                         BindingFlags bindingFlags =
458                                 BindingFlags.Instance |
459                                 BindingFlags.Public |
460                                 BindingFlags.NonPublic;
461
462                         ConstructorInfo[] constructors = type.GetConstructors(bindingFlags);
463
464                         foreach (ConstructorInfo constructor in constructors)
465                         {
466                                 WriteConstructor(writer, constructor);
467                         }
468                 }
469
470                 private void WriteFields(XmlTextWriter writer, Type type)
471                 {
472                         BindingFlags bindingFlags =
473                                 BindingFlags.Instance |
474                                 BindingFlags.Static |
475                                 BindingFlags.Public |
476                                 BindingFlags.NonPublic;
477
478                         foreach (FieldInfo field in type.GetFields(bindingFlags))
479                         {
480                                 if (!IsAlsoAnEvent(field))
481                                 {
482                                         WriteField(writer, field);
483                                 }
484                         }
485                 }
486
487                 private void WriteProperties(XmlTextWriter writer, Type type)
488                 {
489                         BindingFlags bindingFlags =
490                                 BindingFlags.Instance |
491                                 BindingFlags.Static |
492                                 BindingFlags.Public |
493                                 BindingFlags.NonPublic;
494
495                         PropertyInfo[] properties = type.GetProperties(bindingFlags);
496
497                         foreach (PropertyInfo property in properties)
498                         {
499                                 MethodInfo getMethod = property.GetGetMethod(true);
500                                 MethodInfo setMethod = property.GetSetMethod(true);
501
502                                 bool hasGetter = (getMethod != null);
503                                 bool hasSetter = (setMethod != null);
504
505                                 if ((hasGetter || hasSetter) && !IsAlsoAnEvent(property))
506                                 {
507                                         WriteProperty(writer, property, property.DeclaringType.FullName != type.FullName);
508                                 }
509                         }
510                 }
511
512                 private void WriteMethods(XmlTextWriter writer, Type type)
513                 {
514                         BindingFlags bindingFlags =
515                                 BindingFlags.Instance |
516                                 BindingFlags.Static |
517                                 BindingFlags.Public |
518                                 BindingFlags.NonPublic;
519
520                         MethodInfo[] methods = type.GetMethods(bindingFlags);
521
522                         foreach (MethodInfo method in methods)
523                         {
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_")))
529                                 {
530                                         WriteMethod(writer, method, method.DeclaringType.FullName != type.FullName);
531                                 }
532                         }
533                 }
534
535                 private void WriteOperators(XmlTextWriter writer, Type type)
536                 {
537                         BindingFlags bindingFlags =
538                                 BindingFlags.Instance |
539                                 BindingFlags.Static |
540                                 BindingFlags.Public |
541                                 BindingFlags.NonPublic;
542
543                         MethodInfo[] methods = type.GetMethods(bindingFlags);
544
545                         foreach (MethodInfo method in methods)
546                         {
547                                 if (method.Name.StartsWith("op_"))
548                                 {
549                                         WriteOperator(writer, method);
550                                 }
551                         }
552                 }
553
554                 private void WriteEvents(XmlTextWriter writer, Type type)
555                 {
556                         BindingFlags bindingFlags =
557                                 BindingFlags.Instance |
558                                 BindingFlags.Static |
559                                 BindingFlags.Public |
560                                 BindingFlags.NonPublic |
561                                 BindingFlags.DeclaredOnly;
562
563                         foreach (EventInfo eventInfo in type.GetEvents(bindingFlags))
564                         {
565                                 MethodInfo addMethod = eventInfo.GetAddMethod(true);
566
567                                 if (addMethod != null)
568                                 {
569                                         WriteEvent(writer, eventInfo);
570                                 }
571                         }
572                 }
573
574                 // Writes XML documenting a field.
575                 private void WriteField(XmlTextWriter writer, FieldInfo field)
576                 {
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();
584
585                         writer.WriteEndElement();
586                 }
587
588                 // Writes XML documenting an event.
589                 private void WriteEvent(XmlTextWriter writer, EventInfo eventInfo)
590                 {
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();
599
600                         writer.WriteEndElement();
601                 }
602
603                 // Writes XML documenting a constructor.
604                 private void WriteConstructor(XmlTextWriter writer, ConstructorInfo constructor)
605                 {
606                         writer.WriteStartElement("constructor");
607                         writer.WriteAttributeString("name", docname + GetParameterTypes(constructor.GetParameters()));
608                         writer.WriteElementString("summary","TODO");
609                         writer.WriteElementString("remarks","TODO");
610
611                         foreach (ParameterInfo parameter in constructor.GetParameters())
612                         {
613                                 WriteParameter(writer, parameter);
614                         }
615
616                         writer.WriteStartElement("seealso");
617                         writer.WriteAttributeString("cref", "TODO");
618                         writer.WriteEndElement();
619
620                         writer.WriteEndElement();
621                 }
622
623                 // Writes XML documenting a property.
624                 private void WriteProperty(XmlTextWriter writer, PropertyInfo property, bool inherited )
625                 {
626                         if (!inherited)
627                         {
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();
636
637                                 writer.WriteEndElement();
638                         }
639                 }
640
641                 // Writes XML documenting an operator.
642                 private void WriteOperator(XmlTextWriter writer, MethodInfo method)
643                 {
644                         if (method != null)
645                         {
646                                 writer.WriteStartElement("operator");
647                                 writer.WriteAttributeString("name", method.Name + GetParameterTypes(method.GetParameters()));
648                                 writer.WriteElementString("summary","TODO");
649                                 writer.WriteElementString("remarks","TODO");
650
651                                 foreach (ParameterInfo parameter in method.GetParameters())
652                                 {
653                                         WriteParameter(writer, parameter);
654                                 }
655
656                                 writer.WriteElementString("returnType", method.ReturnType.FullName);
657                                 writer.WriteStartElement("seealso");
658                                 writer.WriteAttributeString("cref", "TODO");
659                                 writer.WriteEndElement();
660
661                                 writer.WriteEndElement();
662                         }
663                 }
664
665                 // Writes XML documenting a method.
666                 private void WriteMethod(XmlTextWriter writer, MethodInfo method, bool inherited)
667                 {
668                         if (!inherited && method != null)
669                         {
670                                 writer.WriteStartElement("method");
671                                 writer.WriteAttributeString("name", method.Name + GetParameterTypes(method.GetParameters()));
672                                 writer.WriteElementString("summary","TODO");
673                                 writer.WriteElementString("remarks","TODO");
674
675                                 foreach (ParameterInfo parameter in method.GetParameters())
676                                 {
677                                         WriteParameter(writer, parameter);
678                                 }
679
680                                 writer.WriteElementString("returnType", method.ReturnType.FullName);
681                                 writer.WriteStartElement("seealso");
682                                 writer.WriteAttributeString("cref", "TODO");
683                                 writer.WriteEndElement();
684
685                                 writer.WriteEndElement();
686                         }
687                 }
688
689                 private void WriteParameter(XmlTextWriter writer, ParameterInfo parameter)
690                 {
691                         writer.WriteStartElement("param");
692                         writer.WriteAttributeString("name", parameter.Name);
693                         writer.WriteString("TODO");
694                         writer.WriteEndElement();
695                 }
696         }
697 }
698