New test.
[mono.git] / mcs / class / Mono.C5 / doc / docnet.cs
1 /*\r
2  Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft\r
3  Permission is hereby granted, free of charge, to any person obtaining a copy\r
4  of this software and associated documentation files (the "Software"), to deal\r
5  in the Software without restriction, including without limitation the rights\r
6  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
7  copies of the Software, and to permit persons to whom the Software is\r
8  furnished to do so, subject to the following conditions:\r
9  \r
10  The above copyright notice and this permission notice shall be included in\r
11  all copies or substantial portions of the Software.\r
12  \r
13  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
14  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
15  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
16  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
17  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
18  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
19  SOFTWARE.\r
20 */\r
21 \r
22 // DocNet.cs\r
23 // Author: Antonio Cisternino\r
24 // Version: 0.1\r
25 // Last update: 5/12/2001\r
26 // Modified Jan 2004 by kokholm@itu.dk\r
27 \r
28 using System;\r
29 using System.IO;\r
30 using System.Reflection;\r
31 using System.Xml;\r
32 using System.Text;\r
33 using System.Diagnostics;\r
34 \r
35 namespace DocNet\r
36 {\r
37   class DocNet\r
38   {\r
39     private Assembly assembly;\r
40 \r
41     //private XmlDocument xml;\r
42 \r
43     private string defaultNamespace;\r
44 \r
45     private string assemblyName;\r
46 \r
47     private static C5.HashDictionary<string, string> longtype2short;\r
48 \r
49     private static C5.HashDictionary<string, XmlNode> cachedDocComments;\r
50 \r
51     static DocNet()\r
52     {\r
53       longtype2short = new C5.HashDictionary<string, string>();\r
54       cachedDocComments = new C5.HashDictionary<string, XmlNode>();\r
55       longtype2short.Add("System.Boolean", "bool");\r
56       longtype2short.Add("System.Byte", "byte");\r
57       longtype2short.Add("System.Int32", "int");\r
58       longtype2short.Add("System.Double", "double");\r
59       longtype2short.Add("System.Void", "void");\r
60       longtype2short.Add("System.Object", "object");\r
61       longtype2short.Add("System.String", "string");\r
62       longtype2short.Add("System.Collections.Generic.IEnumerable{T}", "IEnumerable{T}");\r
63       longtype2short.Add("System.Collections.Generic.IEnumerable{U}", "IEnumerable{U}");\r
64       //longtype2short.Add("", "");\r
65     }\r
66 \r
67 \r
68     DocNet(string a, string x, string defaultNamespace)\r
69     {\r
70       this.defaultNamespace = defaultNamespace;\r
71       assembly = Assembly.LoadFrom(a, null);\r
72       XmlDocument xml = new XmlDocument();\r
73       xml.Load(x);\r
74       assemblyName = xml.SelectSingleNode("doc/assembly/name").InnerXml;\r
75 \r
76       if (!assembly.FullName.StartsWith(assemblyName + ","))\r
77         throw new Exception("Wrong assembly specified!\n>> " + assembly.FullName + "\n>> " + assemblyName);\r
78 \r
79       foreach (XmlNode node in xml.SelectNodes("doc/members/member"))\r
80         cachedDocComments.Add(node.SelectNodes("@name").Item(0).Value, node);\r
81     }\r
82 \r
83 \r
84     private void CopyCodeDoc(XmlElement p, string xpath, XmlDocument ret)\r
85     {\r
86       XmlNode n;\r
87       //xml.SelectSingleNode(xpath);\r
88 \r
89       if (cachedDocComments.Find(xpath, out n))\r
90       {\r
91         foreach (XmlNode child in n.ChildNodes)\r
92           p.AppendChild(ret.ImportNode(child, true));\r
93       }\r
94       //else\r
95       //  Console.Error.WriteLine("docNet: {0} not found", xpath);\r
96     }\r
97 \r
98     string xmlClean(string s)\r
99     {\r
100 //            return s.Replace("&", "&amp;").Replace("{", "&lt;").Replace("}", "&gt;").Replace("<", "&lt;").Replace(">", "&gt;");\r
101       return s.Replace("{", "<").Replace("}", ">");\r
102     }\r
103 \r
104     private void AddSignature(XmlElement p, string signtext, XmlDocument ret)\r
105     {\r
106       XmlElement sign = CreateElement(ret, "Signature");\r
107 \r
108       try\r
109       {\r
110         sign.InnerXml = signtext.Replace("&", "&amp;").Replace("{", "&lt;").Replace("}", "&gt;").Replace("<", "&lt;").Replace(">", "&gt;");\r
111       }\r
112       catch (XmlException)\r
113       {\r
114         Console.Error.WriteLine(signtext);\r
115       }\r
116       p.AppendChild(sign);\r
117     }\r
118 \r
119     private void addImplements(XmlElement p, Type t, XmlDocument ret)\r
120     {\r
121       foreach (Type ty in t.GetInterfaces())\r
122       {\r
123         XmlElement impl = CreateElement(ret, "Implements");\r
124 \r
125         if (ty.Assembly == assembly)\r
126         {\r
127           impl.SetAttribute("refid", "T:" + canonicalTypeName(ty, null));\r
128           impl.SetAttribute("C5", "");\r
129         }\r
130         AddSignature(impl, prettyTypeName(ty), ret);\r
131         p.AppendChild(impl);\r
132       }\r
133     }\r
134 \r
135     private void addBases(XmlElement p, Type t, XmlDocument ret)\r
136     {\r
137       Type ty = t.BaseType;\r
138 \r
139       while (ty != null)\r
140       {\r
141         XmlElement @base = CreateElement(ret, "Bases");\r
142 \r
143         if (ty.Assembly == assembly)\r
144         {\r
145           @base.SetAttribute("refid", "T:" + canonicalTypeName(ty, null));\r
146           @base.SetAttribute("C5", "");\r
147         }\r
148 \r
149         AddSignature(@base, prettyTypeName(ty), ret);\r
150         p.PrependChild(@base);\r
151         ty = ty.BaseType;\r
152       }\r
153     }\r
154 \r
155 \r
156 \r
157     private XmlElement CreateElement(XmlDocument ret, string name)\r
158     {\r
159       return ret.CreateElement(null, name, null);\r
160     }\r
161 \r
162     private void VisitField(bool inherited, FieldInfo f, XmlElement type, XmlDocument refman)\r
163     {\r
164       if (f.Name.Equals("value__"))\r
165         return;\r
166       string refid = "F:" + canonicalTypeName(f.DeclaringType, null) + "." + f.Name;\r
167       //string xpath = "doc/members/member[@name = \"" + refid + "\"]";\r
168       XmlElement el = CreateElement(refman, "Field");\r
169 \r
170       el.SetAttribute("Name", f.Name);\r
171       el.SetAttribute("refid", refid);\r
172       el.SetAttribute("Static", f.IsStatic.ToString());\r
173       el.SetAttribute("Declared", xmlClean(prettyTypeName(f.DeclaringType)));\r
174       el.SetAttribute("CDeclared", canonicalTypeName(f.DeclaringType, null));\r
175       el.SetAttribute("Type", xmlClean(prettyTypeName(f.FieldType)));\r
176       el.SetAttribute("Access", f.IsPublic ? "public" : (f.IsPrivate || f.IsAssembly ? "private" : "protected"));\r
177       if (f.DeclaringType.Assembly == assembly)\r
178         el.SetAttribute("C5", "");\r
179 \r
180       if (inherited)\r
181         el.SetAttribute("Inherited", "");\r
182 \r
183       AddSignature(el, /*prettyTypeName(f.FieldType) + " " +*/ f.Name, refman);\r
184       CopyCodeDoc(el, refid, refman);\r
185       //AddSummary(el, xpath + "/summary", ret, doc);\r
186       type.AppendChild(el);\r
187     }\r
188 \r
189     private void VisitEvent(bool inherited, EventInfo e, XmlElement type, XmlDocument ret)\r
190     {\r
191       string refid = "E:" + canonicalTypeName(e.DeclaringType, null) + "." + e.Name;\r
192       //string xpath = "doc/members/member[@name = \"" + refid + "\"]";\r
193       XmlElement el = CreateElement(ret, "Event");\r
194 \r
195       el.SetAttribute("Name", e.Name);\r
196       el.SetAttribute("refid", refid);\r
197       //el.SetAttribute("Static", f.IsStatic.ToString());\r
198       //TODO: check virtual and final values on adders/removers\r
199       //el.SetAttribute("Virtual", e..IsVirtual.ToString());\r
200       //el.SetAttribute("Final", e.IsFinal.ToString());\r
201       el.SetAttribute("Declared", xmlClean(prettyTypeName(e.DeclaringType)));\r
202       el.SetAttribute("CDeclared", canonicalTypeName(e.DeclaringType, null));\r
203       el.SetAttribute("Type", xmlClean(prettyTypeName(e.EventHandlerType)));\r
204       MethodInfo addMethod = e.GetAddMethod(true);\r
205       el.SetAttribute("Access", addMethod.IsPublic ? "public" : addMethod.IsFamily ? "protected" : "private");//NBNBNB! e.IsPublic ? "public" : (e.IsPrivate || e.IsAssembly ? "private" : "protected"));\r
206       if (e.DeclaringType.Assembly == assembly)\r
207         el.SetAttribute("C5", "");\r
208 \r
209       if (inherited)\r
210         el.SetAttribute("Inherited", "");\r
211 \r
212       AddSignature(el, /*prettyTypeName(e.EventHandlerType) + " " +*/ e.Name, ret);\r
213       CopyCodeDoc(el, refid, ret);\r
214       //AddSummary(el, xpath + "/summary", ret, doc);\r
215       type.AppendChild(el);\r
216     }\r
217 \r
218 \r
219     private void VisitProperty(bool inherited, PropertyInfo p, XmlElement type, XmlDocument ret)\r
220     {\r
221       string refid = "P:" + canonicalPropertyName(p);\r
222       string xpath = "doc/members/member[@name = \"" + refid + "\"]";\r
223       XmlElement el = CreateElement(ret, "Property");\r
224 \r
225       el.SetAttribute("Name", p.Name);\r
226       el.SetAttribute("refid", refid);\r
227       el.SetAttribute("Access", "public");//TODO: check if reasonable\r
228       MethodInfo m = p.CanRead ? p.GetGetMethod() : p.GetSetMethod();\r
229       if (m != null)\r
230       {\r
231         el.SetAttribute("Static", m.IsStatic.ToString());\r
232         el.SetAttribute("Abstract", m.IsAbstract.ToString());\r
233         el.SetAttribute("Virtual", m.IsVirtual.ToString());\r
234         el.SetAttribute("Final", m.IsFinal.ToString());\r
235       }\r
236       //else\r
237       //Console.Error.WriteLine("%%%%% {0} | {1}", p, p.DeclaringType);\r
238       el.SetAttribute("Declared", xmlClean(prettyTypeName(p.DeclaringType)));\r
239       el.SetAttribute("CDeclared", canonicalTypeName(p.DeclaringType, null));\r
240       el.SetAttribute("Get", p.CanRead.ToString());\r
241       el.SetAttribute("Set", p.CanWrite.ToString());\r
242       el.SetAttribute("Type", xmlClean(prettyTypeName(p.PropertyType)));\r
243 \r
244       if (p.DeclaringType.Assembly == assembly)\r
245         el.SetAttribute("C5", "");\r
246 \r
247       if (inherited)\r
248         el.SetAttribute("Inherited", "");\r
249 \r
250       if (p.Name.Equals("Item"))\r
251         AddSignature(el, prettyIndexerSignature(p), ret);\r
252       else\r
253         AddSignature(el, /*prettyTypeName(p.PropertyType) + " " +*/ p.Name, ret);\r
254 \r
255       //AddSummary(el, xpath + "/summary", ret, doc);\r
256       CopyCodeDoc(el, refid, ret);\r
257       //AddValue(el, xpath + "/value", ret, doc);\r
258       VisitParameters(p.GetIndexParameters(), el, ret, xpath);\r
259       type.AppendChild(el);\r
260     }\r
261 \r
262 \r
263     private void VisitParameters(ParameterInfo[] pars, XmlElement n, XmlDocument ret, string xpath)\r
264     {\r
265       foreach (ParameterInfo p in pars)\r
266       {\r
267         XmlElement el = CreateElement(ret, "Parameter");\r
268 \r
269         el.SetAttribute("Name", p.Name);\r
270         el.SetAttribute("Type", prettyTypeName(p.ParameterType));\r
271         //AddSummary(el, xpath + "/param[@name = \"" + p.Name + "\"]", ret, doc);\r
272         CopyCodeDoc(el, xpath + "/param[@name = \"" + p.Name + "\"]", ret);\r
273 \r
274         n.AppendChild(el);\r
275       }\r
276     }\r
277 \r
278 \r
279     private void VisitConstructor(Type t, ConstructorInfo c, XmlElement type, XmlDocument ret)\r
280     {\r
281       Type declaringType = c.DeclaringType;\r
282       string refid = "M:" + canonicalTypeName(c.DeclaringType, null) + "." + "#ctor";\r
283 \r
284       refid += canonicalParameters(c.GetParameters(), new string[]{});\r
285 \r
286       string xpath = "doc/members/member[@name = \"" + refid + "\"]";\r
287       XmlElement el = CreateElement(ret, "Constructor");\r
288       el.SetAttribute("Foo", c.IsConstructor ? "Con" : "San");\r
289       el.SetAttribute("refid", refid);\r
290       el.SetAttribute("Declared", prettyTypeName(declaringType));\r
291       el.SetAttribute("CDeclared", canonicalTypeName(declaringType, null));\r
292       el.SetAttribute("Access", c.IsPublic ? "public" : (c.IsPrivate ? "private" : "protected"));\r
293       //el.SetAttribute("Access", c.IsPublic ? "public" : (c.IsPrivate || c.IsAssembly ? "private" : "protected"));\r
294       if (declaringType.Assembly == assembly)\r
295         el.SetAttribute("C5", "");\r
296       if (declaringType != t)\r
297         el.SetAttribute("Inherited", "");\r
298       AddSignature(el, prettyConstructorSignature(c), ret);\r
299       CopyCodeDoc(el, refid, ret);\r
300       //AddSummary(el, xpath + "/summary", ret, doc);\r
301       VisitParameters(c.GetParameters(), el, ret, xpath);\r
302       type.AppendChild(el);\r
303     }\r
304 \r
305 \r
306     private void VisitMethod(bool inherited, MethodInfo m, XmlElement type, XmlDocument ret)\r
307     {\r
308       if (m.Name.StartsWith("get_") || m.Name.StartsWith("set_") || m.Name.StartsWith("add_") || m.Name.StartsWith("remove_"))\r
309         return;\r
310       bool isOperator = m.Name.StartsWith("op_");\r
311 \r
312       string refid = "M:" + canonicalMethodName(m);\r
313 \r
314       string xpath = "doc/members/member[@name = \"" + refid + "\"]";\r
315       XmlElement el = CreateElement(ret, isOperator ? "Operator" : "Method");\r
316 \r
317       string mangledName = m.Name;\r
318       if (isOperator)\r
319       {\r
320         switch (mangledName)\r
321         {\r
322           case "op_Equality": mangledName = "operator =="; break;\r
323           case "op_Inequality": mangledName = "operator !="; break;\r
324           default: throw new ApplicationException("unknown operatorname, " + mangledName);\r
325         }\r
326       }\r
327       el.SetAttribute("Name", mangledName);\r
328       el.SetAttribute("refid", refid);\r
329       el.SetAttribute("Static", m.IsStatic.ToString());\r
330       el.SetAttribute("Abstract", m.IsAbstract.ToString());\r
331       el.SetAttribute("Virtual", m.IsVirtual.ToString());\r
332       el.SetAttribute("Final", m.IsFinal.ToString());\r
333       el.SetAttribute("Declared", xmlClean(prettyTypeName(m.DeclaringType)));\r
334       el.SetAttribute("CDeclared", canonicalTypeName(m.DeclaringType, null));\r
335       el.SetAttribute("ReturnType", xmlClean(prettyTypeName(m.ReturnType)));\r
336       if (m.DeclaringType.Assembly == assembly)\r
337         el.SetAttribute("C5", "");\r
338       if (inherited)\r
339         el.SetAttribute("Inherited", "");\r
340       el.SetAttribute("Access", m.IsPublic ? "public" : (m.IsPrivate || m.IsAssembly ? "private" : "protected"));\r
341       el.SetAttribute("Sealed", m.IsFinal.ToString());\r
342       AddSignature(el, prettyMethodSignature(mangledName, m), ret);\r
343       CopyCodeDoc(el, refid, ret);\r
344       VisitParameters(m.GetParameters(), el, ret, xpath);\r
345 \r
346       foreach (Type gp in m.GetGenericArguments())\r
347         foreach (Type gc in gp.GetGenericParameterConstraints())\r
348           if (gc != typeof(object))\r
349           {\r
350             XmlElement constraint = CreateElement(ret, "constraint");\r
351             constraint.SetAttribute("Value", prettyTypeName(gp) + " : " + xmlClean(prettyTypeName(gc)));\r
352             el.AppendChild(constraint);\r
353           }\r
354       type.AppendChild(el);\r
355     }\r
356 \r
357     public XmlDocument GenerateDoc()\r
358     {\r
359       BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic;\r
360 \r
361       XmlDocument ret = new XmlDocument();\r
362       XmlElement root = CreateElement(ret, "Assembly");\r
363 \r
364       root.SetAttribute("Name", assemblyName);\r
365 \r
366       ret.AppendChild(root);\r
367 \r
368       XmlElement type = null;\r
369       //string xpath = null;\r
370 \r
371       foreach (Type t in assembly.GetTypes())\r
372       {\r
373         if (t.Name.StartsWith("DocNet"))\r
374           continue;\r
375 \r
376         if (t.IsInterface)\r
377         {\r
378           type = CreateElement(ret, "Interface");\r
379           foreach (EventInfo e in t.GetEvents(flags))\r
380             VisitEvent(e.DeclaringType != t, e, type, ret);\r
381 \r
382           foreach (PropertyInfo p in t.GetProperties(flags))\r
383             VisitProperty(false, p, type, ret);\r
384 \r
385           foreach (MethodInfo m in t.GetMethods(flags))\r
386             VisitMethod(false, m, type, ret);\r
387         }\r
388         else if (t.IsValueType)\r
389         {\r
390           type = CreateElement(ret, "Struct");\r
391           foreach (FieldInfo f in t.GetFields(flags))\r
392             VisitField(f.DeclaringType != t, f, type, ret);\r
393 \r
394           foreach (EventInfo e in t.GetEvents(flags))\r
395             VisitEvent(e.DeclaringType != t, e, type, ret);\r
396 \r
397           foreach (PropertyInfo p in t.GetProperties(flags))\r
398             VisitProperty(p.DeclaringType != t, p, type, ret);\r
399 \r
400           foreach (ConstructorInfo c in t.GetConstructors(flags))\r
401             VisitConstructor(t, c, type, ret);\r
402 \r
403           foreach (MethodInfo m in t.GetMethods(flags))\r
404             VisitMethod(m.DeclaringType != t, m, type, ret);\r
405         }\r
406         else if (t.IsSubclassOf(typeof(Delegate)))\r
407         {\r
408           type = CreateElement(ret, "Delegate");\r
409           VisitMethod(false, t.GetMethod("Invoke"), type, ret);\r
410         }\r
411         else\r
412         { // Class\r
413           type = CreateElement(ret, "Class");\r
414           foreach (FieldInfo f in t.GetFields(flags))\r
415             VisitField(f.DeclaringType != t, f, type, ret);\r
416 \r
417           foreach (EventInfo e in t.GetEvents(flags))\r
418             VisitEvent(e.DeclaringType != t, e, type, ret);\r
419 \r
420           foreach (PropertyInfo p in t.GetProperties(flags))\r
421             VisitProperty(p.DeclaringType != t, p, type, ret);\r
422 \r
423           foreach (ConstructorInfo c in t.GetConstructors(flags))\r
424             VisitConstructor(t, c, type, ret);\r
425 \r
426           foreach (MethodInfo m in t.GetMethods(flags))\r
427             VisitMethod(m.DeclaringType != t, m, type, ret);\r
428         }\r
429 \r
430         type.SetAttribute("Name", xmlClean(prettyTypeName(t)));\r
431         type.SetAttribute("Access", t.IsPublic || t.IsNestedPublic ? "public" : t.IsNestedFamily ? "protected" : "private");\r
432 \r
433         string refid = "T:" + canonicalTypeName(t, null);\r
434 \r
435         type.SetAttribute("refid", refid);\r
436         type.SetAttribute("C5", "");\r
437         AddSignature(type, prettyTypeName(t), ret);\r
438         addImplements(type, t, ret);\r
439         addBases(type, t, ret);\r
440 \r
441         foreach (Type gp in t.GetGenericArguments())\r
442         {\r
443           if (gp.GenericParameterAttributes != GenericParameterAttributes.None)\r
444           {\r
445             XmlElement constraint = CreateElement(ret, "constraint");\r
446             string constraintText = null;\r
447             switch (gp.GenericParameterAttributes)\r
448             {\r
449               case GenericParameterAttributes.Contravariant:\r
450                 break;\r
451               case GenericParameterAttributes.Covariant:\r
452                 break;\r
453               case GenericParameterAttributes.DefaultConstructorConstraint:\r
454                 constraintText = "new()";\r
455                 break;\r
456               case GenericParameterAttributes.None:\r
457                 break;\r
458               case GenericParameterAttributes.ReferenceTypeConstraint:\r
459                 constraintText = "class";\r
460                 break;\r
461               case GenericParameterAttributes.SpecialConstraintMask:\r
462                 break;\r
463               case GenericParameterAttributes.NotNullableValueTypeConstraint:\r
464                 constraintText = "struct";\r
465                 break;\r
466               case GenericParameterAttributes.VarianceMask:\r
467                 break;\r
468             }\r
469             constraint.SetAttribute("Value", String.Format("{0} : {1}", gp, constraintText));\r
470             type.AppendChild(constraint);\r
471           }\r
472           foreach (Type gc in gp.GetGenericParameterConstraints())\r
473           {\r
474             if (gc != typeof(object))\r
475             {\r
476               XmlElement constraint = CreateElement(ret, "constraint");\r
477               constraint.SetAttribute("Value", String.Format("{0} : {1}", prettyTypeName(gp), xmlClean(prettyTypeName(gc))));\r
478               type.AppendChild(constraint);\r
479             }\r
480           }\r
481         }\r
482 \r
483         CopyCodeDoc(type, refid, ret);\r
484         root.AppendChild(type);\r
485       }\r
486 \r
487       return ret;\r
488     }\r
489 \r
490     C5.HashDictionary<Type, string> t2ptn = new C5.HashDictionary<Type, string>();\r
491     private string prettyTypeName(Type t)\r
492     {\r
493       string retval;\r
494       //if (!t2ptn.Find(t, out retval))\r
495       //{\r
496       int consumed = 0;\r
497       retval = prettyTypeName(t, ref consumed);\r
498       //    t2ptn.Add(t, retval);\r
499       //}\r
500       return retval;\r
501     }\r
502 \r
503     private string prettyTypeName(Type t, ref int consumed)\r
504     {\r
505       StringBuilder ret = new StringBuilder();\r
506 \r
507       if (t.IsGenericParameter)\r
508         ret.Append(t.Name);\r
509       else if (t.IsArray)\r
510         ret.Append(prettyTypeName(t.GetElementType()) + "[]");\r
511       else if (t.IsByRef)\r
512         ret.Append("ref ").Append(prettyTypeName(t.GetElementType()));\r
513       else if (!t.IsGenericType)\r
514         ret.Append(t.IsNested ? prettyTypeName(t.DeclaringType, ref consumed) + "." + t.Name : t.FullName);\r
515       else\r
516       {\r
517         bool first = true;\r
518         StringBuilder gps = new StringBuilder();\r
519         Type[] gp = t.GetGenericArguments();\r
520 \r
521         ret.Append(t.IsNested ? prettyTypeName(t.DeclaringType, ref consumed) : t.Namespace).Append(".").Append(t.Name);\r
522         if (consumed < gp.Length)\r
523         {\r
524           //TODO: fix this ugly hack to remove `n \r
525           ret.Remove(ret.Length - 2, 2);\r
526           //ret = ret.Substring(0, ret.Length - 2);\r
527           for (int i = consumed, length = gp.Length; i < length; i++)\r
528           {\r
529             Type ty = gp[i];\r
530 \r
531             if (first) first = false;\r
532             else\r
533               gps.Append(",");\r
534 \r
535             gps.Append(prettyTypeName(ty));\r
536           }\r
537 \r
538           consumed = gp.Length;\r
539           ret.Append("{").Append(gps.ToString()).Append("}");\r
540         }\r
541       }\r
542 \r
543       string retval = ret.ToString();\r
544 \r
545       if (retval.StartsWith(defaultNamespace + "."))\r
546         retval = retval.Substring(defaultNamespace.Length + 1);\r
547 \r
548       if (longtype2short.Contains(retval))\r
549         retval = longtype2short[retval];\r
550 \r
551       return retval;\r
552     }\r
553 \r
554     private string prettyParameters(ParameterInfo[] pars)\r
555     {\r
556       string ret = "";\r
557       bool first = true;\r
558 \r
559       foreach (ParameterInfo p in pars)\r
560       {\r
561         if (first) first = false;\r
562         else\r
563           ret += ", ";\r
564         Type pt = p.ParameterType;\r
565         if (p.IsOut)\r
566         {\r
567           ret += "out ";\r
568           pt = pt.GetElementType();\r
569         }\r
570 \r
571         ret += prettyTypeName(pt) + " " + p.Name;\r
572       }\r
573 \r
574       return ret;\r
575     }\r
576 \r
577     private string prettyMethodSignature(string name, MethodInfo m)\r
578     {\r
579       string gp = "";\r
580       if (m.IsGenericMethod)\r
581       {\r
582         Type[] gps = m.GetGenericArguments();\r
583         gp = "<";\r
584 \r
585         for (int i = 0; i < gps.Length; i++)\r
586           gp += (i == 0 ? "" : ",") + gps[i].Name;\r
587 \r
588         gp += ">";\r
589       }\r
590 \r
591       return name + gp + "(" + prettyParameters(m.GetParameters()) + ")";\r
592     }\r
593 \r
594     private string prettyConstructorSignature(ConstructorInfo c)\r
595     {\r
596       Type t = c.DeclaringType;\r
597 \r
598       return prettyTypeName(t) + "(" + prettyParameters(c.GetParameters()) + ")";\r
599     }\r
600 \r
601     private string prettyIndexerSignature(PropertyInfo p)\r
602     {\r
603       return /*prettyTypeName(p.PropertyType) + " " + */ "this[" + prettyParameters(p.GetIndexParameters()) + "]";\r
604     }\r
605 \r
606 \r
607     private string simpleTypeName(Type t)\r
608     {\r
609       return (t.IsNested ? simpleTypeName(t.DeclaringType) : t.Namespace) + "." + t.Name;\r
610     }\r
611 \r
612 \r
613     private string canonicalTypeName(Type t, string[] mgps)\r
614     {\r
615       string ret;\r
616 \r
617       if (t.IsGenericParameter)\r
618         ret = "`" + t.GenericParameterPosition;\r
619       else if (t.IsArray)\r
620         ret = canonicalTypeName(t.GetElementType(), mgps) + "[]";\r
621       else if (t.IsByRef)\r
622         ret = canonicalTypeName(t.GetElementType(), mgps) + "@";\r
623       else\r
624       {\r
625         ret = simpleTypeName(t);\r
626         if (!t.IsGenericType)\r
627           ret += "";\r
628         else if (mgps == null)\r
629           ret += "";//"`" + t.GetGenericArguments().Length;\r
630         else\r
631         {\r
632           //TODO: fix this ugly hack to remove `n \r
633           ret = ret.Substring(0, ret.Length - 2);\r
634 \r
635           bool first = true;\r
636           string gps = "";\r
637           Type[] gp = t.GetGenericArguments();\r
638 \r
639           foreach (Type ty in gp)\r
640           {\r
641             if (first) first = false;\r
642             else\r
643               gps += ",";\r
644 \r
645             if (ty.IsGenericParameter)\r
646             {\r
647               bool ismgp = false;\r
648 \r
649               foreach (string s in mgps) if (s.Equals(ty.Name)) ismgp = true;\r
650 \r
651               gps += (ismgp ? "``" : "`") + ty.GenericParameterPosition;\r
652             }\r
653             else\r
654               gps += canonicalTypeName(ty, mgps);\r
655           }\r
656 \r
657           ret += "{" + gps + "}";\r
658         }\r
659       }\r
660 \r
661       return ret;\r
662     }\r
663 \r
664     private string canonicalMethodName(MethodInfo m)\r
665     {\r
666       string ret = canonicalTypeName(m.DeclaringType, null) + "." + m.Name;\r
667 \r
668       string[] gmps;\r
669 \r
670       if (m.IsGenericMethod)\r
671       {\r
672         Type[] gps = m.GetGenericArguments();\r
673 \r
674         ret += "``" + gps.Length;\r
675         gmps = new string[gps.Length];\r
676         for (int i = 0; i < gps.Length; i++)\r
677           gmps[i] = gps[i].Name;\r
678       }\r
679       else\r
680         gmps = new string[]{};\r
681 \r
682       ret += canonicalParameters(m.GetParameters(), gmps);\r
683       return ret;\r
684     }\r
685 \r
686     private string canonicalPropertyName(PropertyInfo p)\r
687     {\r
688       string pname = canonicalTypeName(p.DeclaringType, null) + "." + p.Name;\r
689       ParameterInfo[] pars = p.GetIndexParameters();\r
690 \r
691       if (pars.Length > 0)\r
692         pname += canonicalParameters(pars, new string[]{});\r
693 \r
694       return pname;\r
695     }\r
696 \r
697     private string canonicalParameters(ParameterInfo[] pars, string[] gmps)\r
698     {\r
699       if (pars.Length == 0) return "";\r
700 \r
701       string ret = "";\r
702       bool first = true;\r
703 \r
704       foreach (ParameterInfo p in pars)\r
705       {\r
706         if (first) first = false;\r
707         else\r
708           ret += ",";\r
709 \r
710         ret += canonicalTypeName(p.ParameterType, gmps); ;\r
711       }\r
712 \r
713       return "(" + ret + ")";\r
714     }\r
715 \r
716 \r
717 \r
718     static void Main(string[] args)\r
719     {\r
720       if (args.Length != 2)\r
721       {\r
722         args = new string[] { @"C5.dll", @"C5.xml" };\r
723 \r
724       }\r
725       {\r
726         Timer timer = new Timer();\r
727         timer.snap();\r
728         DocNet doc = new DocNet(args[0], args[1], "C5");\r
729         XmlDocument merged = doc.GenerateDoc();\r
730         Console.Error.WriteLine("Time merge: {0} ms", timer.snap());\r
731 \r
732         System.Xml.Xsl.XslCompiledTransform overview = new System.Xml.Xsl.XslCompiledTransform();\r
733         overview.Load(@"overview.xslt");\r
734         overview.Transform(merged, new XmlTextWriter(new StreamWriter(@"docbuild\contents.htm")));\r
735         Console.Error.WriteLine("Time, overview: {0} ms", timer.snap());\r
736 \r
737         StringBuilder megaDoc = new StringBuilder();\r
738         using (XmlWriter writer = XmlWriter.Create(megaDoc))\r
739         {\r
740           writer.WriteStartElement("hack");\r
741           System.Xml.Xsl.XslCompiledTransform trans = new System.Xml.Xsl.XslCompiledTransform();\r
742           trans.Load(@"trans.xslt");\r
743           trans.Transform(merged, writer);\r
744           writer.WriteEndElement();\r
745           writer.Close();\r
746         }\r
747         Console.Error.WriteLine("Time trans: {0} ms", timer.snap());\r
748         System.Xml.XPath.XPathDocument megaXml =\r
749           new System.Xml.XPath.XPathDocument(XmlReader.Create(new StringReader(megaDoc.ToString())));\r
750         System.Xml.XPath.XPathNodeIterator nodes = megaXml.CreateNavigator().Select("/hack/*");\r
751         string docfn = null;\r
752         foreach (System.Xml.XPath.XPathNavigator var in nodes)\r
753         {\r
754           if (var.Name == "filestart")\r
755             docfn = var.GetAttribute("name", "");\r
756           if (var.Name == "html")\r
757           {\r
758             Console.Error.Write(".");\r
759             XmlWriter w = new XmlTextWriter(new StreamWriter(@"docbuild\types\" + docfn));\r
760             var.WriteSubtree(w);\r
761             w.Close();\r
762           }\r
763         }\r
764         Console.Error.WriteLine();\r
765         Console.Error.WriteLine("Time split: {0} ms", timer.snap());\r
766       }\r
767       Console.Write("? ");\r
768       Console.Read();\r
769     }\r
770   }\r
771 }\r
772 \r