Project

General

Profile

root / branches / compiler / cSharp / ooasCompiler / src / libs / c5 / docNet / docnet.cs @ 3

1
/*
2
 Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
3
 Permission is hereby granted, free of charge, to any person obtaining a copy
4
 of this software and associated documentation files (the "Software"), to deal
5
 in the Software without restriction, including without limitation the rights
6
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
 copies of the Software, and to permit persons to whom the Software is
8
 furnished to do so, subject to the following conditions:
9
 
10
 The above copyright notice and this permission notice shall be included in
11
 all copies or substantial portions of the Software.
12
 
13
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
 SOFTWARE.
20
*/
21

    
22
// DocNet.cs
23
// Author: Antonio Cisternino
24
// Version: 0.1
25
// Last update: 5/12/2001
26
// Modified Jan 2004 by kokholm@itu.dk
27

    
28
using System;
29
using System.IO;
30
using System.Reflection;
31
using System.Xml;
32
using System.Text;
33
using System.Diagnostics;
34

    
35
namespace DocNet
36
{
37
  class DocNet
38
  {
39
    private Assembly assembly;
40

    
41
    //private XmlDocument xml;
42

    
43
    private string defaultNamespace;
44

    
45
    private string assemblyName;
46

    
47
    private static C5.HashDictionary<string, string> longtype2short;
48

    
49
    private static C5.HashDictionary<string, XmlNode> cachedDocComments;
50

    
51
    static DocNet()
52
    {
53
      longtype2short = new C5.HashDictionary<string, string>();
54
      cachedDocComments = new C5.HashDictionary<string, XmlNode>();
55
      longtype2short.Add("System.Boolean", "bool");
56
      longtype2short.Add("System.Byte", "byte");
57
      longtype2short.Add("System.Int32", "int");
58
      longtype2short.Add("System.Double", "double");
59
      longtype2short.Add("System.Void", "void");
60
      longtype2short.Add("System.Object", "object");
61
      longtype2short.Add("System.String", "string");
62
      longtype2short.Add("System.Collections.Generic.IEnumerable{T}", "IEnumerable{T}");
63
      longtype2short.Add("System.Collections.Generic.IEnumerable{U}", "IEnumerable{U}");
64
      //longtype2short.Add("", "");
65
    }
66

    
67

    
68
    DocNet(string a, string x, string defaultNamespace)
69
    {
70
      this.defaultNamespace = defaultNamespace;
71
      assembly = Assembly.LoadFrom(a, null);
72
      XmlDocument xml = new XmlDocument();
73
      xml.Load(x);
74
      assemblyName = xml.SelectSingleNode("doc/assembly/name").InnerXml;
75

    
76
      if (!assembly.FullName.StartsWith(assemblyName + ","))
77
        throw new Exception("Wrong assembly specified!\n>> " + assembly.FullName + "\n>> " + assemblyName);
78

    
79
      foreach (XmlNode node in xml.SelectNodes("doc/members/member"))
80
        cachedDocComments.Add(node.SelectNodes("@name").Item(0).Value, node);
81
    }
82

    
83

    
84
    private void CopyCodeDoc(XmlElement p, string xpath, XmlDocument ret)
85
    {
86
      XmlNode n;
87
      //xml.SelectSingleNode(xpath);
88

    
89
      if (cachedDocComments.Find(xpath, out n))
90
      {
91
        foreach (XmlNode child in n.ChildNodes)
92
          p.AppendChild(ret.ImportNode(child, true));
93
      }
94
      //else
95
      //  Console.Error.WriteLine("docNet: {0} not found", xpath);
96
    }
97

    
98
    string xmlClean(string s)
99
    {
100
//            return s.Replace("&", "&amp;").Replace("{", "&lt;").Replace("}", "&gt;").Replace("<", "&lt;").Replace(">", "&gt;");
101
      return s.Replace("{", "<").Replace("}", ">");
102
    }
103

    
104
    private void AddSignature(XmlElement p, string signtext, XmlDocument ret)
105
    {
106
      XmlElement sign = CreateElement(ret, "Signature");
107

    
108
      try
109
      {
110
        sign.InnerXml = signtext.Replace("&", "&amp;").Replace("{", "&lt;").Replace("}", "&gt;").Replace("<", "&lt;").Replace(">", "&gt;");
111
      }
112
      catch (XmlException)
113
      {
114
        Console.Error.WriteLine(signtext);
115
      }
116
      p.AppendChild(sign);
117
    }
118

    
119
    private void addImplements(XmlElement p, Type t, XmlDocument ret)
120
    {
121
      foreach (Type ty in t.GetInterfaces())
122
      {
123
        XmlElement impl = CreateElement(ret, "Implements");
124

    
125
        if (ty.Assembly == assembly)
126
        {
127
          impl.SetAttribute("refid", "T:" + canonicalTypeName(ty, null));
128
          impl.SetAttribute("C5", "");
129
        }
130
        AddSignature(impl, prettyTypeName(ty), ret);
131
        p.AppendChild(impl);
132
      }
133
    }
134

    
135
    private void addBases(XmlElement p, Type t, XmlDocument ret)
136
    {
137
      Type ty = t.BaseType;
138

    
139
      while (ty != null)
140
      {
141
        XmlElement @base = CreateElement(ret, "Bases");
142

    
143
        if (ty.Assembly == assembly)
144
        {
145
          @base.SetAttribute("refid", "T:" + canonicalTypeName(ty, null));
146
          @base.SetAttribute("C5", "");
147
        }
148

    
149
        AddSignature(@base, prettyTypeName(ty), ret);
150
        p.PrependChild(@base);
151
        ty = ty.BaseType;
152
      }
153
    }
154

    
155

    
156

    
157
    private XmlElement CreateElement(XmlDocument ret, string name)
158
    {
159
      return ret.CreateElement(null, name, null);
160
    }
161

    
162
    private void VisitField(bool inherited, FieldInfo f, XmlElement type, XmlDocument refman)
163
    {
164
      if (f.Name.Equals("value__"))
165
        return;
166
      string refid = "F:" + canonicalTypeName(f.DeclaringType, null) + "." + f.Name;
167
      //string xpath = "doc/members/member[@name = \"" + refid + "\"]";
168
      XmlElement el = CreateElement(refman, "Field");
169

    
170
      el.SetAttribute("Name", f.Name);
171
      el.SetAttribute("refid", refid);
172
      el.SetAttribute("Static", f.IsStatic.ToString());
173
      el.SetAttribute("Declared", xmlClean(prettyTypeName(f.DeclaringType)));
174
      el.SetAttribute("CDeclared", canonicalTypeName(f.DeclaringType, null));
175
      el.SetAttribute("Type", xmlClean(prettyTypeName(f.FieldType)));
176
      el.SetAttribute("Access", f.IsPublic ? "public" : (f.IsPrivate || f.IsAssembly ? "private" : "protected"));
177
      if (f.DeclaringType.Assembly == assembly)
178
        el.SetAttribute("C5", "");
179

    
180
      if (inherited)
181
        el.SetAttribute("Inherited", "");
182

    
183
      AddSignature(el, /*prettyTypeName(f.FieldType) + " " +*/ f.Name, refman);
184
      CopyCodeDoc(el, refid, refman);
185
      //AddSummary(el, xpath + "/summary", ret, doc);
186
      type.AppendChild(el);
187
    }
188

    
189
    private void VisitEvent(bool inherited, EventInfo e, XmlElement type, XmlDocument ret)
190
    {
191
      string refid = "E:" + canonicalTypeName(e.DeclaringType, null) + "." + e.Name;
192
      //string xpath = "doc/members/member[@name = \"" + refid + "\"]";
193
      XmlElement el = CreateElement(ret, "Event");
194

    
195
      el.SetAttribute("Name", e.Name);
196
      el.SetAttribute("refid", refid);
197
      //el.SetAttribute("Static", f.IsStatic.ToString());
198
      //TODO: check virtual and final values on adders/removers
199
      //el.SetAttribute("Virtual", e..IsVirtual.ToString());
200
      //el.SetAttribute("Final", e.IsFinal.ToString());
201
      el.SetAttribute("Declared", xmlClean(prettyTypeName(e.DeclaringType)));
202
      el.SetAttribute("CDeclared", canonicalTypeName(e.DeclaringType, null));
203
      el.SetAttribute("Type", xmlClean(prettyTypeName(e.EventHandlerType)));
204
      MethodInfo addMethod = e.GetAddMethod(true);
205
      el.SetAttribute("Access", addMethod.IsPublic ? "public" : addMethod.IsFamily ? "protected" : "private");//NBNBNB! e.IsPublic ? "public" : (e.IsPrivate || e.IsAssembly ? "private" : "protected"));
206
      if (e.DeclaringType.Assembly == assembly)
207
        el.SetAttribute("C5", "");
208

    
209
      if (inherited)
210
        el.SetAttribute("Inherited", "");
211

    
212
      AddSignature(el, /*prettyTypeName(e.EventHandlerType) + " " +*/ e.Name, ret);
213
      CopyCodeDoc(el, refid, ret);
214
      //AddSummary(el, xpath + "/summary", ret, doc);
215
      type.AppendChild(el);
216
    }
217

    
218

    
219
    private void VisitProperty(bool inherited, PropertyInfo p, XmlElement type, XmlDocument ret)
220
    {
221
      string refid = "P:" + canonicalPropertyName(p);
222
      string xpath = "doc/members/member[@name = \"" + refid + "\"]";
223
      XmlElement el = CreateElement(ret, "Property");
224

    
225
      el.SetAttribute("Name", p.Name);
226
      el.SetAttribute("refid", refid);
227
      el.SetAttribute("Access", "public");//TODO: check if reasonable
228
      MethodInfo m = p.CanRead ? p.GetGetMethod() : p.GetSetMethod();
229
      if (m != null)
230
      {
231
        el.SetAttribute("Static", m.IsStatic.ToString());
232
        el.SetAttribute("Abstract", m.IsAbstract.ToString());
233
        el.SetAttribute("Virtual", m.IsVirtual.ToString());
234
        el.SetAttribute("Final", m.IsFinal.ToString());
235
      }
236
      //else
237
      //Console.Error.WriteLine("%%%%% {0} | {1}", p, p.DeclaringType);
238
      el.SetAttribute("Declared", xmlClean(prettyTypeName(p.DeclaringType)));
239
      el.SetAttribute("CDeclared", canonicalTypeName(p.DeclaringType, null));
240
      el.SetAttribute("Get", p.CanRead.ToString());
241
      el.SetAttribute("Set", p.CanWrite.ToString());
242
      el.SetAttribute("Type", xmlClean(prettyTypeName(p.PropertyType)));
243

    
244
      if (p.DeclaringType.Assembly == assembly)
245
        el.SetAttribute("C5", "");
246

    
247
      if (inherited)
248
        el.SetAttribute("Inherited", "");
249

    
250
      if (p.Name.Equals("Item"))
251
        AddSignature(el, prettyIndexerSignature(p), ret);
252
      else
253
        AddSignature(el, /*prettyTypeName(p.PropertyType) + " " +*/ p.Name, ret);
254

    
255
      //AddSummary(el, xpath + "/summary", ret, doc);
256
      CopyCodeDoc(el, refid, ret);
257
      //AddValue(el, xpath + "/value", ret, doc);
258
      VisitParameters(p.GetIndexParameters(), el, ret, xpath);
259
      type.AppendChild(el);
260
    }
261

    
262

    
263
    private void VisitParameters(ParameterInfo[] pars, XmlElement n, XmlDocument ret, string xpath)
264
    {
265
      foreach (ParameterInfo p in pars)
266
      {
267
        XmlElement el = CreateElement(ret, "Parameter");
268

    
269
        el.SetAttribute("Name", p.Name);
270
        el.SetAttribute("Type", prettyTypeName(p.ParameterType));
271
        //AddSummary(el, xpath + "/param[@name = \"" + p.Name + "\"]", ret, doc);
272
        CopyCodeDoc(el, xpath + "/param[@name = \"" + p.Name + "\"]", ret);
273

    
274
        n.AppendChild(el);
275
      }
276
    }
277

    
278

    
279
    private void VisitConstructor(Type t, ConstructorInfo c, XmlElement type, XmlDocument ret)
280
    {
281
      Type declaringType = c.DeclaringType;
282
      string refid = "M:" + canonicalTypeName(c.DeclaringType, null) + "." + "#ctor";
283

    
284
      refid += canonicalParameters(c.GetParameters(), new string[]{});
285

    
286
      string xpath = "doc/members/member[@name = \"" + refid + "\"]";
287
      XmlElement el = CreateElement(ret, "Constructor");
288
      el.SetAttribute("Foo", c.IsConstructor ? "Con" : "San");
289
      el.SetAttribute("refid", refid);
290
      el.SetAttribute("Declared", prettyTypeName(declaringType));
291
      el.SetAttribute("CDeclared", canonicalTypeName(declaringType, null));
292
      el.SetAttribute("Access", c.IsPublic ? "public" : (c.IsPrivate ? "private" : "protected"));
293
      //el.SetAttribute("Access", c.IsPublic ? "public" : (c.IsPrivate || c.IsAssembly ? "private" : "protected"));
294
      if (declaringType.Assembly == assembly)
295
        el.SetAttribute("C5", "");
296
      if (declaringType != t)
297
        el.SetAttribute("Inherited", "");
298
      AddSignature(el, prettyConstructorSignature(c), ret);
299
      CopyCodeDoc(el, refid, ret);
300
      //AddSummary(el, xpath + "/summary", ret, doc);
301
      VisitParameters(c.GetParameters(), el, ret, xpath);
302
      type.AppendChild(el);
303
    }
304

    
305

    
306
    private void VisitMethod(bool inherited, MethodInfo m, XmlElement type, XmlDocument ret)
307
    {
308
      if (m.Name.StartsWith("get_") || m.Name.StartsWith("set_") || m.Name.StartsWith("add_") || m.Name.StartsWith("remove_"))
309
        return;
310
      bool isOperator = m.Name.StartsWith("op_");
311

    
312
      string refid = "M:" + canonicalMethodName(m);
313

    
314
      string xpath = "doc/members/member[@name = \"" + refid + "\"]";
315
      XmlElement el = CreateElement(ret, isOperator ? "Operator" : "Method");
316

    
317
      string mangledName = m.Name;
318
      if (isOperator)
319
      {
320
        switch (mangledName)
321
        {
322
          case "op_Equality": mangledName = "operator =="; break;
323
          case "op_Inequality": mangledName = "operator !="; break;
324
          default: throw new ApplicationException("unknown operatorname, " + mangledName);
325
        }
326
      }
327
      el.SetAttribute("Name", mangledName);
328
      el.SetAttribute("refid", refid);
329
      el.SetAttribute("Static", m.IsStatic.ToString());
330
      el.SetAttribute("Abstract", m.IsAbstract.ToString());
331
      el.SetAttribute("Virtual", m.IsVirtual.ToString());
332
      el.SetAttribute("Final", m.IsFinal.ToString());
333
      el.SetAttribute("Declared", xmlClean(prettyTypeName(m.DeclaringType)));
334
      el.SetAttribute("CDeclared", canonicalTypeName(m.DeclaringType, null));
335
      el.SetAttribute("ReturnType", xmlClean(prettyTypeName(m.ReturnType)));
336
      if (m.DeclaringType.Assembly == assembly)
337
        el.SetAttribute("C5", "");
338
      if (inherited)
339
        el.SetAttribute("Inherited", "");
340
      el.SetAttribute("Access", m.IsPublic ? "public" : (m.IsPrivate || m.IsAssembly ? "private" : "protected"));
341
      el.SetAttribute("Sealed", m.IsFinal.ToString());
342
      AddSignature(el, prettyMethodSignature(mangledName, m), ret);
343
      CopyCodeDoc(el, refid, ret);
344
      VisitParameters(m.GetParameters(), el, ret, xpath);
345

    
346
      foreach (Type gp in m.GetGenericArguments())
347
        foreach (Type gc in gp.GetGenericParameterConstraints())
348
          if (gc != typeof(object))
349
          {
350
            XmlElement constraint = CreateElement(ret, "constraint");
351
            constraint.SetAttribute("Value", prettyTypeName(gp) + " : " + xmlClean(prettyTypeName(gc)));
352
            el.AppendChild(constraint);
353
          }
354
      type.AppendChild(el);
355
    }
356

    
357
    public XmlDocument GenerateDoc()
358
    {
359
      BindingFlags flags = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic;
360

    
361
      XmlDocument ret = new XmlDocument();
362
      XmlElement root = CreateElement(ret, "Assembly");
363

    
364
      root.SetAttribute("Name", assemblyName);
365

    
366
      ret.AppendChild(root);
367

    
368
      XmlElement type = null;
369
      //string xpath = null;
370

    
371
      foreach (Type t in assembly.GetTypes())
372
      {
373
        if (t.Name.StartsWith("DocNet"))
374
          continue;
375

    
376
        if (t.IsInterface)
377
        {
378
          type = CreateElement(ret, "Interface");
379
          foreach (EventInfo e in t.GetEvents(flags))
380
            VisitEvent(e.DeclaringType != t, e, type, ret);
381

    
382
          foreach (PropertyInfo p in t.GetProperties(flags))
383
            VisitProperty(false, p, type, ret);
384

    
385
          foreach (MethodInfo m in t.GetMethods(flags))
386
            VisitMethod(false, m, type, ret);
387
        }
388
        else if (t.IsValueType)
389
        {
390
          type = CreateElement(ret, "Struct");
391
          foreach (FieldInfo f in t.GetFields(flags))
392
            VisitField(f.DeclaringType != t, f, type, ret);
393

    
394
          foreach (EventInfo e in t.GetEvents(flags))
395
            VisitEvent(e.DeclaringType != t, e, type, ret);
396

    
397
          foreach (PropertyInfo p in t.GetProperties(flags))
398
            VisitProperty(p.DeclaringType != t, p, type, ret);
399

    
400
          foreach (ConstructorInfo c in t.GetConstructors(flags))
401
            VisitConstructor(t, c, type, ret);
402

    
403
          foreach (MethodInfo m in t.GetMethods(flags))
404
            VisitMethod(m.DeclaringType != t, m, type, ret);
405
        }
406
        else if (t.IsSubclassOf(typeof(Delegate)))
407
        {
408
          type = CreateElement(ret, "Delegate");
409
          VisitMethod(false, t.GetMethod("Invoke"), type, ret);
410
        }
411
        else
412
        { // Class
413
          type = CreateElement(ret, "Class");
414
          foreach (FieldInfo f in t.GetFields(flags))
415
            VisitField(f.DeclaringType != t, f, type, ret);
416

    
417
          foreach (EventInfo e in t.GetEvents(flags))
418
            VisitEvent(e.DeclaringType != t, e, type, ret);
419

    
420
          foreach (PropertyInfo p in t.GetProperties(flags))
421
            VisitProperty(p.DeclaringType != t, p, type, ret);
422

    
423
          foreach (ConstructorInfo c in t.GetConstructors(flags))
424
            VisitConstructor(t, c, type, ret);
425

    
426
          foreach (MethodInfo m in t.GetMethods(flags))
427
            VisitMethod(m.DeclaringType != t, m, type, ret);
428
        }
429

    
430
        type.SetAttribute("Name", xmlClean(prettyTypeName(t)));
431
        type.SetAttribute("Access", t.IsPublic || t.IsNestedPublic ? "public" : t.IsNestedFamily ? "protected" : "private");
432

    
433
        string refid = "T:" + canonicalTypeName(t, null);
434

    
435
        type.SetAttribute("refid", refid);
436
        type.SetAttribute("C5", "");
437
        AddSignature(type, prettyTypeName(t), ret);
438
        addImplements(type, t, ret);
439
        addBases(type, t, ret);
440

    
441
        foreach (Type gp in t.GetGenericArguments())
442
        {
443
          if (gp.GenericParameterAttributes != GenericParameterAttributes.None)
444
          {
445
            XmlElement constraint = CreateElement(ret, "constraint");
446
            string constraintText = null;
447
            switch (gp.GenericParameterAttributes)
448
            {
449
              case GenericParameterAttributes.Contravariant:
450
                break;
451
              case GenericParameterAttributes.Covariant:
452
                break;
453
              case GenericParameterAttributes.DefaultConstructorConstraint:
454
                constraintText = "new()";
455
                break;
456
              case GenericParameterAttributes.None:
457
                break;
458
              case GenericParameterAttributes.ReferenceTypeConstraint:
459
                constraintText = "class";
460
                break;
461
              case GenericParameterAttributes.SpecialConstraintMask:
462
                break;
463
              case GenericParameterAttributes.NotNullableValueTypeConstraint:
464
                constraintText = "struct";
465
                break;
466
              case GenericParameterAttributes.VarianceMask:
467
                break;
468
            }
469
            constraint.SetAttribute("Value", String.Format("{0} : {1}", gp, constraintText));
470
            type.AppendChild(constraint);
471
          }
472
          foreach (Type gc in gp.GetGenericParameterConstraints())
473
          {
474
            if (gc != typeof(object))
475
            {
476
              XmlElement constraint = CreateElement(ret, "constraint");
477
              constraint.SetAttribute("Value", String.Format("{0} : {1}", prettyTypeName(gp), xmlClean(prettyTypeName(gc))));
478
              type.AppendChild(constraint);
479
            }
480
          }
481
        }
482

    
483
        CopyCodeDoc(type, refid, ret);
484
        root.AppendChild(type);
485
      }
486

    
487
      return ret;
488
    }
489

    
490
    C5.HashDictionary<Type, string> t2ptn = new C5.HashDictionary<Type, string>();
491
    private string prettyTypeName(Type t)
492
    {
493
      string retval;
494
      //if (!t2ptn.Find(t, out retval))
495
      //{
496
      int consumed = 0;
497
      retval = prettyTypeName(t, ref consumed);
498
      //    t2ptn.Add(t, retval);
499
      //}
500
      return retval;
501
    }
502

    
503
    private string prettyTypeName(Type t, ref int consumed)
504
    {
505
      StringBuilder ret = new StringBuilder();
506

    
507
      if (t.IsGenericParameter)
508
        ret.Append(t.Name);
509
      else if (t.IsArray)
510
        ret.Append(prettyTypeName(t.GetElementType()) + "[]");
511
      else if (t.IsByRef)
512
        ret.Append("ref ").Append(prettyTypeName(t.GetElementType()));
513
      else if (!t.IsGenericType)
514
        ret.Append(t.IsNested ? prettyTypeName(t.DeclaringType, ref consumed) + "." + t.Name : t.FullName);
515
      else
516
      {
517
        bool first = true;
518
        StringBuilder gps = new StringBuilder();
519
        Type[] gp = t.GetGenericArguments();
520

    
521
        ret.Append(t.IsNested ? prettyTypeName(t.DeclaringType, ref consumed) : t.Namespace).Append(".").Append(t.Name);
522
        if (consumed < gp.Length)
523
        {
524
          //TODO: fix this ugly hack to remove `n 
525
          ret.Remove(ret.Length - 2, 2);
526
          //ret = ret.Substring(0, ret.Length - 2);
527
          for (int i = consumed, length = gp.Length; i < length; i++)
528
          {
529
            Type ty = gp[i];
530

    
531
            if (first) first = false;
532
            else
533
              gps.Append(",");
534

    
535
            gps.Append(prettyTypeName(ty));
536
          }
537

    
538
          consumed = gp.Length;
539
          ret.Append("{").Append(gps.ToString()).Append("}");
540
        }
541
      }
542

    
543
      string retval = ret.ToString();
544

    
545
      if (retval.StartsWith(defaultNamespace + "."))
546
        retval = retval.Substring(defaultNamespace.Length + 1);
547

    
548
      if (longtype2short.Contains(retval))
549
        retval = longtype2short[retval];
550

    
551
      return retval;
552
    }
553

    
554
    private string prettyParameters(ParameterInfo[] pars)
555
    {
556
      string ret = "";
557
      bool first = true;
558

    
559
      foreach (ParameterInfo p in pars)
560
      {
561
        if (first) first = false;
562
        else
563
          ret += ", ";
564
        Type pt = p.ParameterType;
565
        if (p.IsOut)
566
        {
567
          ret += "out ";
568
          pt = pt.GetElementType();
569
        }
570

    
571
        ret += prettyTypeName(pt) + " " + p.Name;
572
      }
573

    
574
      return ret;
575
    }
576

    
577
    private string prettyMethodSignature(string name, MethodInfo m)
578
    {
579
      string gp = "";
580
      if (m.IsGenericMethod)
581
      {
582
        Type[] gps = m.GetGenericArguments();
583
        gp = "<";
584

    
585
        for (int i = 0; i < gps.Length; i++)
586
          gp += (i == 0 ? "" : ",") + gps[i].Name;
587

    
588
        gp += ">";
589
      }
590

    
591
      return name + gp + "(" + prettyParameters(m.GetParameters()) + ")";
592
    }
593

    
594
    private string prettyConstructorSignature(ConstructorInfo c)
595
    {
596
      Type t = c.DeclaringType;
597

    
598
      return prettyTypeName(t) + "(" + prettyParameters(c.GetParameters()) + ")";
599
    }
600

    
601
    private string prettyIndexerSignature(PropertyInfo p)
602
    {
603
      return /*prettyTypeName(p.PropertyType) + " " + */ "this[" + prettyParameters(p.GetIndexParameters()) + "]";
604
    }
605

    
606

    
607
    private string simpleTypeName(Type t)
608
    {
609
      return (t.IsNested ? simpleTypeName(t.DeclaringType) : t.Namespace) + "." + t.Name;
610
    }
611

    
612

    
613
    private string canonicalTypeName(Type t, string[] mgps)
614
    {
615
      string ret;
616

    
617
      if (t.IsGenericParameter)
618
        ret = "`" + t.GenericParameterPosition;
619
      else if (t.IsArray)
620
        ret = canonicalTypeName(t.GetElementType(), mgps) + "[]";
621
      else if (t.IsByRef)
622
        ret = canonicalTypeName(t.GetElementType(), mgps) + "@";
623
      else
624
      {
625
        ret = simpleTypeName(t);
626
        if (!t.IsGenericType)
627
          ret += "";
628
        else if (mgps == null)
629
          ret += "";//"`" + t.GetGenericArguments().Length;
630
        else
631
        {
632
          //TODO: fix this ugly hack to remove `n 
633
          ret = ret.Substring(0, ret.Length - 2);
634

    
635
          bool first = true;
636
          string gps = "";
637
          Type[] gp = t.GetGenericArguments();
638

    
639
          foreach (Type ty in gp)
640
          {
641
            if (first) first = false;
642
            else
643
              gps += ",";
644

    
645
            if (ty.IsGenericParameter)
646
            {
647
              bool ismgp = false;
648

    
649
              foreach (string s in mgps) if (s.Equals(ty.Name)) ismgp = true;
650

    
651
              gps += (ismgp ? "``" : "`") + ty.GenericParameterPosition;
652
            }
653
            else
654
              gps += canonicalTypeName(ty, mgps);
655
          }
656

    
657
          ret += "{" + gps + "}";
658
        }
659
      }
660

    
661
      return ret;
662
    }
663

    
664
    private string canonicalMethodName(MethodInfo m)
665
    {
666
      string ret = canonicalTypeName(m.DeclaringType, null) + "." + m.Name;
667

    
668
      string[] gmps;
669

    
670
      if (m.IsGenericMethod)
671
      {
672
        Type[] gps = m.GetGenericArguments();
673

    
674
        ret += "``" + gps.Length;
675
        gmps = new string[gps.Length];
676
        for (int i = 0; i < gps.Length; i++)
677
          gmps[i] = gps[i].Name;
678
      }
679
      else
680
        gmps = new string[]{};
681

    
682
      ret += canonicalParameters(m.GetParameters(), gmps);
683
      return ret;
684
    }
685

    
686
    private string canonicalPropertyName(PropertyInfo p)
687
    {
688
      string pname = canonicalTypeName(p.DeclaringType, null) + "." + p.Name;
689
      ParameterInfo[] pars = p.GetIndexParameters();
690

    
691
      if (pars.Length > 0)
692
        pname += canonicalParameters(pars, new string[]{});
693

    
694
      return pname;
695
    }
696

    
697
    private string canonicalParameters(ParameterInfo[] pars, string[] gmps)
698
    {
699
      if (pars.Length == 0) return "";
700

    
701
      string ret = "";
702
      bool first = true;
703

    
704
      foreach (ParameterInfo p in pars)
705
      {
706
        if (first) first = false;
707
        else
708
          ret += ",";
709

    
710
        ret += canonicalTypeName(p.ParameterType, gmps); ;
711
      }
712

    
713
      return "(" + ret + ")";
714
    }
715

    
716

    
717

    
718
    static void Main(string[] args)
719
    {
720
      if (args.Length != 2)
721
      {
722
        args = new string[] { @"C5.dll", @"C5.xml" };
723

    
724
      }
725
      {
726
        Timer timer = new Timer();
727
        timer.snap();
728
        DocNet doc = new DocNet(args[0], args[1], "C5");
729
        XmlDocument merged = doc.GenerateDoc();
730
        if (true)
731
        {
732
          XmlWriterSettings s = new XmlWriterSettings();
733
          s.Indent = true;
734
          XmlWriter w = XmlWriter.Create("merged.xml", s);
735
          merged.WriteTo(w);
736
          w.Close();
737
        }
738
        Console.Error.WriteLine("Time merge: {0} ms", timer.snap());
739

    
740
        System.Xml.Xsl.XslCompiledTransform overview = new System.Xml.Xsl.XslCompiledTransform();
741
        overview.Load(@"overview.xslt");
742
        overview.Transform(merged, new XmlTextWriter(new StreamWriter(@"docbuild\contents.htm")));
743
        Console.Error.WriteLine("Time, overview: {0} ms", timer.snap());
744

    
745
        StringBuilder megaDoc = new StringBuilder();
746
        using (XmlWriter writer = XmlWriter.Create(megaDoc))
747
        {
748
          writer.WriteStartElement("hack");
749
          System.Xml.Xsl.XslCompiledTransform trans = new System.Xml.Xsl.XslCompiledTransform();
750
          trans.Load(@"trans.xslt");
751
          trans.Transform(merged, writer);
752
          writer.WriteEndElement();
753
          writer.Close();
754
        }
755
        Console.Error.WriteLine("Time trans: {0} ms", timer.snap());
756
        System.Xml.XPath.XPathDocument megaXml =
757
          new System.Xml.XPath.XPathDocument(XmlReader.Create(new StringReader(megaDoc.ToString())));
758
        System.Xml.XPath.XPathNodeIterator nodes = megaXml.CreateNavigator().Select("/hack/*");
759
        string docfn = null;
760
        foreach (System.Xml.XPath.XPathNavigator var in nodes)
761
        {
762
          if (var.Name == "filestart")
763
            docfn = var.GetAttribute("name", "");
764
          if (var.Name == "html")
765
          {
766
            Console.Error.Write(".");
767
            XmlWriter w = new XmlTextWriter(new StreamWriter(@"docbuild\types\" + docfn));
768
            var.WriteSubtree(w);
769
            w.Close();
770
          }
771
        }
772
        Console.Error.WriteLine();
773
        Console.Error.WriteLine("Time split: {0} ms", timer.snap());
774
      }
775
      Console.Write("? ");
776
      Console.Read();
777
    }
778
  }
779
}
780